1 /*
2  *    This file is part of CasADi.
3  *
4  *    CasADi -- A symbolic framework for dynamic optimization.
5  *    Copyright (C) 2010-2014 Joel Andersson, Joris Gillis, Moritz Diehl,
6  *                            K.U. Leuven. All rights reserved.
7  *    Copyright (C) 2011-2014 Greg Horn
8  *
9  *    CasADi is free software; you can redistribute it and/or
10  *    modify it under the terms of the GNU Lesser General Public
11  *    License as published by the Free Software Foundation; either
12  *    version 3 of the License, or (at your option) any later version.
13  *
14  *    CasADi is distributed in the hope that it will be useful,
15  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *    Lesser General Public License for more details.
18  *
19  *    You should have received a copy of the GNU Lesser General Public
20  *    License along with CasADi; if not, write to the Free Software
21  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 
26 #include "dae_builder.hpp"
27 
28 #include <cctype>
29 #include <ctime>
30 #include <map>
31 #include <set>
32 #include <sstream>
33 #include <string>
34 
35 #include "casadi_misc.hpp"
36 #include "exception.hpp"
37 #include "code_generator.hpp"
38 #include "calculus.hpp"
39 #include "xml_file.hpp"
40 #include "external.hpp"
41 
42 using namespace std;
43 namespace casadi {
44 
DaeBuilder()45   DaeBuilder::DaeBuilder() {
46     this->t = MX::sym("t");
47   }
48 
parse_fmi(const std::string & filename)49   void DaeBuilder::parse_fmi(const std::string& filename) {
50 
51     // Load
52     XmlFile xml_file("tinyxml");
53     XmlNode document = xml_file.parse(filename);
54 
55     // **** Add model variables ****
56     {
57       // Get a reference to the ModelVariables node
58       const XmlNode& modvars = document[0]["ModelVariables"];
59 
60       // Add variables
61       for (casadi_int i=0; i<modvars.size(); ++i) {
62 
63         // Get a reference to the variable
64         const XmlNode& vnode = modvars[i];
65 
66         // Get the attributes
67         string name        = vnode.getAttribute("name");
68         casadi_int valueReference;
69         vnode.readAttribute("valueReference", valueReference);
70         string variability = vnode.getAttribute("variability");
71         string causality   = vnode.getAttribute("causality");
72         string alias       = vnode.getAttribute("alias");
73 
74         // Skip to the next variable if its an alias
75         if (alias == "alias" || alias == "negatedAlias")
76           continue;
77 
78         // Get the name
79         const XmlNode& nn = vnode["QualifiedName"];
80         string qn = qualified_name(nn);
81 
82         // Add variable, if not already added
83         if (varmap_.find(qn)==varmap_.end()) {
84 
85           // Create variable
86           Variable var(name);
87 
88           // Value reference
89           var.valueReference = valueReference;
90 
91           // Variability
92           if (variability=="constant")
93             var.variability = CONSTANT;
94           else if (variability=="parameter")
95             var.variability = PARAMETER;
96           else if (variability=="discrete")
97             var.variability = DISCRETE;
98           else if (variability=="continuous")
99             var.variability = CONTINUOUS;
100           else
101             throw CasadiException("Unknown variability");
102 
103           // Causality
104           if (causality=="input")
105             var.causality = INPUT;
106           else if (causality=="output")
107             var.causality = OUTPUT;
108           else if (causality=="internal")
109             var.causality = INTERNAL;
110           else
111             throw CasadiException("Unknown causality");
112 
113           // Alias
114           if (alias=="noAlias")
115             var.alias = NO_ALIAS;
116           else if (alias=="alias")
117             var.alias = ALIAS;
118           else if (alias=="negatedAlias")
119             var.alias = NEGATED_ALIAS;
120           else
121             throw CasadiException("Unknown alias");
122 
123           // Other properties
124           if (vnode.hasChild("Real")) {
125             const XmlNode& props = vnode["Real"];
126             props.readAttribute("unit", var.unit, false);
127             props.readAttribute("displayUnit", var.display_unit, false);
128             props.readAttribute("min", var.min, false);
129             props.readAttribute("max", var.max, false);
130             props.readAttribute("initialGuess", var.guess, false);
131             props.readAttribute("start", var.start, false);
132             props.readAttribute("nominal", var.nominal, false);
133             props.readAttribute("free", var.free, false);
134           }
135 
136           // Variable category
137           if (vnode.hasChild("VariableCategory")) {
138             string cat = vnode["VariableCategory"].getText();
139             if (cat=="derivative")
140               var.category = CAT_DERIVATIVE;
141             else if (cat=="state")
142               var.category = CAT_STATE;
143             else if (cat=="dependentConstant")
144               var.category = CAT_DEPENDENT_CONSTANT;
145             else if (cat=="independentConstant")
146               var.category = CAT_INDEPENDENT_CONSTANT;
147             else if (cat=="dependentParameter")
148               var.category = CAT_DEPENDENT_PARAMETER;
149             else if (cat=="independentParameter")
150               var.category = CAT_INDEPENDENT_PARAMETER;
151             else if (cat=="algebraic")
152               var.category = CAT_ALGEBRAIC;
153             else
154               throw CasadiException("Unknown variable category: " + cat);
155           }
156 
157           // Add to list of variables
158           add_variable(qn, var);
159 
160           // Sort expression
161           switch (var.category) {
162           case CAT_DERIVATIVE:
163             // Skip - meta information about time derivatives is
164             //        kept together with its parent variable
165             break;
166           case CAT_STATE:
167             this->s.push_back(var.v);
168             this->sdot.push_back(var.d);
169             break;
170           case CAT_DEPENDENT_CONSTANT:
171             // Skip
172             break;
173           case CAT_INDEPENDENT_CONSTANT:
174             // Skip
175             break;
176           case CAT_DEPENDENT_PARAMETER:
177             // Skip
178             break;
179           case CAT_INDEPENDENT_PARAMETER:
180             if (var.free) {
181               this->p.push_back(var.v);
182             } else {
183               // Skip
184             }
185             break;
186           case CAT_ALGEBRAIC:
187             if (var.causality == INTERNAL) {
188               this->s.push_back(var.v);
189               this->sdot.push_back(var.d);
190             } else if (var.causality == INPUT) {
191               this->u.push_back(var.v);
192             }
193             break;
194           default:
195             casadi_error("Unknown category");
196           }
197         }
198       }
199     }
200 
201     // **** Add binding equations ****
202     {
203       // Get a reference to the BindingEquations node
204       const XmlNode& bindeqs = document[0]["equ:BindingEquations"];
205 
206       for (casadi_int i=0; i<bindeqs.size(); ++i) {
207         const XmlNode& beq = bindeqs[i];
208 
209         // Get the variable and binding expression
210         Variable& var = read_variable(beq[0]);
211         MX bexpr = read_expr(beq[1][0]);
212         this->d.push_back(var.v);
213         this->ddef.push_back(bexpr);
214       }
215     }
216 
217     // **** Add dynamic equations ****
218     {
219       // Get a reference to the DynamicEquations node
220       const XmlNode& dyneqs = document[0]["equ:DynamicEquations"];
221 
222       // Add equations
223       for (casadi_int i=0; i<dyneqs.size(); ++i) {
224 
225         // Get a reference to the variable
226         const XmlNode& dnode = dyneqs[i];
227 
228         // Add the differential equation
229         MX de_new = read_expr(dnode[0]);
230         this->dae.push_back(de_new);
231       }
232     }
233 
234     // **** Add initial equations ****
235     {
236       // Get a reference to the DynamicEquations node
237       const XmlNode& initeqs = document[0]["equ:InitialEquations"];
238 
239       // Add equations
240       for (casadi_int i=0; i<initeqs.size(); ++i) {
241 
242         // Get a reference to the node
243         const XmlNode& inode = initeqs[i];
244 
245         // Add the differential equations
246         for (casadi_int i=0; i<inode.size(); ++i) {
247           this->init.push_back(read_expr(inode[i]));
248         }
249       }
250     }
251 
252     // **** Add optimization ****
253     if (document[0].hasChild("opt:Optimization")) {
254 
255       // Get a reference to the DynamicEquations node
256       const XmlNode& opts = document[0]["opt:Optimization"];
257       for (casadi_int i=0; i<opts.size(); ++i) {
258 
259         // Get a reference to the node
260         const XmlNode& onode = opts[i];
261 
262         // Get the type
263         if (onode.checkName("opt:ObjectiveFunction")) { // mayer term
264           try {
265             // Add components
266             for (casadi_int i=0; i<onode.size(); ++i) {
267               const XmlNode& var = onode[i];
268 
269               // If string literal, ignore
270               if (var.checkName("exp:StringLiteral"))
271                 continue;
272 
273               // Read expression
274               MX v = read_expr(var);
275 
276               // Treat as an output
277               add_y("mterm", v);
278             }
279           } catch(exception& ex) {
280             throw CasadiException(std::string("addObjectiveFunction failed: ") + ex.what());
281           }
282         } else if (onode.checkName("opt:IntegrandObjectiveFunction")) {
283           try {
284             for (casadi_int i=0; i<onode.size(); ++i) {
285               const XmlNode& var = onode[i];
286 
287               // If string literal, ignore
288               if (var.checkName("exp:StringLiteral")) continue;
289 
290               // Read expression
291               MX v = read_expr(var);
292 
293               // Treat as a quadrature state
294               add_q("lterm");
295               add_quad("lterm_rhs", v);
296             }
297           } catch(exception& ex) {
298             throw CasadiException(std::string("addIntegrandObjectiveFunction failed: ")
299                                   + ex.what());
300           }
301         } else if (onode.checkName("opt:IntervalStartTime")) {
302           // Ignore, treated above
303         } else if (onode.checkName("opt:IntervalFinalTime")) {
304           // Ignore, treated above
305         } else if (onode.checkName("opt:TimePoints")) {
306           // Ignore, treated above
307         } else if (onode.checkName("opt:PointConstraints")) {
308           casadi_warning("opt:PointConstraints not supported, ignored");
309         } else if (onode.checkName("opt:Constraints")) {
310           casadi_warning("opt:Constraints not supported, ignored");
311         } else if (onode.checkName("opt:PathConstraints")) {
312           casadi_warning("opt:PointConstraints not supported, ignored");
313         } else {
314           casadi_warning("DaeBuilder::addOptimization: Unknown node " + str(onode.name()));
315         }
316       }
317     }
318 
319     // Make sure that the dimensions are consistent at this point
320     if (this->s.size()!=this->dae.size()) {
321       casadi_warning("The number of differential-algebraic equations does not match "
322                      "the number of implicitly defined states.");
323     }
324     if (this->z.size()!=this->alg.size()) {
325       casadi_warning("The number of algebraic equations (equations not involving "
326                     "differentiated variables) does not match the number of "
327                     "algebraic variables.");
328     }
329   }
330 
read_variable(const XmlNode & node)331   Variable& DaeBuilder::read_variable(const XmlNode& node) {
332     // Qualified name
333     string qn = qualified_name(node);
334 
335     // Find and return the variable
336     return variable(qn);
337   }
338 
read_expr(const XmlNode & node)339   MX DaeBuilder::read_expr(const XmlNode& node) {
340     const string& fullname = node.name();
341     if (fullname.find("exp:")== string::npos) {
342       casadi_error("DaeBuilder::read_expr: unknown - expression is supposed to "
343                    "start with 'exp:' , got " + fullname);
344     }
345 
346     // Chop the 'exp:'
347     string name = fullname.substr(4);
348 
349     // The switch below is alphabetical, and can be thus made more efficient,
350     // for example by using a switch statement of the first three letters,
351     // if it would ever become a bottleneck
352     if (name=="Add") {
353       return read_expr(node[0]) + read_expr(node[1]);
354     } else if (name=="Acos") {
355       return acos(read_expr(node[0]));
356     } else if (name=="Asin") {
357       return asin(read_expr(node[0]));
358     } else if (name=="Atan") {
359       return atan(read_expr(node[0]));
360     } else if (name=="Cos") {
361       return cos(read_expr(node[0]));
362     } else if (name=="Der") {
363       const Variable& v = read_variable(node[0]);
364       return v.d;
365     } else if (name=="Div") {
366       return read_expr(node[0]) / read_expr(node[1]);
367     } else if (name=="Exp") {
368       return exp(read_expr(node[0]));
369     } else if (name=="Identifier") {
370       return read_variable(node).v;
371     } else if (name=="IntegerLiteral") {
372       casadi_int val;
373       node.getText(val);
374       return val;
375     } else if (name=="Instant") {
376       double val;
377       node.getText(val);
378       return val;
379     } else if (name=="Log") {
380       return log(read_expr(node[0]));
381     } else if (name=="LogLeq") { // Logical less than equal
382       return read_expr(node[0]) <= read_expr(node[1]);
383     } else if (name=="LogGeq") { // Logical greater than equal
384       return read_expr(node[0]) >= read_expr(node[1]);
385     } else if (name=="LogLt") { // Logical less than
386       return read_expr(node[0]) < read_expr(node[1]);
387     } else if (name=="LogGt") { // Logical greater than
388       return read_expr(node[0]) > read_expr(node[1]);
389     } else if (name=="Max") {
390       return fmax(read_expr(node[0]), read_expr(node[1]));
391     } else if (name=="Min") {
392       return fmin(read_expr(node[0]), read_expr(node[1]));
393     } else if (name=="Mul") { // Multiplication
394       return read_expr(node[0]) * read_expr(node[1]);
395     } else if (name=="Neg") {
396       return -read_expr(node[0]);
397     } else if (name=="NoEvent") {
398       // NOTE: This is a workaround, we assume that whenever NoEvent occurs,
399       // what is meant is a switch
400       casadi_int n = node.size();
401 
402       // Default-expression
403       MX ex = read_expr(node[n-1]);
404 
405       // Evaluate ifs
406       for (casadi_int i=n-3; i>=0; i -= 2) {
407         ex = if_else(read_expr(node[i]), read_expr(node[i+1]), ex);
408       }
409 
410       return ex;
411     } else if (name=="Pow") {
412       return pow(read_expr(node[0]), read_expr(node[1]));
413     } else if (name=="RealLiteral") {
414       double val;
415       node.getText(val);
416       return val;
417     } else if (name=="Sin") {
418       return sin(read_expr(node[0]));
419     } else if (name=="Sqrt") {
420       return sqrt(read_expr(node[0]));
421     } else if (name=="StringLiteral") {
422       throw CasadiException(node.getText());
423     } else if (name=="Sub") {
424       return read_expr(node[0]) - read_expr(node[1]);
425     } else if (name=="Tan") {
426       return tan(read_expr(node[0]));
427     } else if (name=="Time") {
428       return t;
429     } else if (name=="TimedVariable") {
430       return read_variable(node[0]).v;
431     }
432 
433     // throw error if reached this point
434     throw CasadiException(string("DaeBuilder::read_expr: Unknown node: ") + name);
435 
436   }
437 
disp(std::ostream & stream,bool more) const438   void DaeBuilder::disp(std::ostream& stream, bool more) const {
439     // Assert correctness
440     if (more) sanity_check();
441 
442     // Print dimensions
443     stream << "ns = " << this->s.size() << ", "
444            << "nx = " << this->x.size() << ", "
445            << "nz = " << this->z.size() << ", "
446            << "nq = " << this->q.size() << ", "
447            << "ny = " << this->y.size() << ", "
448            << "np = " << this->p.size() << ", "
449            << "nd = " << this->d.size() << ", "
450            << "nu = " << this->u.size();
451 
452     // Quick return?
453     if (!more) return;
454     stream << endl;
455 
456     // Print the functions
457     if (!fun_.empty()) {
458       stream << "Functions" << endl;
459       for (const Function& f : fun_) {
460         stream << "  " << f << endl;
461       }
462     }
463 
464     // Print the variables
465     stream << "Variables" << endl;
466     stream << "  t = " << str(this->t) << endl;
467     if (!this->s.empty()) stream << "  s = " << str(this->s) << endl;
468     if (!this->x.empty()) stream << "  x = " << str(this->x) << endl;
469     if (!this->z.empty()) stream << "  z =  " << str(this->z) << endl;
470     if (!this->q.empty()) stream << "  q =  " << str(this->q) << endl;
471     if (!this->y.empty()) stream << "  y =  " << str(this->y) << endl;
472     if (!this->p.empty()) stream << "  p =  " << str(this->p) << endl;
473     if (!this->d.empty()) stream << "  d =  " << str(this->d) << endl;
474     if (!this->u.empty()) stream << "  u =  " << str(this->u) << endl;
475 
476     if (!this->d.empty()) {
477       stream << "Dependent parameters" << endl;
478       for (casadi_int i=0; i<this->d.size(); ++i)
479         stream << "  " << str(this->d[i]) << " == " << str(this->ddef[i]) << endl;
480     }
481 
482     if (!this->dae.empty()) {
483       stream << "Fully-implicit differential-algebraic equations" << endl;
484       for (casadi_int k=0; k<this->dae.size(); ++k) {
485         stream << "  0 == " << this->dae[k] << endl;
486       }
487     }
488 
489     if (!this->x.empty()) {
490       stream << "Differential equations" << endl;
491       for (casadi_int k=0; k<this->x.size(); ++k) {
492         stream << "  " << str(der(this->x[k])) << " == " << str(this->ode[k]) << endl;
493       }
494     }
495 
496     if (!this->alg.empty()) {
497       stream << "Algebraic equations" << endl;
498       for (casadi_int k=0; k<this->z.size(); ++k) {
499         stream << "  0 == " << str(this->alg[k]) << endl;
500       }
501     }
502 
503     if (!this->q.empty()) {
504       stream << "Quadrature equations" << endl;
505       for (casadi_int k=0; k<this->q.size(); ++k) {
506         stream << "  " << str(der(this->q[k])) << " == " << str(this->quad[k]) << endl;
507       }
508     }
509 
510     if (!this->init.empty()) {
511       stream << "Initial equations" << endl;
512       for (casadi_int k=0; k<this->init.size(); ++k) {
513         stream << "  0 == " << str(this->init[k]) << endl;
514       }
515     }
516 
517     if (!this->y.empty()) {
518       stream << "Output variables" << endl;
519       for (casadi_int i=0; i<this->y.size(); ++i) {
520         stream << "  " << str(this->y[i]) << " == " << str(this->ydef[i]) << endl;
521       }
522     }
523   }
524 
eliminate_quad()525   void DaeBuilder::eliminate_quad() {
526     // Move all the quadratures to the list of differential states
527     this->x.insert(this->x.end(), this->q.begin(), this->q.end());
528     this->q.clear();
529   }
530 
scale_variables()531   void DaeBuilder::scale_variables() {
532     // Assert correctness
533     sanity_check();
534 
535     // Gather variables and expressions to replace
536     vector<MX> v_id, v_rep;
537     for (VarMap::iterator it=varmap_.begin(); it!=varmap_.end(); ++it) {
538       if (it->second.nominal!=1) {
539         Variable& v=it->second;
540         casadi_assert_dev(v.nominal!=0);
541         v.min /= v.nominal;
542         v.max /= v.nominal;
543         v.start /= v.nominal;
544         v.derivative_start /= v.nominal;
545         v.guess /= v.nominal;
546         v_id.push_back(v.v);
547         v_id.push_back(v.d);
548         v_rep.push_back(v.v * v.nominal);
549         v_rep.push_back(v.d * v.nominal);
550       }
551     }
552 
553     // Quick return if no expressions to substitute
554     if (v_id.empty()) return;
555 
556     // Collect all expressions to be replaced
557     vector<MX> ex;
558     ex.insert(ex.end(), this->ode.begin(), this->ode.end());
559     ex.insert(ex.end(), this->dae.begin(), this->dae.end());
560     ex.insert(ex.end(), this->alg.begin(), this->alg.end());
561     ex.insert(ex.end(), this->quad.begin(), this->quad.end());
562     ex.insert(ex.end(), this->ddef.begin(), this->ddef.end());
563     ex.insert(ex.end(), this->ydef.begin(), this->ydef.end());
564     ex.insert(ex.end(), this->init.begin(), this->init.end());
565 
566     // Substitute all at once (more efficient since they may have common subexpressions)
567     ex = substitute(ex, v_id, v_rep);
568 
569     // Get the modified expressions
570     vector<MX>::const_iterator it=ex.begin();
571     for (casadi_int i=0; i<this->x.size(); ++i) this->ode[i] = *it++ / nominal(this->x[i]);
572     for (casadi_int i=0; i<this->s.size(); ++i) this->dae[i] = *it++;
573     for (casadi_int i=0; i<this->z.size(); ++i) this->alg[i] = *it++;
574     for (casadi_int i=0; i<this->q.size(); ++i) this->quad[i] = *it++ / nominal(this->q[i]);
575     for (casadi_int i=0; i<this->d.size(); ++i) this->ddef[i] = *it++ / nominal(this->d[i]);
576     for (casadi_int i=0; i<this->y.size(); ++i) this->ydef[i] = *it++ / nominal(this->y[i]);
577     for (casadi_int i=0; i<this->init.size(); ++i) this->init[i] = *it++;
578     casadi_assert_dev(it==ex.end());
579 
580     // Nominal value is 1 after scaling
581     for (VarMap::iterator it=varmap_.begin(); it!=varmap_.end(); ++it) {
582       it->second.nominal=1;
583     }
584   }
585 
sort_d()586   void DaeBuilder::sort_d() {
587     // Quick return if no intermediates
588     if (this->d.empty()) return;
589 
590     // Find out which intermediates depends on which other
591     Function f("tmp", {vertcat(this->d)}, {vertcat(this->d) - vertcat(this->ddef)});
592     Sparsity sp = f.sparsity_jac(0, 0);
593     casadi_assert_dev(sp.is_square());
594 
595     // BLT transformation
596     vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
597     sp.btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
598 
599     // Resort equations and variables
600     vector<MX> ddefnew(this->d.size()), dnew(this->d.size());
601     for (casadi_int i=0; i<colperm.size(); ++i) {
602       // Permute equations
603       ddefnew[i] = this->ddef[colperm[i]];
604 
605       // Permute variables
606       dnew[i] = this->d[colperm[i]];
607     }
608     this->ddef = ddefnew;
609     this->d = dnew;
610   }
611 
split_d()612   void DaeBuilder::split_d() {
613     // Quick return if no intermediates
614     if (this->d.empty()) return;
615 
616     // Begin by sorting the dependent parameters
617     sort_d();
618 
619     // Sort the equations by causality
620     vector<MX> ex;
621     substitute_inplace(this->d, this->ddef, ex);
622 
623     // Make sure that the interdependencies have been properly eliminated
624     casadi_assert_dev(!depends_on(vertcat(this->ddef), vertcat(this->d)));
625   }
626 
eliminate_d()627   void DaeBuilder::eliminate_d() {
628     // Quick return if possible
629     if (this->d.empty()) return;
630 
631     // Begin by sorting the dependent parameters
632     sort_d();
633 
634     // Collect all expressions to be replaced
635     vector<MX> ex;
636     ex.insert(ex.end(), this->ode.begin(), this->ode.end());
637     ex.insert(ex.end(), this->dae.begin(), this->dae.end());
638     ex.insert(ex.end(), this->alg.begin(), this->alg.end());
639     ex.insert(ex.end(), this->quad.begin(), this->quad.end());
640     ex.insert(ex.end(), this->ydef.begin(), this->ydef.end());
641     ex.insert(ex.end(), this->init.begin(), this->init.end());
642 
643     // Substitute all at once (since they may have common subexpressions)
644     substitute_inplace(this->d, this->ddef, ex);
645 
646     // Get the modified expressions
647     vector<MX>::const_iterator it=ex.begin();
648     for (casadi_int i=0; i<this->x.size(); ++i) this->ode[i] = *it++;
649     for (casadi_int i=0; i<this->s.size(); ++i) this->dae[i] = *it++;
650     for (casadi_int i=0; i<this->z.size(); ++i) this->alg[i] = *it++;
651     for (casadi_int i=0; i<this->q.size(); ++i) this->quad[i] = *it++;
652     for (casadi_int i=0; i<this->y.size(); ++i) this->ydef[i] = *it++;
653     for (casadi_int i=0; i<this->init.size(); ++i) this->init[i] = *it++;
654     casadi_assert_dev(it==ex.end());
655   }
656 
scale_equations()657   void DaeBuilder::scale_equations() {
658     casadi_error("DaeBuilder::scale_equations broken");
659   }
660 
sort_dae()661   void DaeBuilder::sort_dae() {
662     // Quick return if no differential states
663     if (this->x.empty()) return;
664 
665     // Find out which differential equation depends on which differential state
666     Function f("tmp", {vertcat(this->sdot)}, {vertcat(this->dae)});
667     Sparsity sp = f.sparsity_jac(0, 0);
668     casadi_assert_dev(sp.is_square());
669 
670     // BLT transformation
671     vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
672     sp.btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
673 
674     // Resort equations and variables
675     vector<MX> daenew(this->s.size()), snew(this->s.size()), sdotnew(this->s.size());
676     for (casadi_int i=0; i<rowperm.size(); ++i) {
677       // Permute equations
678       daenew[i] = this->dae[rowperm[i]];
679 
680       // Permute variables
681       snew[i] = this->s[colperm[i]];
682       sdotnew[i] = this->sdot[colperm[i]];
683     }
684     this->dae = daenew;
685     this->s = snew;
686     this->sdot = sdotnew;
687   }
688 
sort_alg()689   void DaeBuilder::sort_alg() {
690     // Quick return if no algebraic states
691     if (this->z.empty()) return;
692 
693     // Find out which algebraic equation depends on which algebraic state
694     Function f("tmp", {vertcat(this->z)}, {vertcat(this->alg)});
695     Sparsity sp = f.sparsity_jac(0, 0);
696     casadi_assert_dev(sp.is_square());
697 
698     // BLT transformation
699     vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
700     sp.btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
701 
702     // Resort equations and variables
703     vector<MX> algnew(this->z.size()), znew(this->z.size());
704     for (casadi_int i=0; i<rowperm.size(); ++i) {
705       // Permute equations
706       algnew[i] = this->alg[rowperm[i]];
707 
708       // Permute variables
709       znew[i] = this->z[colperm[i]];
710     }
711     this->alg = algnew;
712     this->z = znew;
713   }
714 
make_semi_explicit()715   void DaeBuilder::make_semi_explicit() {
716     // Only works if there are no i
717     eliminate_d();
718 
719     // Separate the algebraic variables and equations
720     split_dae();
721 
722     // Quick return if there are no implicitly defined states
723     if (this->s.empty()) return;
724 
725     // Write the ODE as a function of the state derivatives
726     Function f("tmp", {vertcat(this->sdot)}, {vertcat(this->dae)});
727 
728     // Get the sparsity of the Jacobian which can be used to determine which
729     // variable can be calculated from which other
730     Sparsity sp = f.sparsity_jac(0, 0);
731     casadi_assert_dev(sp.is_square());
732 
733     // BLT transformation
734     vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
735     casadi_int nb = sp.btf(rowperm, colperm, rowblock, colblock,
736                                   coarse_rowblock, coarse_colblock);
737 
738     // Resort equations and variables
739     vector<MX> daenew(this->s.size()), snew(this->s.size()), sdotnew(this->s.size());
740     for (casadi_int i=0; i<rowperm.size(); ++i) {
741       // Permute equations
742       daenew[i] = this->dae[rowperm[i]];
743 
744       // Permute variables
745       snew[i] = this->s[colperm[i]];
746       sdotnew[i] = this->sdot[colperm[i]];
747     }
748     this->dae = daenew;
749     this->s = snew;
750     this->sdot = sdotnew;
751 
752     // Differentiate to write the sorted ODE as a function of state derivatives
753     MX J = jacobian(vertcat(this->dae), vertcat(this->sdot));
754 
755     // Explicit ODE
756     vector<MX> new_ode;
757 
758     // Loop over blocks
759     for (casadi_int b=0; b<nb; ++b) {
760 
761       // Get variables in the block
762       vector<MX> xb(this->s.begin()+colblock[b], this->s.begin()+colblock[b+1]);
763       vector<MX> xdotb(this->sdot.begin()+colblock[b], this->sdot.begin()+colblock[b+1]);
764 
765       // Get equations in the block
766       vector<MX> fb(this->dae.begin()+rowblock[b], this->dae.begin()+rowblock[b+1]);
767 
768       // Get local Jacobian
769       MX Jb = J(Slice(rowblock[b], rowblock[b+1]), Slice(colblock[b], colblock[b+1])); // NOLINT
770 
771       // If Jb depends on xb, then the state derivative does not enter linearly
772       // in the ODE and we cannot solve for the state derivative
773       casadi_assert(!depends_on(Jb, vertcat(xdotb)),
774         "Cannot find an explicit expression for variable(s) " + str(xb));
775 
776       // Divide fb into a part which depends on vb and a part which doesn't according to
777       // "fb == mul(Jb, vb) + fb_res"
778       vector<MX> fb_res = substitute(fb, xdotb, vector<MX>(xdotb.size(), 0));
779 
780       // Solve for vb
781       vector<MX> fb_exp = vertsplit(solve(Jb, -vertcat(fb_res)));
782 
783       // Add to explicitly determined equations and variables
784       new_ode.insert(new_ode.end(), fb_exp.begin(), fb_exp.end());
785     }
786 
787     // Eliminate inter-dependencies
788     vector<MX> ex;
789     substitute_inplace(this->sdot, new_ode, ex, false);
790 
791     // Add to explicit differential states and ODE
792     this->x.insert(this->x.end(), this->s.begin(), this->s.end());
793     this->ode.insert(this->ode.end(), new_ode.begin(), new_ode.end());
794     this->dae.clear();
795     this->s.clear();
796     this->sdot.clear();
797   }
798 
eliminate_alg()799   void DaeBuilder::eliminate_alg() {
800     // Only works if there are no i
801     eliminate_d();
802 
803     // Quick return if there are no algebraic states
804     if (this->z.empty()) return;
805 
806     // Write the algebraic equations as a function of the algebraic states
807     Function f("f", {vertcat(this->z)}, {vertcat(this->alg)});
808 
809     // Get the sparsity of the Jacobian which can be used to determine which
810     // variable can be calculated from which other
811     Sparsity sp = f.sparsity_jac(0, 0);
812     casadi_assert_dev(sp.is_square());
813 
814     // BLT transformation
815     vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
816     casadi_int nb = sp.btf(rowperm, colperm, rowblock, colblock,
817                                   coarse_rowblock, coarse_colblock);
818 
819     // Resort equations and variables
820     vector<MX> algnew(this->z.size()), znew(this->z.size());
821     for (casadi_int i=0; i<rowperm.size(); ++i) {
822       // Permute equations
823       algnew[i] = this->alg[rowperm[i]];
824 
825       // Permute variables
826       znew[i] = this->z[colperm[i]];
827     }
828     this->alg = algnew;
829     this->z = znew;
830 
831     // Rewrite the sorted algebraic equations as a function of the algebraic states
832     f = Function("f", {vertcat(this->z)}, {vertcat(this->alg)});
833 
834     // Variables where we have found an explicit expression and where we haven't
835     vector<MX> z_exp, z_imp;
836 
837     // Explicit and implicit equations
838     vector<MX> f_exp, f_imp;
839 
840     // Loop over blocks
841     for (casadi_int b=0; b<nb; ++b) {
842 
843       // Get local variables
844       vector<MX> zb(this->z.begin()+colblock[b], this->z.begin()+colblock[b+1]);
845 
846       // Get local equations
847       vector<MX> fb(this->alg.begin()+rowblock[b], this->alg.begin()+rowblock[b+1]);
848 
849       // Get local Jacobian
850       MX Jb = jacobian(vertcat(fb), vertcat(zb));
851 
852       // If Jb depends on zb, then we cannot (currently) solve for it explicitly
853       if (depends_on(Jb, vertcat(zb))) {
854 
855         // Add the equations to the new list of algebraic equations
856         f_imp.insert(f_imp.end(), fb.begin(), fb.end());
857 
858         // ... and the variables accordingly
859         z_imp.insert(z_imp.end(), zb.begin(), zb.end());
860 
861       } else { // The variables that we wish to determine enter linearly
862 
863         // Divide fb into a part which depends on vb and a part which doesn't
864         // according to "fb == mul(Jb, vb) + fb_res"
865         vector<MX> fb_res = substitute(fb, zb, vector<MX>(zb.size(), 0));
866 
867         // Solve for vb
868         vector<MX> fb_exp = vertsplit(solve(Jb, -vertcat(fb_res)));
869 
870         // Add to explicitly determined equations and variables
871         z_exp.insert(z_exp.end(), zb.begin(), zb.end());
872         f_exp.insert(f_exp.end(), fb_exp.begin(), fb_exp.end());
873       }
874     }
875 
876     // Eliminate inter-dependencies in fb_exp
877     vector<MX> ex;
878     substitute_inplace(z_exp, f_exp, ex, false);
879 
880     // Add to the beginning of the dependent variables
881     // (since the other dependent variable might depend on them)
882     this->d.insert(this->d.begin(), z_exp.begin(), z_exp.end());
883     this->ddef.insert(this->ddef.begin(), f_exp.begin(), f_exp.end());
884 
885     // Save new algebraic equations
886     this->z = z_imp;
887     this->alg = f_imp;
888 
889     // Eliminate new dependent variables from the other equations
890     eliminate_d();
891   }
892 
make_explicit()893   void DaeBuilder::make_explicit() {
894     // Only works if there are no i
895     eliminate_d();
896 
897     // Start by transforming to semi-explicit form
898     make_semi_explicit();
899 
900     // Then eliminate the algebraic variables
901     eliminate_alg();
902 
903     // Error if still algebraic variables
904     casadi_assert(this->z.empty(), "Failed to eliminate algebraic variables");
905   }
906 
variable(const std::string & name) const907   const Variable& DaeBuilder::variable(const std::string& name) const {
908     return const_cast<DaeBuilder*>(this)->variable(name);
909   }
910 
variable(const std::string & name)911   Variable& DaeBuilder::variable(const std::string& name) {
912     // Find the variable
913     VarMap::iterator it = varmap_.find(name);
914     if (it==varmap_.end()) {
915       casadi_error("No such variable: \"" + name + "\".");
916     }
917 
918     // Return the variable
919     return it->second;
920   }
921 
add_variable(const std::string & name,const Variable & var)922   void DaeBuilder::add_variable(const std::string& name, const Variable& var) {
923     // Try to find the component
924     if (varmap_.find(name)!=varmap_.end()) {
925       stringstream ss;
926       casadi_error("Variable \"" + name + "\" has already been added.");
927     }
928 
929     // Add to the map of all variables
930     varmap_[name] = var;
931   }
932 
add_variable(const std::string & name,casadi_int n)933   MX DaeBuilder::add_variable(const std::string& name, casadi_int n) {
934     return add_variable(name, Sparsity::dense(n));
935   }
936 
add_variable(const std::string & name,const Sparsity & sp)937   MX DaeBuilder::add_variable(const std::string& name, const Sparsity& sp) {
938     Variable v(name, sp);
939     add_variable(name, v);
940     return v.v;
941   }
942 
add_x(const std::string & name,casadi_int n)943   MX DaeBuilder::add_x(const std::string& name, casadi_int n) {
944     if (name.empty()) return add_x("x" + str(this->x.size()), n);
945     MX new_x = add_variable(name, n);
946     this->x.push_back(new_x);
947     return new_x;
948   }
949 
add_q(const std::string & name,casadi_int n)950   MX DaeBuilder::add_q(const std::string& name, casadi_int n) {
951     if (name.empty()) return add_q("q" + str(this->q.size()), n);
952     MX new_q = add_variable(name, n);
953     this->q.push_back(new_q);
954     return new_q;
955   }
956 
add_s(const std::string & name,casadi_int n)957   std::pair<MX, MX> DaeBuilder::add_s(const std::string& name, casadi_int n) {
958     if (name.empty()) return add_s("s" + str(this->s.size()), n);
959     Variable v(name, Sparsity::dense(n));
960     add_variable(name, v);
961     this->s.push_back(v.v);
962     this->sdot.push_back(v.d);
963     return std::pair<MX, MX>(v.v, v.d);
964   }
965 
add_z(const std::string & name,casadi_int n)966   MX DaeBuilder::add_z(const std::string& name, casadi_int n) {
967     if (name.empty()) return add_z("z" + str(this->z.size()), n);
968     MX new_z = add_variable(name, n);
969     this->z.push_back(new_z);
970     return new_z;
971   }
972 
add_p(const std::string & name,casadi_int n)973   MX DaeBuilder::add_p(const std::string& name, casadi_int n) {
974     if (name.empty()) return add_p("p" + str(this->p.size()), n);
975     MX new_p = add_variable(name, n);
976     this->p.push_back(new_p);
977     return new_p;
978   }
979 
add_u(const std::string & name,casadi_int n)980   MX DaeBuilder::add_u(const std::string& name, casadi_int n) {
981     if (name.empty()) return add_u("u" + str(this->u.size()), n);
982     MX new_u = add_variable(name, n);
983     this->u.push_back(new_u);
984     return new_u;
985   }
986 
add_aux(const std::string & name,casadi_int n)987   MX DaeBuilder::add_aux(const std::string& name, casadi_int n) {
988     if (name.empty()) return add_aux("aux" + str(this->aux.size()), n);
989     MX new_aux = add_variable(name, n);
990     this->aux.push_back(new_aux);
991     return new_aux;
992   }
993 
add_d(const std::string & name,const MX & new_ddef)994   MX DaeBuilder::add_d(const std::string& name, const MX& new_ddef) {
995     MX new_d = add_variable(name, new_ddef.sparsity());
996     this->d.push_back(new_d);
997     this->ddef.push_back(new_ddef);
998     this->lam_ddef.push_back(MX::sym("lam_" + name, new_ddef.sparsity()));
999     return new_d;
1000   }
1001 
add_y(const std::string & name,const MX & new_ydef)1002   MX DaeBuilder::add_y(const std::string& name, const MX& new_ydef) {
1003     MX new_y = add_variable(name, new_ydef.sparsity());
1004     this->y.push_back(new_y);
1005     this->ydef.push_back(new_ydef);
1006     this->lam_ydef.push_back(MX::sym("lam_" + name, new_ydef.sparsity()));
1007     return new_y;
1008   }
1009 
add_ode(const std::string & name,const MX & new_ode)1010   void DaeBuilder::add_ode(const std::string& name, const MX& new_ode) {
1011     this->ode.push_back(new_ode);
1012     this->lam_ode.push_back(MX::sym("lam_" + name, new_ode.sparsity()));
1013   }
1014 
add_dae(const std::string & name,const MX & new_dae)1015   void DaeBuilder::add_dae(const std::string& name, const MX& new_dae) {
1016     this->dae.push_back(new_dae);
1017     this->lam_dae.push_back(MX::sym("lam_" + name, new_dae.sparsity()));
1018   }
1019 
add_alg(const std::string & name,const MX & new_alg)1020   void DaeBuilder::add_alg(const std::string& name, const MX& new_alg) {
1021     this->alg.push_back(new_alg);
1022     this->lam_alg.push_back(MX::sym("lam_" + name, new_alg.sparsity()));
1023   }
1024 
add_quad(const std::string & name,const MX & new_quad)1025   void DaeBuilder::add_quad(const std::string& name, const MX& new_quad) {
1026     this->quad.push_back(new_quad);
1027     this->lam_quad.push_back(MX::sym("lam_" + name, new_quad.sparsity()));
1028   }
1029 
sanity_check() const1030   void DaeBuilder::sanity_check() const {
1031     // Time
1032     casadi_assert(this->t.is_symbolic(), "Non-symbolic time t");
1033     casadi_assert(this->t.is_scalar(), "Non-scalar time t");
1034 
1035     // Differential states
1036     casadi_assert(this->x.size()==this->ode.size(),
1037                           "x and ode have different lengths");
1038     for (casadi_int i=0; i<this->x.size(); ++i) {
1039       casadi_assert(this->x[i].size()==this->ode[i].size(),
1040                             "ode has wrong dimensions");
1041       casadi_assert(this->x[i].is_symbolic(), "Non-symbolic state x");
1042     }
1043 
1044     // DAE
1045     casadi_assert(this->s.size()==this->sdot.size(),
1046                           "s and sdot have different lengths");
1047     casadi_assert(this->s.size()==this->dae.size(),
1048                           "s and dae have different lengths");
1049     for (casadi_int i=0; i<this->s.size(); ++i) {
1050       casadi_assert(this->s[i].is_symbolic(), "Non-symbolic state s");
1051       casadi_assert(this->s[i].size()==this->sdot[i].size(),
1052                             "sdot has wrong dimensions");
1053       casadi_assert(this->s[i].size()==this->dae[i].size(),
1054                             "dae has wrong dimensions");
1055     }
1056 
1057     // Algebraic variables/equations
1058     casadi_assert(this->z.size()==this->alg.size(),
1059                           "z and alg have different lengths");
1060     for (casadi_int i=0; i<this->z.size(); ++i) {
1061       casadi_assert(this->z[i].is_symbolic(), "Non-symbolic algebraic variable z");
1062       casadi_assert(this->z[i].size()==this->alg[i].size(),
1063                             "alg has wrong dimensions");
1064     }
1065 
1066     // Quadrature states/equations
1067     casadi_assert(this->q.size()==this->quad.size(),
1068                           "q and quad have different lengths");
1069     for (casadi_int i=0; i<this->q.size(); ++i) {
1070       casadi_assert(this->q[i].is_symbolic(), "Non-symbolic quadrature state q");
1071       casadi_assert(this->q[i].size()==this->quad[i].size(),
1072                             "quad has wrong dimensions");
1073     }
1074 
1075     // Intermediate variables
1076     casadi_assert(this->d.size()==this->ddef.size(),
1077                           "d and ddef have different lengths");
1078     for (casadi_int i=0; i<this->d.size(); ++i) {
1079       casadi_assert(this->d[i].is_symbolic(), "Non-symbolic dependent parameter d");
1080       casadi_assert(this->d[i].size()==this->ddef[i].size(),
1081                             "ddef has wrong dimensions");
1082     }
1083 
1084     // Output equations
1085     casadi_assert(this->y.size()==this->ydef.size(),
1086                           "y and ydef have different lengths");
1087     for (casadi_int i=0; i<this->y.size(); ++i) {
1088       casadi_assert(this->y[i].is_symbolic(), "Non-symbolic output y");
1089       casadi_assert(this->y[i].size()==this->ydef[i].size(),
1090                             "ydef has wrong dimensions");
1091     }
1092 
1093     // Control
1094     for (casadi_int i=0; i<this->u.size(); ++i) {
1095       casadi_assert(this->u[i].is_symbolic(), "Non-symbolic control u");
1096     }
1097 
1098     // Parameter
1099     for (casadi_int i=0; i<this->p.size(); ++i) {
1100       casadi_assert(this->p[i].is_symbolic(), "Non-symbolic parameter p");
1101     }
1102   }
1103 
qualified_name(const XmlNode & nn)1104   std::string DaeBuilder::qualified_name(const XmlNode& nn) {
1105     // Stringstream to assemble name
1106     stringstream qn;
1107 
1108     for (casadi_int i=0; i<nn.size(); ++i) {
1109       // Add a dot
1110       if (i!=0) qn << ".";
1111 
1112       // Get the name part
1113       qn << nn[i].getAttribute("name");
1114 
1115       // Get the index, if any
1116       if (nn[i].size()>0) {
1117         casadi_int ind;
1118         nn[i]["exp:ArraySubscripts"]["exp:IndexExpression"]["exp:IntegerLiteral"].getText(ind);
1119         qn << "[" << ind << "]";
1120       }
1121     }
1122 
1123     // Return the name
1124     return qn.str();
1125   }
1126 
var(const std::string & name) const1127   MX DaeBuilder::var(const std::string& name) const {
1128     return variable(name).v;
1129   }
1130 
der(const std::string & name) const1131   MX DaeBuilder::der(const std::string& name) const {
1132     return variable(name).d;
1133   }
1134 
der(const MX & var) const1135   MX DaeBuilder::der(const MX& var) const {
1136     casadi_assert_dev(var.is_column() && var.is_symbolic());
1137     MX ret = MX::zeros(var.sparsity());
1138     for (casadi_int i=0; i<ret.nnz(); ++i) {
1139       ret.nz(i) = der(var.nz(i).name());
1140     }
1141     return ret;
1142   }
1143 
split_dae()1144   void DaeBuilder::split_dae() {
1145     // Only works if there are no d
1146     eliminate_d();
1147 
1148     // Quick return if no s
1149     if (this->s.empty()) return;
1150 
1151     // We investigate the interdependencies in sdot -> dae
1152     Function f("f", {vertcat(this->sdot)}, {vertcat(this->dae)});
1153 
1154     // Number of s
1155     casadi_int ns = f.nnz_in(0);
1156     casadi_assert_dev(f.nnz_out(0)==ns);
1157 
1158     // Input/output buffers
1159     vector<bvec_t> f_sdot(ns, 1);
1160     vector<bvec_t> f_dae(ns, 0);
1161 
1162     // Propagate to f_dae
1163     f({get_ptr(f_sdot)}, {get_ptr(f_dae)});
1164 
1165     // Get the new differential and algebraic equations
1166     vector<MX> new_dae, new_alg;
1167     for (casadi_int i=0; i<ns; ++i) {
1168       if (f_dae[i]==bvec_t(1)) {
1169         new_dae.push_back(this->dae[i]);
1170       } else {
1171         casadi_assert_dev(f_dae[i]==bvec_t(0));
1172         new_alg.push_back(this->dae[i]);
1173       }
1174     }
1175 
1176     // Seed all outputs
1177     std::fill(f_dae.begin(), f_dae.end(), 1);
1178 
1179     // Propagate to f_sdot
1180     std::fill(f_sdot.begin(), f_sdot.end(), 0);
1181     f.rev({get_ptr(f_sdot)}, {get_ptr(f_dae)});
1182 
1183     // Get the new algebraic variables and new states
1184     vector<MX> new_s, new_sdot, new_z;
1185     for (casadi_int i=0; i<ns; ++i) {
1186       if (f_sdot[i]==bvec_t(1)) {
1187         new_s.push_back(this->s[i]);
1188         new_sdot.push_back(this->sdot[i]);
1189       } else {
1190         casadi_assert_dev(f_sdot[i]==bvec_t(0));
1191         new_z.push_back(this->s[i]);
1192       }
1193     }
1194 
1195     // Make sure split was successful
1196     casadi_assert_dev(new_dae.size()==new_s.size());
1197 
1198     // Divide up the s and dae
1199     this->dae = new_dae;
1200     this->s = new_s;
1201     this->sdot = new_sdot;
1202     this->alg.insert(this->alg.end(), new_alg.begin(), new_alg.end());
1203     this->z.insert(this->z.end(), new_z.begin(), new_z.end());
1204   }
1205 
unit(const std::string & name) const1206   std::string DaeBuilder::unit(const std::string& name) const {
1207     return variable(name).unit;
1208   }
1209 
unit(const MX & var) const1210   std::string DaeBuilder::unit(const MX& var) const {
1211     casadi_assert(!var.is_column() && var.is_valid_input(),
1212                           "DaeBuilder::unit: Argument must be a symbolic vector");
1213     if (var.is_empty()) {
1214       return "n/a";
1215     } else {
1216       std::vector<MX> prim = var.primitives();
1217       string ret = unit(prim.at(0).name());
1218       for (casadi_int i=1; i<prim.size(); ++i) {
1219         casadi_assert(ret == unit(prim.at(i).name()),
1220                               "DaeBuilder::unit: Argument has mixed units");
1221       }
1222       return ret;
1223     }
1224   }
1225 
set_unit(const std::string & name,const std::string & val)1226   void DaeBuilder::set_unit(const std::string& name, const std::string& val) {
1227     variable(name).unit = val;
1228   }
1229 
nominal(const std::string & name) const1230   double DaeBuilder::nominal(const std::string& name) const {
1231     return variable(name).nominal;
1232   }
1233 
set_nominal(const std::string & name,double val)1234   void DaeBuilder::set_nominal(const std::string& name, double val) {
1235     variable(name).nominal = val;
1236   }
1237 
nominal(const MX & var) const1238   std::vector<double> DaeBuilder::nominal(const MX& var) const {
1239     casadi_assert(var.is_column() && var.is_valid_input(),
1240                           "DaeBuilder::nominal: Argument must be a symbolic vector");
1241     std::vector<double> ret(var.nnz());
1242     std::vector<MX> prim = var.primitives();
1243     for (casadi_int i=0; i<prim.size(); ++i) {
1244       casadi_assert_dev(prim[i].nnz()==1);
1245       ret[i] = nominal(prim.at(i).name());
1246     }
1247     return ret;
1248   }
1249 
set_nominal(const MX & var,const std::vector<double> & val)1250   void DaeBuilder::set_nominal(const MX& var, const std::vector<double>& val) {
1251     casadi_assert(var.is_column() && var.is_valid_input(),
1252                           "DaeBuilder::nominal: Argument must be a symbolic vector");
1253     casadi_assert(var.nnz()==var.nnz(), "DaeBuilder::nominal: Dimension mismatch");
1254     std::vector<MX> prim = var.primitives();
1255     for (casadi_int i=0; i<prim.size(); ++i) {
1256       casadi_assert_dev(prim[i].nnz()==1);
1257       set_nominal(prim.at(i).name(), val.at(i));
1258     }
1259   }
1260 
attribute(getAtt f,const MX & var,bool normalized) const1261   std::vector<double> DaeBuilder::attribute(getAtt f, const MX& var, bool normalized) const {
1262     casadi_assert(var.is_column() && var.is_valid_input(),
1263                           "DaeBuilder::attribute: Argument must be a symbolic vector");
1264     std::vector<double> ret(var.nnz());
1265     std::vector<MX> prim = var.primitives();
1266     for (casadi_int i=0; i<prim.size(); ++i) {
1267       casadi_assert_dev(prim[i].nnz()==1);
1268       ret[i] = (this->*f)(prim[i].name(), normalized);
1269     }
1270     return ret;
1271   }
1272 
attribute(getAttS f,const MX & var) const1273   MX DaeBuilder::attribute(getAttS f, const MX& var) const {
1274     casadi_assert(var.is_column() && var.is_valid_input(),
1275                           "DaeBuilder::attribute: Argument must be a symbolic vector");
1276     MX ret = MX::zeros(var.sparsity());
1277     std::vector<MX> prim = var.primitives();
1278     for (casadi_int i=0; i<prim.size(); ++i) {
1279       casadi_assert_dev(prim[i].nnz()==1);
1280       ret.nz(i) = (this->*f)(prim[i].name());
1281     }
1282     return ret;
1283   }
1284 
set_attribute(setAtt f,const MX & var,const std::vector<double> & val,bool normalized)1285   void DaeBuilder::set_attribute(setAtt f, const MX& var, const std::vector<double>& val,
1286                                  bool normalized) {
1287     casadi_assert(var.is_column() && var.is_valid_input(),
1288                           "DaeBuilder::set_attribute: Argument must be a symbolic vector");
1289     casadi_assert(var.nnz()==val.size(), "DaeBuilder::set_attribute: Dimension mismatch");
1290     std::vector<MX> prim = var.primitives();
1291     for (casadi_int i=0; i<prim.size(); ++i) {
1292       casadi_assert_dev(prim[i].nnz()==1);
1293       (this->*f)(prim[i].name(), val[i], normalized);
1294     }
1295   }
1296 
set_attribute(setAttS f,const MX & var,const MX & val)1297   void DaeBuilder::set_attribute(setAttS f, const MX& var, const MX& val) {
1298     casadi_assert(var.is_column() && var.is_valid_input(),
1299                           "DaeBuilder::set_attribute: Argument must be a symbolic vector");
1300     casadi_assert(var.sparsity()==val.sparsity(),
1301                           "DaeBuilder::set_attribute: Sparsity mismatch");
1302     std::vector<MX> prim = var.primitives();
1303     for (casadi_int i=0; i<prim.size(); ++i) {
1304       casadi_assert_dev(prim[i].nnz()==1);
1305       (this->*f)(var.nz(i).name(), val.nz(i));
1306     }
1307   }
1308 
min(const std::string & name,bool normalized) const1309   double DaeBuilder::min(const std::string& name, bool normalized) const {
1310     const Variable& v = variable(name);
1311     return normalized ? v.min / v.nominal : v.min;
1312   }
1313 
min(const MX & var,bool normalized) const1314   std::vector<double> DaeBuilder::min(const MX& var, bool normalized) const {
1315     return attribute(&DaeBuilder::min, var, normalized);
1316   }
1317 
set_min(const std::string & name,double val,bool normalized)1318   void DaeBuilder::set_min(const std::string& name, double val, bool normalized) {
1319     Variable& v = variable(name);
1320     v.min = normalized ? val*v.nominal : val;
1321   }
1322 
set_min(const MX & var,const std::vector<double> & val,bool normalized)1323   void DaeBuilder::set_min(const MX& var, const std::vector<double>& val, bool normalized) {
1324     set_attribute(&DaeBuilder::set_min, var, val, normalized);
1325   }
1326 
max(const std::string & name,bool normalized) const1327   double DaeBuilder::max(const std::string& name, bool normalized) const {
1328     const Variable& v = variable(name);
1329     return normalized ? v.max / v.nominal : v.max;
1330   }
1331 
max(const MX & var,bool normalized) const1332   std::vector<double> DaeBuilder::max(const MX& var, bool normalized) const {
1333     return attribute(&DaeBuilder::max, var, normalized);
1334   }
1335 
set_max(const std::string & name,double val,bool normalized)1336   void DaeBuilder::set_max(const std::string& name, double val, bool normalized) {
1337     Variable& v = variable(name);
1338     v.max = normalized ? val*v.nominal : val;
1339   }
1340 
set_max(const MX & var,const std::vector<double> & val,bool normalized)1341   void DaeBuilder::set_max(const MX& var, const std::vector<double>& val, bool normalized) {
1342     set_attribute(&DaeBuilder::set_max, var, val, normalized);
1343   }
1344 
guess(const std::string & name,bool normalized) const1345   double DaeBuilder::guess(const std::string& name, bool normalized) const {
1346     const Variable& v = variable(name);
1347     return normalized ? v.guess / v.nominal : v.guess;
1348   }
1349 
guess(const MX & var,bool normalized) const1350   std::vector<double> DaeBuilder::guess(const MX& var, bool normalized) const {
1351     return attribute(&DaeBuilder::guess, var, normalized);
1352   }
1353 
set_guess(const std::string & name,double val,bool normalized)1354   void DaeBuilder::set_guess(const std::string& name, double val, bool normalized) {
1355     Variable& v = variable(name);
1356     v.guess = normalized ? val*v.nominal : val;
1357   }
1358 
set_guess(const MX & var,const std::vector<double> & val,bool normalized)1359   void DaeBuilder::set_guess(const MX& var, const std::vector<double>& val,
1360                                     bool normalized) {
1361     set_attribute(&DaeBuilder::set_guess, var, val, normalized);
1362   }
1363 
start(const std::string & name,bool normalized) const1364   double DaeBuilder::start(const std::string& name, bool normalized) const {
1365     const Variable& v = variable(name);
1366     return normalized ? v.start / v.nominal : v.start;
1367   }
1368 
start(const MX & var,bool normalized) const1369   std::vector<double> DaeBuilder::start(const MX& var, bool normalized) const {
1370     return attribute(&DaeBuilder::start, var, normalized);
1371   }
1372 
set_start(const std::string & name,double val,bool normalized)1373   void DaeBuilder::set_start(const std::string& name, double val, bool normalized) {
1374     Variable& v = variable(name);
1375     v.start = normalized ? val*v.nominal : val;
1376   }
1377 
set_start(const MX & var,const std::vector<double> & val,bool normalized)1378   void DaeBuilder::set_start(const MX& var, const std::vector<double>& val, bool normalized) {
1379     set_attribute(&DaeBuilder::set_start, var, val, normalized);
1380   }
1381 
derivative_start(const std::string & name,bool normalized) const1382   double DaeBuilder::derivative_start(const std::string& name, bool normalized) const {
1383     const Variable& v = variable(name);
1384     return normalized ? v.derivative_start / v.nominal : v.derivative_start;
1385   }
1386 
derivative_start(const MX & var,bool normalized) const1387   std::vector<double> DaeBuilder::derivative_start(const MX& var, bool normalized) const {
1388     return attribute(&DaeBuilder::derivative_start, var, normalized);
1389   }
1390 
set_derivative_start(const std::string & name,double val,bool normalized)1391   void DaeBuilder::set_derivative_start(const std::string& name, double val, bool normalized) {
1392     Variable& v = variable(name);
1393     v.derivative_start = normalized ? val*v.nominal : val;
1394   }
1395 
set_derivative_start(const MX & var,const std::vector<double> & val,bool normalized)1396   void DaeBuilder::set_derivative_start(const MX& var, const std::vector<double>& val,
1397                                        bool normalized) {
1398     set_attribute(&DaeBuilder::set_derivative_start, var, val, normalized);
1399   }
1400 
name_in(DaeBuilderIn ind)1401   std::string DaeBuilder::name_in(DaeBuilderIn ind) {
1402     switch (ind) {
1403     case DAE_BUILDER_T: return "t";
1404     case DAE_BUILDER_C: return "c";
1405     case DAE_BUILDER_P: return "p";
1406     case DAE_BUILDER_D: return "d";
1407     case DAE_BUILDER_U: return "u";
1408     case DAE_BUILDER_X: return "x";
1409     case DAE_BUILDER_S: return "s";
1410     case DAE_BUILDER_SDOT: return "sdot";
1411     case DAE_BUILDER_Z: return "z";
1412     case DAE_BUILDER_Q: return "q";
1413     case DAE_BUILDER_W: return "w";
1414     case DAE_BUILDER_Y: return "y";
1415     default: return "";
1416     }
1417   }
1418 
enum_in(const std::string & id)1419   DaeBuilder::DaeBuilderIn DaeBuilder::enum_in(const std::string& id) {
1420     if (id=="t") {
1421       return DAE_BUILDER_T;
1422     } else if (id=="c") {
1423       return DAE_BUILDER_C;
1424     } else if (id=="p") {
1425       return DAE_BUILDER_P;
1426     } else if (id=="d") {
1427       return DAE_BUILDER_D;
1428     } else if (id=="u") {
1429       return DAE_BUILDER_U;
1430     } else if (id=="x") {
1431       return DAE_BUILDER_X;
1432     } else if (id=="s") {
1433       return DAE_BUILDER_S;
1434     } else if (id=="sdot") {
1435       return DAE_BUILDER_SDOT;
1436     } else if (id=="z") {
1437       return DAE_BUILDER_Z;
1438     } else if (id=="q") {
1439       return DAE_BUILDER_Q;
1440     } else if (id=="w") {
1441       return DAE_BUILDER_W;
1442     } else if (id=="y") {
1443       return DAE_BUILDER_Y;
1444     } else {
1445       return DAE_BUILDER_NUM_IN;
1446     }
1447   }
1448 
1449   std::vector<DaeBuilder::DaeBuilderIn>
enum_in(const std::vector<std::string> & id)1450   DaeBuilder::enum_in(const std::vector<std::string>& id) {
1451     std::vector<DaeBuilderIn> ret(id.size());
1452     for (casadi_int i=0; i<id.size(); ++i) {
1453       ret[i] = enum_in(id[i]);
1454     }
1455     return ret;
1456   }
1457 
name_out(DaeBuilderOut ind)1458   std::string DaeBuilder::name_out(DaeBuilderOut ind) {
1459     switch (ind) {
1460     case DAE_BUILDER_DDEF: return "ddef";
1461     case DAE_BUILDER_WDEF: return "wdef";
1462     case DAE_BUILDER_ODE: return "ode";
1463     case DAE_BUILDER_DAE: return "dae";
1464     case DAE_BUILDER_ALG: return "alg";
1465     case DAE_BUILDER_QUAD: return "quad";
1466     case DAE_BUILDER_YDEF: return "ydef";
1467     default: return "";
1468     }
1469   }
1470 
enum_out(const std::string & id)1471   DaeBuilder::DaeBuilderOut DaeBuilder::enum_out(const std::string& id) {
1472     if (id=="ddef") {
1473       return DAE_BUILDER_DDEF;
1474     } else if (id=="wdef") {
1475       return DAE_BUILDER_WDEF;
1476     } else if (id=="ode") {
1477       return DAE_BUILDER_ODE;
1478     } else if (id=="dae") {
1479       return DAE_BUILDER_DAE;
1480     } else if (id=="alg") {
1481       return DAE_BUILDER_ALG;
1482     } else if (id=="quad") {
1483       return DAE_BUILDER_QUAD;
1484     } else if (id=="ydef") {
1485       return DAE_BUILDER_YDEF;
1486     } else {
1487       return DAE_BUILDER_NUM_OUT;
1488     }
1489   }
1490 
1491   std::vector<DaeBuilder::DaeBuilderOut>
enum_out(const std::vector<std::string> & id)1492   DaeBuilder::enum_out(const std::vector<std::string>& id) {
1493     std::vector<DaeBuilderOut> ret(id.size());
1494     for (casadi_int i=0; i<id.size(); ++i) {
1495       ret[i] = enum_out(id[i]);
1496     }
1497     return ret;
1498   }
1499 
name_in()1500   std::string DaeBuilder::name_in() {
1501     stringstream ss;
1502     ss << "[";
1503     for (casadi_int i=0; i!=DAE_BUILDER_NUM_IN; ++i) {
1504       if (i!=0) ss << ",";
1505       ss << name_in(static_cast<DaeBuilderIn>(i));
1506     }
1507     ss << "]";
1508     return ss.str();
1509   }
1510 
name_out()1511   std::string DaeBuilder::name_out() {
1512     stringstream ss;
1513     ss << "[";
1514     for (casadi_int i=0; i!=DAE_BUILDER_NUM_OUT; ++i) {
1515       if (i!=0) ss << ",";
1516       ss << name_out(static_cast<DaeBuilderOut>(i));
1517     }
1518     ss << "]";
1519     return ss.str();
1520   }
1521 
input(DaeBuilderIn ind) const1522   std::vector<MX> DaeBuilder::input(DaeBuilderIn ind) const {
1523     switch (ind) {
1524     case DAE_BUILDER_T: return vector<MX>(1, this->t);
1525     case DAE_BUILDER_C: return this->c;
1526     case DAE_BUILDER_P: return this->p;
1527     case DAE_BUILDER_D: return this->d;
1528     case DAE_BUILDER_U: return this->u;
1529     case DAE_BUILDER_X: return this->x;
1530     case DAE_BUILDER_S: return this->s;
1531     case DAE_BUILDER_SDOT: return this->sdot;
1532     case DAE_BUILDER_Z: return this->z;
1533     case DAE_BUILDER_Q: return this->q;
1534     case DAE_BUILDER_W: return this->w;
1535     case DAE_BUILDER_Y: return this->y;
1536     default: return std::vector<MX>();
1537     }
1538   }
1539 
input(std::vector<DaeBuilderIn> & ind) const1540   std::vector<MX> DaeBuilder::input(std::vector<DaeBuilderIn>& ind) const {
1541     vector<MX> ret(ind.size());
1542     for (casadi_int i=0; i<ind.size(); ++i) {
1543       ret[i] = vertcat(input(ind[i]));
1544     }
1545     return ret;
1546   }
1547 
output(DaeBuilderOut ind) const1548   std::vector<MX> DaeBuilder::output(DaeBuilderOut ind) const {
1549     switch (ind) {
1550     case DAE_BUILDER_DDEF: return this->ddef;
1551     case DAE_BUILDER_WDEF: return this->wdef;
1552     case DAE_BUILDER_ODE: return this->ode;
1553     case DAE_BUILDER_DAE: return this->dae;
1554     case DAE_BUILDER_ALG: return this->alg;
1555     case DAE_BUILDER_QUAD: return this->quad;
1556     case DAE_BUILDER_YDEF: return this->ydef;
1557     default: return std::vector<MX>();
1558     }
1559   }
1560 
output(std::vector<DaeBuilderOut> & ind) const1561   std::vector<MX> DaeBuilder::output(std::vector<DaeBuilderOut>& ind) const {
1562     vector<MX> ret(ind.size());
1563     for (casadi_int i=0; i<ind.size(); ++i) {
1564       ret[i] = vertcat(output(ind[i]));
1565     }
1566     return ret;
1567   }
1568 
multiplier(DaeBuilderOut ind) const1569   std::vector<MX> DaeBuilder::multiplier(DaeBuilderOut ind) const {
1570     switch (ind) {
1571     case DAE_BUILDER_DDEF: return this->lam_ddef;
1572     case DAE_BUILDER_WDEF: return this->lam_wdef;
1573     case DAE_BUILDER_ODE: return this->lam_ode;
1574     case DAE_BUILDER_DAE: return this->lam_dae;
1575     case DAE_BUILDER_ALG: return this->lam_alg;
1576     case DAE_BUILDER_QUAD: return this->lam_quad;
1577     case DAE_BUILDER_YDEF: return this->lam_ydef;
1578     default: return std::vector<MX>();
1579     }
1580   }
1581 
add_lc(const std::string & name,const std::vector<std::string> & f_out)1582   MX DaeBuilder::add_lc(const std::string& name,
1583                         const std::vector<std::string>& f_out) {
1584     // Make sure object valid
1585     sanity_check();
1586 
1587     // Make sure name is valid
1588     casadi_assert(!name.empty(), "DaeBuilder::add_lc: \"name\" is empty");
1589     for (string::const_iterator i=name.begin(); i!=name.end(); ++i) {
1590       casadi_assert(isalnum(*i),
1591                             "DaeBuilder::add_lc: \"name\" must be alphanumeric");
1592     }
1593 
1594     // Get a reference to the expression
1595     MX& ret = lin_comb_[name];
1596     if (!ret.is_empty()) casadi_warning("DaeBuilder::add_lc: Overwriting " << name);
1597     ret = 0;
1598 
1599     // Get indices of outputs
1600     std::vector<DaeBuilderOut> f_out_enum(f_out.size());
1601     std::vector<bool> in_use(DAE_BUILDER_NUM_OUT, false);
1602     for (casadi_int i=0; i<f_out.size(); ++i) {
1603       DaeBuilderOut oind = enum_out(f_out[i]);
1604       casadi_assert(oind!=DAE_BUILDER_NUM_OUT,
1605         "DaeBuilder::add_lc: No output expression " + f_out[i] + ". "
1606         "Valid expressions are " + name_out());
1607       casadi_assert(!in_use[oind],
1608         "DaeBuilder::add_lc: Duplicate expression " + f_out[i]);
1609       in_use[oind] = true;
1610 
1611       // Add linear combination of expressions
1612       vector<MX> res=output(oind), lam_res=multiplier(oind);
1613       for (casadi_int i=0; i<res.size(); ++i) {
1614         ret += dot(lam_res[i], res[i]);
1615       }
1616     }
1617 
1618     // Return the (cached) expression
1619     return ret;
1620   }
1621 
create(const std::string & fname,const std::vector<std::string> & s_in,const std::vector<std::string> & s_out) const1622   Function DaeBuilder::create(const std::string& fname,
1623                                 const std::vector<std::string>& s_in,
1624                                 const std::vector<std::string>& s_out) const {
1625     // Collect function inputs
1626     vector<MX> ret_in(s_in.size());
1627     std::vector<bool> input_used(DAE_BUILDER_NUM_IN, false);
1628     std::vector<bool> output_used(DAE_BUILDER_NUM_IN, false);
1629     for (vector<string>::const_iterator s_in_it=s_in.begin(); s_in_it!=s_in.end(); ++s_in_it) {
1630       // Primal variable
1631       DaeBuilderIn iind = enum_in(*s_in_it);
1632       if (iind!=DAE_BUILDER_NUM_IN) {
1633         casadi_assert(!input_used[iind],
1634           "DaeBuilder::function: Duplicate expression " + *s_in_it);
1635         input_used[iind] = true;
1636         ret_in[s_in_it-s_in.begin()] = vertcat(input(iind));
1637         continue;
1638       }
1639 
1640       // Dual variable
1641       if (s_in_it->size()>4 && s_in_it->substr(0, 4)=="lam_") {
1642         DaeBuilderOut oind = enum_out(s_in_it->substr(4, string::npos));
1643         if (oind!=DAE_BUILDER_NUM_OUT) {
1644           casadi_assert(!output_used[oind],
1645             "DaeBuilder::function: Duplicate expression " + *s_in_it);
1646           output_used[oind] = true;
1647           ret_in[s_in_it-s_in.begin()] = vertcat(multiplier(oind));
1648           continue;
1649         }
1650       }
1651 
1652       // Error if reached this point
1653       stringstream ss;
1654       ss << "DaeBuilder::function: No input expression " << *s_in_it << "." << endl;
1655       ss << "Valid expressions are: [";
1656       for (casadi_int i=0; i!=DAE_BUILDER_NUM_IN; ++i) {
1657         if (i!=0) ss << ", ";
1658         ss << name_in(static_cast<DaeBuilderIn>(i));
1659       }
1660       for (casadi_int i=0; i!=DAE_BUILDER_NUM_OUT; ++i) {
1661         ss << ", lam_" << name_out(static_cast<DaeBuilderOut>(i));
1662       }
1663       ss << "]";
1664       casadi_error(ss.str());
1665     }
1666 
1667     // Function outputs
1668     vector<MX> ret_out(s_out.size());
1669     vector<bool> assigned(s_out.size(), false);
1670 
1671     // List of valid attributes
1672     enum Attributes {
1673       ATTR_TRANSPOSE,
1674       ATTR_TRIU,
1675       ATTR_TRIL,
1676       ATTR_DENSIFY};
1677 
1678     // Separarate attributes
1679     vector<vector<Attributes> > attr(s_out.size());
1680     vector<string> s_out_noatt = s_out;
1681     for (casadi_int i=0; i<s_out_noatt.size(); ++i) {
1682       // Currently processed string
1683       string& s = s_out_noatt[i];
1684 
1685       // Loop over attributes
1686       while (true) {
1687         // Find the first underscore separator
1688         size_t pos = s.find('_');
1689         if (pos>=s.size()) break; // No more underscore
1690         string a = s.substr(0, pos);
1691 
1692         // Abort if not attribute
1693         if (a=="transpose") {
1694           attr[i].push_back(ATTR_TRANSPOSE);
1695         } else if (a=="triu") {
1696           attr[i].push_back(ATTR_TRIU);
1697         } else if (a=="tril") {
1698           attr[i].push_back(ATTR_TRIL);
1699         } else if (a=="densify") {
1700           attr[i].push_back(ATTR_DENSIFY);
1701         } else {
1702           // No more attribute
1703           break;
1704         }
1705 
1706         // Strip attribute
1707         s = s.substr(pos+1, string::npos);
1708       }
1709     }
1710 
1711     // Non-differentiated outputs
1712     fill(output_used.begin(), output_used.end(), false);
1713     for (casadi_int i=0; i<s_out_noatt.size(); ++i) {
1714       DaeBuilderOut oind = enum_out(s_out_noatt[i]);
1715       if (oind!=DAE_BUILDER_NUM_OUT) {
1716         casadi_assert(!output_used[oind],
1717           "DaeBuilder::function: Duplicate expression " + s_out_noatt[i]);
1718         output_used[oind] = true;
1719         ret_out[i] = vertcat(output(oind));
1720         assigned[i] = true;
1721       }
1722     }
1723 
1724     // Linear combination of outputs
1725     for (casadi_int i=0; i<s_out_noatt.size(); ++i) {
1726       if (assigned[i]) continue;
1727       std::map<std::string, MX>::const_iterator j=lin_comb_.find(s_out_noatt[i]);
1728       if (j!=lin_comb_.end()) {
1729         ret_out[i] = j->second;
1730         assigned[i] = true;
1731       }
1732     }
1733 
1734     // Determine which Jacobian blocks to generate
1735     vector<vector<casadi_int> > wanted(DAE_BUILDER_NUM_OUT,
1736       vector<casadi_int>(DAE_BUILDER_NUM_IN, -1));
1737     for (casadi_int i=0; i<s_out_noatt.size(); ++i) {
1738       if (assigned[i]) continue;
1739 
1740       // Get the string without attributes
1741       const string& so = s_out_noatt[i];
1742 
1743       // Find the first underscore separator
1744       size_t pos = so.find('_');
1745       if (pos>=so.size()) continue;
1746 
1747       // Get operation
1748       string s = so.substr(0, pos);
1749       if (s!="jac") continue;
1750 
1751       // Get expression to be differentiated
1752       size_t pos1 = so.find('_', pos+1);
1753       if (pos1>=so.size()) continue;
1754       s = so.substr(pos+1, pos1-pos-1);
1755       DaeBuilderOut oind = enum_out(s);
1756       if (oind==DAE_BUILDER_NUM_OUT) continue;
1757 
1758       // Jacobian with respect to what variable
1759       s = so.substr(pos1+1, string::npos);
1760       DaeBuilderIn iind = enum_in(s);
1761       if (iind==DAE_BUILDER_NUM_IN) continue;
1762 
1763       // Check if duplicate
1764       casadi_assert(wanted[oind][iind]==-1,
1765         "DaeBuilder::function: Duplicate Jacobian " + so);
1766       wanted[oind][iind] = i;
1767     }
1768 
1769     // Generate Jacobian blocks
1770     for (casadi_int oind=0; oind!=DAE_BUILDER_NUM_OUT; ++oind) {
1771       for (casadi_int iind=0; iind!=DAE_BUILDER_NUM_IN; ++iind) {
1772         // Skip if not wanted
1773         if (wanted[oind][iind]==-1) continue;
1774 
1775         // List of blocks to be calculated together, starting with current
1776         vector<DaeBuilderIn> ib(1, static_cast<DaeBuilderIn>(iind));
1777         vector<DaeBuilderOut> ob(1, static_cast<DaeBuilderOut>(oind));
1778 
1779         // Add other blocks that can be calculated with the same inputs
1780         // (typically cheap if forward mode used)
1781         for (casadi_int oind1=oind+1; oind1!=DAE_BUILDER_NUM_OUT; ++oind1) {
1782           if (wanted[oind1][iind]>=0) {
1783             ob.push_back(static_cast<DaeBuilderOut>(oind1));
1784           }
1785         }
1786 
1787         // Add other blocks that can be calculated with the same outputs
1788         // (typically cheap if reverse mode used)
1789         for (casadi_int iind1=iind+1; iind1!=DAE_BUILDER_NUM_IN; ++iind1) {
1790           // Do we really want _all_ the input/output combinations?
1791           bool all_wanted = true;
1792           for (casadi_int k=0; k<ob.size() && all_wanted; ++k) {
1793             all_wanted = wanted[ob[k]][iind1]>=0;
1794           }
1795 
1796           // Add block(s)
1797           if (all_wanted) {
1798             ib.push_back(static_cast<DaeBuilderIn>(iind1));
1799           }
1800         }
1801 
1802         // When we know which blocks we are interested in, we form the Jacobian
1803         vector<MX> arg=input(ib), res=output(ob);
1804         MX J = jacobian(vertcat(res), vertcat(arg));
1805 
1806         // Divide into blocks and copy to output
1807         vector<vector<MX> > J_all = blocksplit(J, offset(res), offset(arg));
1808         for (casadi_int ki=0; ki<ib.size(); ++ki) {
1809           for (casadi_int ko=0; ko<ob.size(); ++ko) {
1810             casadi_int& ind=wanted[ob[ko]][ib[ki]];
1811             ret_out[ind] = J_all[ko][ki];
1812             assigned[ind] = true;
1813             ind = -1;
1814           }
1815         }
1816       }
1817     }
1818 
1819     // For all linear combinations
1820     for (std::map<std::string, MX>::const_iterator lin_comb_it=lin_comb_.begin();
1821          lin_comb_it!=lin_comb_.end(); ++lin_comb_it) {
1822       // Determine which Hessian blocks to generate
1823       wanted.resize(DAE_BUILDER_NUM_IN);
1824       fill(wanted.begin(), wanted.end(), vector<casadi_int>(DAE_BUILDER_NUM_IN, -1));
1825 
1826       for (casadi_int i=0; i<s_out_noatt.size(); ++i) {
1827         if (assigned[i]) continue;
1828 
1829         // Get the string without attributes
1830         const string& so = s_out_noatt[i];
1831 
1832         // Get operation
1833         size_t pos = so.find('_');
1834         if (pos>=so.size()) continue;
1835         string s = so.substr(0, pos);
1836         if (s!="hes") continue;
1837 
1838         // Get expression to be differentiated
1839         size_t pos1 = so.find('_', pos+1);
1840         if (pos1>=so.size()) continue;
1841         s = so.substr(pos+1, pos1-pos-1);
1842         if (s!=lin_comb_it->first) continue;
1843 
1844         // Get first derivative
1845         pos = so.find('_', pos1+1);
1846         if (pos>=so.size()) continue;
1847         s = so.substr(pos1+1, pos-pos1-1);
1848         DaeBuilderIn iind1 = enum_in(s);
1849         if (iind1==DAE_BUILDER_NUM_IN) continue;
1850 
1851         // Get second derivative
1852         s = so.substr(pos+1, string::npos);
1853         DaeBuilderIn iind2 = enum_in(s);
1854         if (iind2==DAE_BUILDER_NUM_IN) continue;
1855 
1856         // Check if duplicate
1857         casadi_assert(wanted[iind1][iind2]==-1,
1858           "DaeBuilder::function: Duplicate Hessian " + so);
1859         wanted[iind1][iind2] = i;
1860       }
1861 
1862       // Created wanted Hessian blocks
1863       for (casadi_int iind1=0; iind1!=DAE_BUILDER_NUM_IN; ++iind1) {
1864         for (casadi_int iind2=0; iind2!=DAE_BUILDER_NUM_IN; ++iind2) {
1865           // Skip if not wanted
1866           if (wanted[iind1][iind2]==-1) continue;
1867 
1868           // List of blocks to be calculated together, starting with current
1869           vector<DaeBuilderIn> ib1(1, static_cast<DaeBuilderIn>(iind1));
1870           vector<DaeBuilderIn> ib2(1, static_cast<DaeBuilderIn>(iind2));
1871 
1872           // Add other blocks vertically
1873           for (casadi_int iind=iind1+1; iind!=DAE_BUILDER_NUM_IN; ++iind) {
1874             if (wanted[iind][iind2]>=0 || wanted[iind2][iind]>=0) {
1875               ib1.push_back(static_cast<DaeBuilderIn>(iind));
1876             }
1877           }
1878 
1879           // Add other blocks horizontally
1880           for (casadi_int iind=iind2+1; iind!=DAE_BUILDER_NUM_IN; ++iind) {
1881             // Do we really want _all_ the blocks?
1882             bool all_wanted = true;
1883             for (casadi_int k=0; k<ib1.size() && all_wanted; ++k) {
1884               all_wanted = wanted[ib1[k]][iind]>=0 || wanted[iind][ib1[k]]>=0;
1885             }
1886 
1887             // Add block(s)
1888             if (all_wanted) {
1889               ib2.push_back(static_cast<DaeBuilderIn>(iind));
1890             }
1891           }
1892 
1893           // Symmetric or not?
1894           bool symmetric=ib1.size()==ib2.size();
1895           for (casadi_int i=0; symmetric && i<ib1.size(); ++i) symmetric=ib1[i]==ib2[i];
1896 
1897           // Calculate blocks
1898           vector<vector<MX> > H_all;
1899           if (symmetric) {
1900             vector<MX> arg=input(ib1);
1901             MX H = hessian(lin_comb_it->second, vertcat(arg));
1902             H_all = blocksplit(H, offset(arg), offset(arg));
1903           } else {
1904             vector<MX> arg1=input(ib1), arg2=input(ib2);
1905             MX g = gradient(lin_comb_it->second, vertcat(arg1));
1906             MX J = jacobian(g, vertcat(arg2));
1907             H_all = blocksplit(J, offset(arg1), offset(arg2));
1908           }
1909           // Fetch the requested blocks
1910           for (casadi_int k1=0; k1<ib1.size(); ++k1) {
1911             for (casadi_int k2=0; k2<ib2.size(); ++k2) {
1912               casadi_int& ind=wanted[ib1[k1]][ib2[k2]];
1913               if (ind>=0) {
1914                 ret_out[ind] = H_all[k1][k2];
1915                 assigned[ind] = true;
1916                 ind = -1;
1917               }
1918             }
1919           }
1920         }
1921       }
1922     }
1923 
1924     // Check and post-process outputs
1925     for (casadi_int i=0; i<s_out.size(); ++i) {
1926       // Make sure all outputs have been assigned
1927       if (!assigned[i]) {
1928         casadi_error("DaeBuilder::function: Cannot treat output expression " + s_out[i]);
1929       }
1930 
1931       // Apply attributes starting from the right-most one
1932       MX& r = ret_out[i];
1933       for (auto a=attr[i].rbegin(); a!=attr[i].rend(); ++a) {
1934         switch (*a) {
1935         case ATTR_TRANSPOSE: r = r.T(); break;
1936         case ATTR_TRIU: r = triu(r); break;
1937         case ATTR_TRIL: r = tril(r); break;
1938         case ATTR_DENSIFY: r = densify(r); break;
1939         }
1940       }
1941     }
1942 
1943     // Generate the constructed function
1944     return Function(fname, ret_in, ret_out, s_in, s_out);
1945   }
1946 
add_fun(const Function & f)1947   Function DaeBuilder::add_fun(const Function& f) {
1948     casadi_assert(!has_fun(f.name()), "Function '" + f.name() + "' already exists");
1949     fun_.push_back(f);
1950     return f;
1951   }
1952 
add_fun(const std::string & name,const std::vector<std::string> & arg,const std::vector<std::string> & res,const Dict & opts)1953   Function DaeBuilder::add_fun(const std::string& name,
1954                                const std::vector<std::string>& arg,
1955                                const std::vector<std::string>& res,
1956                                const Dict& opts) {
1957     casadi_assert(!has_fun(name), "Function '" + name + "' already exists");
1958 
1959     // Get inputs
1960     vector<MX> arg_ex, res_ex;
1961     for (auto&& s : arg) arg_ex.push_back(var(s));
1962     for (auto&& s : res) {
1963       // Find the binding expression FIXME(@jaeandersson)
1964       casadi_int d_ind;
1965       for (d_ind=0; d_ind<this->d.size(); ++d_ind) {
1966         if (s==this->d.at(d_ind).name()) {
1967           res_ex.push_back(this->ddef.at(d_ind));
1968           break;
1969         }
1970       }
1971       casadi_assert(d_ind<this->d.size(), "Cannot find dependent '" + s + "'");
1972     }
1973     Function ret(name, arg_ex, res_ex, arg, res, opts);
1974     return add_fun(ret);
1975   }
1976 
add_fun(const std::string & name,const Importer & compiler,const Dict & opts)1977   Function DaeBuilder::add_fun(const std::string& name, const Importer& compiler,
1978                                const Dict& opts) {
1979     casadi_assert(!has_fun(name), "Function '" + name + "' already exists");
1980     return add_fun(external(name, compiler, opts));
1981   }
1982 
has_fun(const std::string & name) const1983   bool DaeBuilder::has_fun(const std::string& name) const {
1984     for (const Function& f : fun_) {
1985       if (f.name()==name) return true;
1986     }
1987     return false;
1988   }
1989 
fun(const std::string & name) const1990   Function DaeBuilder::fun(const std::string& name) const {
1991     casadi_assert(has_fun(name), "No such function: '" + name + "'");
1992     for (const Function& f : fun_) {
1993       if (f.name()==name) return f;
1994     }
1995     return Function();
1996   }
1997 
1998 } // namespace casadi
1999