Typedefs | Functions
casadi::IndexReduction Namespace Reference

Typedefs

typedef struct VariableStruct Variable
 
typedef struct EquationStruct Equation
 
typedef struct GraphStruct Graph
 

Functions

void graph_add_der (Graph &G, Variable *v)
 
void add_variable (Equation *e, Variable *v)
 
void graph_add_der (Graph &G, Equation *e, bool add_old=false)
 
bool dfs_match_pantelides (Equation *i)
 
bool dae_struct_detect_pantelides (Graph &G, std::vector< casadi_int > &var_map, std::vector< casadi_int > &eq_map, casadi_int max_iter)
 Perform Pantelides algorithm for DAE index reduction. More...
 
void dae_struct_detect (const std::string &algorithm, const Sparsity &graph, std::vector< casadi_int > &var_map, std::vector< casadi_int > &eq_map, casadi_int max_iter)
 

Typedef Documentation

◆ Equation

typedef struct EquationStruct casadi::IndexReduction::Equation

Definition at line 1226 of file integration_tools.cpp.

◆ Graph

typedef struct GraphStruct casadi::IndexReduction::Graph

Definition at line 1226 of file integration_tools.cpp.

◆ Variable

typedef struct VariableStruct casadi::IndexReduction::Variable

Definition at line 1226 of file integration_tools.cpp.

Function Documentation

◆ add_variable()

void casadi::IndexReduction::add_variable ( Equation e,
Variable v 
)

Definition at line 478 of file integration_tools.cpp.

478  {
479  auto it = std::find(e->vars0.begin(), e->vars0.end(), v);
480  if (it==e->vars0.end()) {
481  e->vars0.push_back(v);
482  if (!v->deleted) {
483  e->vars.push_back(v);
484  v->eqs.push_back(e);
485  }
486  }
487  }

Referenced by graph_add_der().

◆ dae_struct_detect()

void casadi::IndexReduction::dae_struct_detect ( const std::string &  algorithm,
const Sparsity graph,
std::vector< casadi_int > &  var_map,
std::vector< casadi_int > &  eq_map,
casadi_int  max_iter 
)

Definition at line 655 of file integration_tools.cpp.

658  {
659  // Input sanitization
660  casadi_assert(var_map.size()==graph.size2(),
661  "var_map size must match graph columns.");
662 
663  // Graph structure
664  Graph G;
665 
666  // Allocate space for node representation
667  G.E.resize(graph.size1(), nullptr);
668  G.V.resize(graph.size2(), nullptr);
669  G.nrow_orig = graph.size1();
670  G.ncol_orig = graph.size2();
671 
672  for (auto*& e : G.E) e = new Equation();
673  for (auto*& v : G.V) v = new Variable();
674 
675  // Set positions
676  casadi_int i;
677  i=0; for (auto* e : G.E) e->i = i++;
678  i=0; for (auto* v : G.V) v->i = i++;
679 
680  // Create edges using incidence sparsity
681  const casadi_int* colind = graph.colind();
682  const casadi_int* row = graph.row();
683 
684  // Loop over incidence columns
685  for (casadi_int c=0;c<graph.size2();++c) {
686  // Loop over nonzeros
687  for (casadi_int j=colind[c]; j<colind[c+1]; ++j) {
688  casadi_int r = row[j];
689  G.V[c]->eqs.push_back(G.E[r]); // Non-monotone
690  G.E[r]->vars.push_back(G.V[c]);
691  }
692  }
693 
694  // Process var_map
695  for (casadi_int i=0;i<var_map.size();++i) {
696  Variable* v = G.V[i];
697  casadi_int i_der = var_map[i];
698  if (i_der>=0) {
699  Variable* e = G.V[i_der];
700  v->der = e;
701  e->der_inv = v;
702  }
703  }
704 
705  for (auto* v : G.V) v->eqs0 = v->eqs;
706  for (auto* e : G.E) e->vars0 = e->vars;
707 
708  bool detect = false;
709  if (algorithm=="pantelides") {
710  detect = dae_struct_detect_pantelides(G, var_map, eq_map, max_iter);
711  } else {
712  // Clean up
713  for (auto* v : G.V) delete v;
714  for (auto* e : G.E) delete e;
715  casadi_error("Algorithm '" + algorithm + "' not recognized.");
716  }
717  if (!detect) {
718  for (auto* v : G.V) delete v;
719  for (auto* e : G.E) delete e;
720  casadi_error("Structural detection failed.");
721  }
722 
723  // Prepare outputs
724  var_map.resize(G.V.size());
725  eq_map.resize(G.E.size());
726 
727  int k = 0;
728  // Populate var_map
729  for (auto* v : G.V) {
730  if (v->der) {
731  var_map[v->i] = v->der->i;
732  } else {
733  var_map[v->i] = -1;
734  }
735  casadi_assert_dev(v->i==k);
736  k++;
737  }
738 
739  k = 0;
740  // Populate eq_map
741  for (auto* e : G.E) {
742  if (e->der) {
743  eq_map[e->i] = e->der->i;
744  } else {
745  eq_map[e->i] = -1;
746  }
747  casadi_assert_dev(e->i==k);
748  k++;
749  }
750 
751  // Clean up
752  for (auto* v : G.V) delete v;
753  for (auto* e : G.E) delete e;
754 
755  }
struct EquationStruct Equation
bool dae_struct_detect_pantelides(Graph &G, std::vector< casadi_int > &var_map, std::vector< casadi_int > &eq_map, casadi_int max_iter)
Perform Pantelides algorithm for DAE index reduction.
struct GraphStruct Graph
struct VariableStruct Variable

References casadi::Sparsity::colind(), dae_struct_detect_pantelides(), casadi::Sparsity::row(), casadi::Sparsity::size1(), and casadi::Sparsity::size2().

Referenced by casadi::reduce_index_gen().

◆ dae_struct_detect_pantelides()

bool casadi::IndexReduction::dae_struct_detect_pantelides ( Graph G,
std::vector< casadi_int > &  var_map,
std::vector< casadi_int > &  eq_map,
casadi_int  max_iter 
)

The algorithm works purely on structure: no symbolics equations are used.

Parameters
graphStructural relation between equations (columns) and variables (rows)
var_mapIndicate for each variable where its derivative can be found in the variable list if var_map[i]>=0: var[var_map[i]] == dot(var[i]) Size will increase to accommodate new variables introduced by index reduction
eq_mapIndicate for each equation if it should be differentiated if eq_map[i]>=0: eq[eq_map[i]] == dot(eq[i]) Size will increase over the original number of equations to accommodate extra equations introduced by index reduction

Definition at line 575 of file integration_tools.cpp.

577  {
578 
579  // Pantelides alg 4.1: Set N'=N do (2)
580  casadi_int Np = G.E.size();
581  // Pantelides alg 4.1: For k=1 to N' do (3)
582  for (casadi_int k=0;k<Np;++k) {
583  // Pantelides alg 4.1: Set i=k (3a)
584  Equation* i = G.E[k];
585 
586  casadi_int iter = 0;
587  // Pantelides alg 4.1: Repeat (3b)
588  while (true) {
589  if (iter++ > max_iter) return false;
590  // Pantelides alg 4.1: delete all V-nodes with A!=0 and their incident edges
591  // * from the graph (3b-1)
592  for (auto* v : G.V) {
593  if (v->der) {
594  v->deleted = true;
595  v->eqs.clear();
596  for (auto* e : G.E) {
597  auto it = std::find(e->vars.begin(), e->vars.end(), v);
598  if (it!=e->vars.end()) e->vars.erase(it);
599  }
600  }
601  }
602 
603  // Pantelides alg 4.1: Designate all nodes as "uncoloured" (3b-2)
604  for (auto* v : G.V) v->visited = false;
605  for (auto* e : G.E) e->visited = false;
606 
607  // Pantelides alg 4.1: Set PATHFOUND= FALSE (3b-3)
608  // Pantelides alg 4.1: AUGMENTPATH (i, PATHFOUND) (3b-4)
609  // Pantelides alg 4.1: Until PATHFOUND (3c)
610  if (dfs_match_pantelides(i)) break; // out of while loop
611 
612  // Pantelides alg 4.1: If PATHFOUND FALSE then (3b-5)
613  casadi_int n = G.V.size();
614  // Pantelides alg 4.1: For every coloured V-node j do (3b-5-i)
615  for (casadi_int jj=0;jj<n;++jj) {
616  Variable* j = G.V[jj];
617  if (j->visited && !j->deleted) {
618  graph_add_der(G, j);
619  }
620  }
621 
622  // Pantelides alg 4.1: For every coloured E-node l do (3b-5-ii)
623  n = G.E.size();
624  for (casadi_int ll=0;ll<n;++ll) {
625  Equation* l = G.E[ll];
626  if (l->visited) graph_add_der(G, l, true);
627  }
628 
629  for (casadi_int ll=n;ll<G.E.size();++ll) {
630  Equation* l = G.E[ll];
631  bool valid = false;
632  for (auto* v : l->vars0) {
633  if (!v->eqs.empty()) valid = true;
634  }
635  if (!valid) return false;
636  }
637 
638  // Pantelides alg 4.1: For every coloured V-node j set
639  // ASSIGN (A(j))= B(ASSIGN (j)) (3b-5-iii)
640  for (auto* j : G.V) {
641  if (j->visited && !j->deleted) {
642  j->der->assign = j->assign->der;
643  j->assign->der->assign = j->der;
644  }
645  }
646 
647  // Pantelides alg 4.1: Set i=B(i) (3b-5-iv)
648  i = i->der;
649 
650  }
651  }
652  return true;
653  }
bool dfs_match_pantelides(Equation *i)
void graph_add_der(Graph &G, Variable *v)

References dfs_match_pantelides(), and graph_add_der().

Referenced by dae_struct_detect().

◆ dfs_match_pantelides()

bool casadi::IndexReduction::dfs_match_pantelides ( Equation i)

Definition at line 515 of file integration_tools.cpp.

515  {
516 
517  // Pantelides alg 3.2: Colour i (1)
518  i->visited = true;
519 
520  // Look for unassigned candidate variables
521  // Pantelides alg 3.2: (2) If a V-node j exists such that edge (i-j) exists...
522  for (auto* j : i->vars) {
523  // Pantelides alg 3.2: ... and ASSIGN (j)= 0 then:
524  if (j->assign==nullptr) {
525  // Found such variable
526  // Assign
527  // Pantelides alg 3.2: (2b) Set ASSIGN(j)=i
528  j->assign = i; i->assign = j;
529 
530  // Pantelides alg 3.2: (2a) set PATHFOUND = TRUE, (2c) return
531  return true; // End successfully
532  }
533  }
534 
535  // Look for assigned candidate variables
536  // Pantelides alg 3.2: (3) For every j such that edge (i-j) exists
537  for (auto j : i->vars) {
538  // Pantelides alg 3.2: ... and j is uncoloured do:
539  if (!j->visited) {
540  // Pantelides alg 3.2: (3a) Colour j
541  j->visited = true;
542 
543  // Pantelides alg 3.2: (3b) Set k = ASSIGN (j)
544  Equation* k = j->assign;
545 
546  // Pantelides alg 3.2: (3c) AUGMENTPATH (k, PATHFOUND)
547  if (dfs_match_pantelides(k)) {
548  // Re-assignment
549  // Pantelides alg 3.2: (3d-1) Set ASSIGN (j) = i
550  j->assign = i; i->assign = j;
551  // Pantelides alg 3.2: (3d-2) Return
552  return true;
553  }
554 
555  }
556  }
557 
558  // Exhausted all options; return unsuccessfully
559  return false;
560  }

Referenced by dae_struct_detect_pantelides().

◆ graph_add_der() [1/2]

void casadi::IndexReduction::graph_add_der ( Graph G,
Equation e,
bool  add_old = false 
)

Definition at line 489 of file integration_tools.cpp.

489  {
490  // Push new equation to the graph
491  G.E.push_back(new Equation());
492 
493  Equation* e_new = G.E.back();
494 
495  // Get a position
496  e_new->i = G.E.size()-1;
497 
498  // Add derivative relationship between new and old equation
499  e_new->der_inv = e;
500  e->der = e_new;
501 
502  // Loop over all variables in old equation
503  for (auto* v : e->vars0) {
504  // We depend on the old variable
505  if (add_old) {
506  add_variable(e_new, v);
507  }
508  // And we depend on its derivative (create if not present)
509  if (!v->der) graph_add_der(G, v);
510  add_variable(e_new, v->der);
511  }
512 
513  }
void add_variable(Equation *e, Variable *v)

References add_variable(), and graph_add_der().

◆ graph_add_der() [2/2]

void casadi::IndexReduction::graph_add_der ( Graph G,
Variable v 
)

Definition at line 465 of file integration_tools.cpp.

465  {
466  // Push new equation to the graph
467  G.V.push_back(new Variable());
468  Variable* v_new = G.V.back();
469 
470  // Get a position
471  v_new->i = G.V.size()-1;
472 
473  // Add derivative relationship between new and old variable
474  v_new->der_inv = v;
475  v->der = v_new;
476  }

Referenced by dae_struct_detect_pantelides(), and graph_add_der().