Janus 2.0.0
High-performance C++20 dual-mode numerical framework
Loading...
Searching...
No Matches
StructuralTransforms.hpp
Go to the documentation of this file.
1
3#pragma once
4
5#include "Function.hpp"
6#include "JanusError.hpp"
7#include "JanusTypes.hpp"
8#include "Sparsity.hpp"
9
10#include <algorithm>
11#include <casadi/casadi.hpp>
12#include <limits>
13#include <numeric>
14#include <string>
15#include <utility>
16#include <vector>
17
18namespace janus {
19
30
39
57
62 std::vector<int> residual_indices;
63 std::vector<int> variable_indices;
64 std::vector<int> tear_variable_indices;
65
68 bool is_coupled() const { return residual_indices.size() > 1 || variable_indices.size() > 1; }
69};
70
76 std::vector<int> row_permutation;
77 std::vector<int> column_permutation;
78 std::vector<int> row_block_offsets;
79 std::vector<int> column_block_offsets;
80 std::vector<int> coarse_row_block_offsets;
81 std::vector<int> coarse_column_block_offsets;
82 std::vector<StructuralBlock> blocks;
83};
84
95
96namespace detail {
97
98inline void validate_options(const StructuralTransformOptions &opts, const std::string &context) {
99 if (opts.input_idx < 0) {
100 throw InvalidArgument(context + ": input_idx cannot be negative");
101 }
102 if (opts.output_idx < 0) {
103 throw InvalidArgument(context + ": output_idx cannot be negative");
104 }
105 if (opts.max_alias_row_nnz <= 0) {
106 throw InvalidArgument(context + ": max_alias_row_nnz must be positive");
107 }
108}
109
111 const std::string &context) {
112 const auto &cfn = fn.casadi_function();
113 if (opts.input_idx >= cfn.n_in()) {
114 throw InvalidArgument(context + ": input_idx out of range");
115 }
116 if (opts.output_idx >= cfn.n_out()) {
117 throw InvalidArgument(context + ": output_idx out of range");
118 }
119
120 const auto in_sp = cfn.sparsity_in(opts.input_idx);
121 const auto out_sp = cfn.sparsity_out(opts.output_idx);
122 if (!in_sp.is_dense() || !in_sp.is_column()) {
123 throw InvalidArgument(context + ": selected input must be a dense column vector");
124 }
125 if (!out_sp.is_dense() || !out_sp.is_column()) {
126 throw InvalidArgument(context + ": selected output must be a dense column vector");
127 }
128 if (cfn.nnz_in(opts.input_idx) != cfn.nnz_out(opts.output_idx)) {
129 throw InvalidArgument(context + ": selected input and output dimensions must match");
130 }
131}
132
133inline std::vector<int> make_index_vector(int n) {
134 std::vector<int> indices(static_cast<std::size_t>(n));
135 std::iota(indices.begin(), indices.end(), 0);
136 return indices;
137}
138
139inline std::vector<casadi::MX> mx_elements(const casadi::MX &v) {
140 std::vector<casadi::MX> elems;
141 elems.reserve(static_cast<std::size_t>(v.size1() * v.size2()));
142 for (int i = 0; i < v.size1(); ++i) {
143 for (int j = 0; j < v.size2(); ++j) {
144 elems.push_back(v(i, j));
145 }
146 }
147 return elems;
148}
149
150inline casadi::MX vertcat_subset(const std::vector<casadi::MX> &elems,
151 const std::vector<int> &indices) {
152 std::vector<casadi::MX> subset;
153 subset.reserve(indices.size());
154 for (int index : indices) {
155 subset.push_back(elems.at(static_cast<std::size_t>(index)));
156 }
157 return subset.empty() ? casadi::MX(0, 1) : casadi::MX::vertcat(subset);
158}
159
160inline std::vector<int> find_row_nonzeros(const casadi::MX &A, int row) {
161 std::vector<int> cols;
162 cols.reserve(static_cast<std::size_t>(A.size2()));
163 for (int col = 0; col < A.size2(); ++col) {
164 if (!A(row, col).is_zero()) {
165 cols.push_back(col);
166 }
167 }
168 return cols;
169}
170
171inline bool has_no_free_symbols(const casadi::MX &expr) {
172 try {
173 casadi::Function("structural_constant_probe", std::vector<casadi::MX>{},
174 std::vector<casadi::MX>{expr});
175 return true;
176 } catch (const std::exception &) {
177 return false;
178 }
179}
180
181inline bool coefficients_are_constant(const casadi::MX &A, int row,
182 const std::vector<int> &nz_cols) {
183 for (int col : nz_cols) {
184 if (!has_no_free_symbols(A(row, col))) {
185 return false;
186 }
187 }
188 return true;
189}
190
192 int pivot_index = -1;
193 casadi::MX replacement;
194};
195
196inline bool try_make_alias_candidate(const casadi::MX &expr, const casadi::MX &state_symbol,
197 const std::vector<int> &active_var_indices,
198 const StructuralTransformOptions &opts,
199 AliasCandidate &candidate) {
200 casadi::MX A_row;
201 casadi::MX b_row;
202 try {
203 casadi::MX::linear_coeff(casadi::MX::vertcat(std::vector<casadi::MX>{expr}), state_symbol,
204 A_row, b_row, true);
205 } catch (const std::exception &) {
206 return false;
207 }
208
209 const std::vector<int> nz_cols_full = find_row_nonzeros(A_row, 0);
210 std::vector<int> nz_cols;
211 nz_cols.reserve(nz_cols_full.size());
212 for (int col : nz_cols_full) {
213 if (std::find(active_var_indices.begin(), active_var_indices.end(), col) !=
214 active_var_indices.end()) {
215 nz_cols.push_back(col);
216 }
217 }
218
219 if (nz_cols.empty() || static_cast<int>(nz_cols.size()) > opts.max_alias_row_nnz) {
220 return false;
221 }
222 if (opts.require_constant_alias_coefficients && !coefficients_are_constant(A_row, 0, nz_cols)) {
223 return false;
224 }
225
226 int pivot_index = nz_cols.front();
227 for (int col : nz_cols) {
228 if (col > pivot_index) {
229 pivot_index = col;
230 }
231 }
232
233 casadi::MX rhs = b_row(0);
234 for (int col : nz_cols) {
235 if (col == pivot_index) {
236 continue;
237 }
238 rhs += A_row(0, col) * state_symbol(col);
239 }
240
241 candidate.pivot_index = pivot_index;
242 candidate.replacement = -rhs / A_row(0, pivot_index);
243 return true;
244}
245
246inline std::vector<int> erase_value(const std::vector<int> &values, int erased_index) {
247 std::vector<int> result;
248 result.reserve(values.size() > 0 ? values.size() - 1 : 0);
249 for (int value : values) {
250 if (value != erased_index) {
251 result.push_back(value);
252 }
253 }
254 return result;
255}
256
257inline std::vector<int> casadi_to_int(const std::vector<casadi_int> &values) {
258 return std::vector<int>(values.begin(), values.end());
259}
260
262 const std::vector<std::vector<int>> &adjacency;
263 const std::vector<bool> &removed;
264 std::vector<int> index;
265 std::vector<int> lowlink;
266 std::vector<int> stack;
267 std::vector<bool> on_stack;
268 int next_index = 0;
269 std::vector<std::vector<int>> components;
270};
271
272inline void tarjan_visit(int node, TarjanState &state) {
273 state.index[node] = state.next_index;
274 state.lowlink[node] = state.next_index;
275 state.next_index += 1;
276 state.stack.push_back(node);
277 state.on_stack[node] = true;
278
279 for (int neighbor : state.adjacency[node]) {
280 if (state.removed[neighbor]) {
281 continue;
282 }
283 if (state.index[neighbor] < 0) {
284 tarjan_visit(neighbor, state);
285 state.lowlink[node] = std::min(state.lowlink[node], state.lowlink[neighbor]);
286 } else if (state.on_stack[neighbor]) {
287 state.lowlink[node] = std::min(state.lowlink[node], state.index[neighbor]);
288 }
289 }
290
291 if (state.lowlink[node] == state.index[node]) {
292 std::vector<int> component;
293 while (!state.stack.empty()) {
294 const int top = state.stack.back();
295 state.stack.pop_back();
296 state.on_stack[top] = false;
297 component.push_back(top);
298 if (top == node) {
299 break;
300 }
301 }
302 state.components.push_back(component);
303 }
304}
305
306inline std::vector<std::vector<int>>
307strongly_connected_components(const std::vector<std::vector<int>> &adjacency,
308 const std::vector<bool> &removed) {
309 TarjanState state{adjacency,
310 removed,
311 std::vector<int>(adjacency.size(), -1),
312 std::vector<int>(adjacency.size(), -1),
313 {},
314 std::vector<bool>(adjacency.size(), false),
315 0,
316 {}};
317
318 for (std::size_t node = 0; node < adjacency.size(); ++node) {
319 if (removed[node] || state.index[node] >= 0) {
320 continue;
321 }
322 tarjan_visit(static_cast<int>(node), state);
323 }
324 return state.components;
325}
326
327inline std::vector<int> tearing_recommendation(const casadi::Sparsity &incidence,
328 const std::vector<int> &row_indices,
329 const std::vector<int> &col_indices) {
330 const int block_size = static_cast<int>(std::min(row_indices.size(), col_indices.size()));
331 if (block_size <= 1) {
332 return {};
333 }
334
335 std::vector<std::vector<int>> adjacency(static_cast<std::size_t>(block_size));
336 for (int local = 0; local < block_size; ++local) {
337 const int row = row_indices.at(static_cast<std::size_t>(local));
338 const int matched_col = col_indices.at(static_cast<std::size_t>(local));
339 for (int dep_local = 0; dep_local < block_size; ++dep_local) {
340 const int dep_col = col_indices.at(static_cast<std::size_t>(dep_local));
341 if (dep_col == matched_col) {
342 continue;
343 }
344 if (incidence.has_nz(row, dep_col)) {
345 adjacency[static_cast<std::size_t>(local)].push_back(dep_local);
346 }
347 }
348 auto &neighbors = adjacency[static_cast<std::size_t>(local)];
349 std::sort(neighbors.begin(), neighbors.end());
350 neighbors.erase(std::unique(neighbors.begin(), neighbors.end()), neighbors.end());
351 }
352
353 std::vector<bool> removed(static_cast<std::size_t>(block_size), false);
354 std::vector<int> tears;
355
356 while (true) {
357 const auto components = strongly_connected_components(adjacency, removed);
358 std::vector<int> cyclic_component;
359 for (const auto &component : components) {
360 if (component.size() > 1) {
361 cyclic_component = component;
362 break;
363 }
364 }
365 if (cyclic_component.empty()) {
366 break;
367 }
368
369 int best_node = cyclic_component.front();
370 int best_score = -1;
371 for (int node : cyclic_component) {
372 int score = static_cast<int>(adjacency[static_cast<std::size_t>(node)].size());
373 for (int other : cyclic_component) {
374 if (std::find(adjacency[static_cast<std::size_t>(other)].begin(),
375 adjacency[static_cast<std::size_t>(other)].end(),
376 node) != adjacency[static_cast<std::size_t>(other)].end()) {
377 score += 1;
378 }
379 }
380 if (score > best_score) {
381 best_score = score;
382 best_node = node;
383 }
384 }
385
386 removed[static_cast<std::size_t>(best_node)] = true;
387 tears.push_back(col_indices.at(static_cast<std::size_t>(best_node)));
388 }
389
390 return tears;
391}
392
393} // namespace detail
394
403 const StructuralTransformOptions &opts = {}) {
404 detail::validate_options(opts, "alias_eliminate");
405 detail::validate_selected_block(fn, opts, "alias_eliminate");
406
407 const auto &cfn = fn.casadi_function();
408 const auto inputs = cfn.mx_in();
409 const auto outputs = cfn(inputs);
410
411 const casadi::MX selected_input = inputs.at(static_cast<std::size_t>(opts.input_idx));
412 const casadi::MX selected_output = outputs.at(static_cast<std::size_t>(opts.output_idx));
413
414 const casadi::MX state_symbol =
415 janus::sym(cfn.name_in(opts.input_idx) + "_struct", selected_input.nnz(), 1);
416 std::vector<casadi::MX> state_exprs = detail::mx_elements(state_symbol);
417 std::vector<casadi::MX> residuals =
418 detail::mx_elements(casadi::MX::substitute(std::vector<casadi::MX>{selected_output},
419 std::vector<casadi::MX>{selected_input},
420 std::vector<casadi::MX>{state_symbol})
421 .front());
422
423 std::vector<int> active_var_indices = detail::make_index_vector(selected_input.nnz());
424 std::vector<int> active_residual_indices = detail::make_index_vector(selected_output.nnz());
425
426 struct RawAlias {
427 int residual_index;
428 int variable_index;
429 casadi::MX replacement;
430 };
431 std::vector<RawAlias> raw_aliases;
432
433 bool progress = true;
434 while (progress) {
435 progress = false;
436 for (int residual_index : active_residual_indices) {
437 detail::AliasCandidate candidate;
439 residuals.at(static_cast<std::size_t>(residual_index)), state_symbol,
440 active_var_indices, opts, candidate)) {
441 continue;
442 }
443
444 const int pivot_original = candidate.pivot_index;
445 std::vector<casadi::MX> substitution_exprs = detail::mx_elements(state_symbol);
446 substitution_exprs.at(static_cast<std::size_t>(pivot_original)) = candidate.replacement;
447 const casadi::MX substitution_vector = casadi::MX::vertcat(substitution_exprs);
448
449 residuals = casadi::MX::substitute(residuals, std::vector<casadi::MX>{state_symbol},
450 std::vector<casadi::MX>{substitution_vector});
451 state_exprs = casadi::MX::substitute(state_exprs, std::vector<casadi::MX>{state_symbol},
452 std::vector<casadi::MX>{substitution_vector});
453
454 raw_aliases.push_back(RawAlias{residual_index, pivot_original, candidate.replacement});
455 active_var_indices = detail::erase_value(active_var_indices, pivot_original);
456 active_residual_indices = detail::erase_value(active_residual_indices, residual_index);
457 progress = true;
458 break;
459 }
460 }
461
462 std::vector<int> eliminated_variable_indices;
463 std::vector<int> eliminated_residual_indices;
464 eliminated_variable_indices.reserve(raw_aliases.size());
465 eliminated_residual_indices.reserve(raw_aliases.size());
466 for (const auto &alias : raw_aliases) {
467 eliminated_variable_indices.push_back(alias.variable_index);
468 eliminated_residual_indices.push_back(alias.residual_index);
469 }
470
471 std::vector<casadi::MX> wrapper_inputs_mx;
472 std::vector<SymbolicArg> wrapper_inputs;
473 wrapper_inputs_mx.reserve(static_cast<std::size_t>(cfn.n_in()));
474 wrapper_inputs.reserve(static_cast<std::size_t>(cfn.n_in()));
475
476 casadi::MX reduced_input;
477 for (int i = 0; i < cfn.n_in(); ++i) {
478 if (i == opts.input_idx) {
479 reduced_input =
480 janus::sym(cfn.name_in(i), static_cast<int>(active_var_indices.size()), 1);
481 wrapper_inputs_mx.push_back(reduced_input);
482 wrapper_inputs.emplace_back(reduced_input);
483 } else {
484 casadi::MX arg = janus::sym(cfn.name_in(i), cfn.size1_in(i), cfn.size2_in(i));
485 wrapper_inputs_mx.push_back(arg);
486 wrapper_inputs.emplace_back(arg);
487 }
488 }
489
490 std::vector<casadi::MX> subs_from;
491 std::vector<casadi::MX> subs_to;
492 subs_from.reserve(static_cast<std::size_t>(cfn.n_in()));
493 subs_to.reserve(static_cast<std::size_t>(cfn.n_in()));
494
495 std::vector<casadi::MX> reduced_state_substitution(selected_input.nnz(), 0.0);
496 for (std::size_t k = 0; k < active_var_indices.size(); ++k) {
497 reduced_state_substitution.at(static_cast<std::size_t>(active_var_indices[k])) =
498 reduced_input(static_cast<int>(k));
499 }
500 subs_from.push_back(state_symbol);
501 subs_to.push_back(casadi::MX::vertcat(reduced_state_substitution));
502 for (int i = 0; i < cfn.n_in(); ++i) {
503 if (i == opts.input_idx) {
504 continue;
505 }
506 subs_from.push_back(inputs.at(static_cast<std::size_t>(i)));
507 subs_to.push_back(wrapper_inputs_mx.at(static_cast<std::size_t>(i)));
508 }
509
510 const std::vector<casadi::MX> reduced_residual_exprs =
511 casadi::MX::substitute(residuals, subs_from, subs_to);
512 const std::vector<casadi::MX> full_state_exprs =
513 casadi::MX::substitute(state_exprs, subs_from, subs_to);
514
515 const casadi::MX reduced_residual =
516 detail::vertcat_subset(reduced_residual_exprs, active_residual_indices);
517 const casadi::MX reconstructed_state =
518 full_state_exprs.empty() ? casadi::MX(0, 1) : casadi::MX::vertcat(full_state_exprs);
519
520 std::vector<AliasSubstitution> substitutions;
521 substitutions.reserve(raw_aliases.size());
522 for (const auto &alias : raw_aliases) {
523 const casadi::MX replacement =
524 casadi::MX::substitute(std::vector<casadi::MX>{alias.replacement}, subs_from, subs_to)
525 .front();
526 substitutions.push_back(
527 AliasSubstitution{alias.residual_index, alias.variable_index, replacement});
528 }
529
531 Function(cfn.name() + "_alias_reduced", wrapper_inputs,
532 std::vector<SymbolicArg>{SymbolicArg(reduced_residual)}),
533 Function(cfn.name() + "_alias_reconstruct", wrapper_inputs,
534 std::vector<SymbolicArg>{SymbolicArg(reconstructed_state)}),
535 active_var_indices,
536 eliminated_variable_indices,
537 active_residual_indices,
538 eliminated_residual_indices,
539 substitutions,
540 };
541}
542
551 const StructuralTransformOptions &opts = {}) {
552 detail::validate_options(opts, "block_triangularize");
553 detail::validate_selected_block(fn, opts, "block_triangularize");
554
555 const casadi::Sparsity incidence_sp =
556 get_jacobian_sparsity(fn, opts.output_idx, opts.input_idx).casadi_sparsity();
557
558 std::vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
559 incidence_sp.btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
560
561 std::vector<StructuralBlock> blocks;
562 const std::size_t n_blocks = rowblock.size() > 0 ? rowblock.size() - 1 : 0;
563 blocks.reserve(n_blocks);
564 for (std::size_t block = 0; block < n_blocks; ++block) {
565 std::vector<int> block_rows;
566 std::vector<int> block_cols;
567 for (casadi_int k = rowblock[block]; k < rowblock[block + 1]; ++k) {
568 block_rows.push_back(static_cast<int>(rowperm[k]));
569 }
570 for (casadi_int k = colblock[block]; k < colblock[block + 1]; ++k) {
571 block_cols.push_back(static_cast<int>(colperm[k]));
572 }
573
574 blocks.push_back(StructuralBlock{
575 block_rows,
576 block_cols,
577 detail::tearing_recommendation(incidence_sp, block_rows, block_cols),
578 });
579 }
580
581 return BLTDecomposition{
582 SparsityPattern(incidence_sp), detail::casadi_to_int(rowperm),
584 detail::casadi_to_int(colblock), detail::casadi_to_int(coarse_rowblock),
585 detail::casadi_to_int(coarse_colblock), blocks,
586 };
587}
588
597 const StructuralTransformOptions &opts = {}) {
598 AliasEliminationResult alias = alias_eliminate(fn, opts);
599
600 StructuralTransformOptions reduced_opts = opts;
601 reduced_opts.output_idx = 0;
602 BLTDecomposition blt = block_triangularize(alias.reduced_function, reduced_opts);
603
604 return StructuralAnalysis{std::move(alias), std::move(blt)};
605}
606
607} // namespace janus
Symbolic function wrapper around CasADi with Eigen-native IO.
Custom exception hierarchy for Janus framework.
Core type aliases for numeric and symbolic Eigen/CasADi interop.
Sparsity pattern analysis, graph coloring, and sparse derivative evaluators.
Wrapper around casadi::Function providing Eigen-native IO.
Definition Function.hpp:46
const casadi::Function & casadi_function() const
Access the underlying CasADi function.
Definition Function.hpp:186
Input validation failed (e.g., mismatched sizes, invalid parameters).
Definition JanusError.hpp:31
Definition Sparsity.hpp:38
const casadi::Sparsity & casadi_sparsity() const
Access underlying CasADi Sparsity object.
Definition Sparsity.hpp:377
Smooth approximation of ReLU function: softplus(x) = (1/beta) * log(1 + exp(beta * x)).
Definition Diagnostics.hpp:131
std::vector< std::vector< int > > strongly_connected_components(const std::vector< std::vector< int > > &adjacency, const std::vector< bool > &removed)
Definition StructuralTransforms.hpp:307
void tarjan_visit(int node, TarjanState &state)
Definition StructuralTransforms.hpp:272
void validate_options(const StructuralTransformOptions &opts, const std::string &context)
Definition StructuralTransforms.hpp:98
std::vector< int > find_row_nonzeros(const casadi::MX &A, int row)
Definition StructuralTransforms.hpp:160
std::vector< int > erase_value(const std::vector< int > &values, int erased_index)
Definition StructuralTransforms.hpp:246
bool coefficients_are_constant(const casadi::MX &A, int row, const std::vector< int > &nz_cols)
Definition StructuralTransforms.hpp:181
casadi::MX vertcat_subset(const std::vector< casadi::MX > &elems, const std::vector< int > &indices)
Definition StructuralTransforms.hpp:150
std::vector< casadi::MX > mx_elements(const casadi::MX &v)
Definition StructuralTransforms.hpp:139
std::vector< int > make_index_vector(int n)
Definition StructuralTransforms.hpp:133
void validate_selected_block(const Function &fn, const StructuralTransformOptions &opts, const std::string &context)
Definition StructuralTransforms.hpp:110
std::vector< int > tearing_recommendation(const casadi::Sparsity &incidence, const std::vector< int > &row_indices, const std::vector< int > &col_indices)
Definition StructuralTransforms.hpp:327
bool try_make_alias_candidate(const casadi::MX &expr, const casadi::MX &state_symbol, const std::vector< int > &active_var_indices, const StructuralTransformOptions &opts, AliasCandidate &candidate)
Definition StructuralTransforms.hpp:196
bool has_no_free_symbols(const casadi::MX &expr)
Definition StructuralTransforms.hpp:171
std::vector< int > casadi_to_int(const std::vector< casadi_int > &values)
Definition StructuralTransforms.hpp:257
Definition Diagnostics.hpp:19
BLTDecomposition block_triangularize(const Function &fn, const StructuralTransformOptions &opts={})
Compute a block-triangular decomposition of a selected residual block.
Definition StructuralTransforms.hpp:550
SymbolicScalar sym(const std::string &name)
Create a named symbolic scalar variable.
Definition JanusTypes.hpp:90
AliasEliminationResult alias_eliminate(const Function &fn, const StructuralTransformOptions &opts={})
Eliminate trivial affine alias rows from a selected residual block.
Definition StructuralTransforms.hpp:402
StructuralAnalysis structural_analyze(const Function &fn, const StructuralTransformOptions &opts={})
Run alias elimination followed by BLT decomposition.
Definition StructuralTransforms.hpp:596
SparsityPattern get_jacobian_sparsity(const Function &fn, int output_idx=0, int input_idx=0)
Get sparsity of a janus::Function Jacobian.
Definition Sparsity.hpp:951
casadi::MX SymbolicScalar
CasADi MX symbolic scalar.
Definition JanusTypes.hpp:70
Result of alias elimination on a selected residual block.
Definition StructuralTransforms.hpp:48
std::vector< int > kept_variable_indices
Original indices of kept variables.
Definition StructuralTransforms.hpp:51
std::vector< AliasSubstitution > substitutions
Applied substitution records.
Definition StructuralTransforms.hpp:55
Function reconstruct_full_input
Maps reduced inputs back to original ordering.
Definition StructuralTransforms.hpp:50
std::vector< int > eliminated_variable_indices
Original indices of eliminated variables.
Definition StructuralTransforms.hpp:52
std::vector< int > eliminated_residual_indices
Original indices of eliminated residuals.
Definition StructuralTransforms.hpp:54
std::vector< int > kept_residual_indices
Original indices of kept residuals.
Definition StructuralTransforms.hpp:53
Function reduced_function
Function with aliases removed.
Definition StructuralTransforms.hpp:49
A single eliminated alias or trivial affine variable relation.
Definition StructuralTransforms.hpp:34
int residual_index
Row that was eliminated.
Definition StructuralTransforms.hpp:35
SymbolicScalar replacement
Expression replacing the eliminated variable.
Definition StructuralTransforms.hpp:37
int eliminated_variable_index
Variable solved for.
Definition StructuralTransforms.hpp:36
Block-triangular decomposition and tearing metadata for a selected block.
Definition StructuralTransforms.hpp:74
std::vector< int > column_block_offsets
Fine column block boundaries.
Definition StructuralTransforms.hpp:79
std::vector< int > coarse_column_block_offsets
Coarse column block boundaries.
Definition StructuralTransforms.hpp:81
std::vector< int > coarse_row_block_offsets
Coarse row block boundaries.
Definition StructuralTransforms.hpp:80
std::vector< StructuralBlock > blocks
Diagonal blocks with tearing info.
Definition StructuralTransforms.hpp:82
std::vector< int > row_permutation
BTF row permutation.
Definition StructuralTransforms.hpp:76
std::vector< int > column_permutation
BTF column permutation.
Definition StructuralTransforms.hpp:77
std::vector< int > row_block_offsets
Fine row block boundaries.
Definition StructuralTransforms.hpp:78
SparsityPattern incidence
Incidence (Jacobian sparsity) of the block.
Definition StructuralTransforms.hpp:75
Combined alias-elimination and BLT analysis pass.
Definition StructuralTransforms.hpp:91
BLTDecomposition blt
BLT decomposition of the reduced system.
Definition StructuralTransforms.hpp:93
AliasEliminationResult alias_elimination
Alias elimination pass result.
Definition StructuralTransforms.hpp:92
One diagonal block in a block-triangular decomposition.
Definition StructuralTransforms.hpp:61
bool is_coupled() const
Check if the block involves multiple coupled equations.
Definition StructuralTransforms.hpp:68
std::vector< int > residual_indices
Residual rows in this block.
Definition StructuralTransforms.hpp:62
std::vector< int > variable_indices
Variable columns in this block.
Definition StructuralTransforms.hpp:63
std::vector< int > tear_variable_indices
Recommended tearing variables.
Definition StructuralTransforms.hpp:64
Options for structural simplification and analysis passes.
Definition StructuralTransforms.hpp:23
bool require_constant_alias_coefficients
Require constant (symbol-free) coefficients.
Definition StructuralTransforms.hpp:27
int output_idx
Index of the output block to analyze.
Definition StructuralTransforms.hpp:25
int max_alias_row_nnz
Max non-zeros in an alias candidate row.
Definition StructuralTransforms.hpp:26
int input_idx
Index of the input block to analyze.
Definition StructuralTransforms.hpp:24
Definition StructuralTransforms.hpp:191
casadi::MX replacement
Definition StructuralTransforms.hpp:193
int pivot_index
Definition StructuralTransforms.hpp:192
Definition StructuralTransforms.hpp:261
std::vector< int > lowlink
Definition StructuralTransforms.hpp:265
int next_index
Definition StructuralTransforms.hpp:268
const std::vector< std::vector< int > > & adjacency
Definition StructuralTransforms.hpp:262
std::vector< bool > on_stack
Definition StructuralTransforms.hpp:267
std::vector< int > index
Definition StructuralTransforms.hpp:264
std::vector< std::vector< int > > components
Definition StructuralTransforms.hpp:269
std::vector< int > stack
Definition StructuralTransforms.hpp:266
const std::vector< bool > & removed
Definition StructuralTransforms.hpp:263