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