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 #ifndef CASADI_FUNCTION_INTERNAL_HPP 27 #define CASADI_FUNCTION_INTERNAL_HPP 28 29 #include "function.hpp" 30 #include <set> 31 #include <stack> 32 #include "code_generator.hpp" 33 #include "importer.hpp" 34 #include "sparse_storage.hpp" 35 #include "options.hpp" 36 #include "shared_object_internal.hpp" 37 #include "timing.hpp" 38 #ifdef CASADI_WITH_THREAD 39 #ifdef CASADI_WITH_THREAD_MINGW 40 #include <mingw.mutex.h> 41 #else // CASADI_WITH_THREAD_MINGW 42 #include <mutex> 43 #endif // CASADI_WITH_THREAD_MINGW 44 #endif //CASADI_WITH_THREAD 45 46 // This macro is for documentation purposes 47 #define INPUTSCHEME(name) 48 49 // This macro is for documentation purposes 50 #define OUTPUTSCHEME(name) 51 52 /// \cond INTERNAL 53 54 namespace casadi { 55 template<typename T> zip(const std::vector<std::string> & id,const std::vector<T> & mat)56 std::vector<std::pair<std::string, T>> zip(const std::vector<std::string>& id, 57 const std::vector<T>& mat) { 58 casadi_assert_dev(id.size()==mat.size()); 59 std::vector<std::pair<std::string, T>> r(id.size()); 60 for (casadi_uint i=0; i<r.size(); ++i) r[i] = make_pair(id[i], mat[i]); 61 return r; 62 } 63 64 /** \brief Function memory with temporary work vectors */ 65 struct CASADI_EXPORT ProtoFunctionMemory { 66 // Function specific statistics 67 std::map<std::string, FStats> fstats; 68 69 // Short-hand for "total" fstats 70 FStats* t_total; 71 72 // Add a statistic add_statcasadi::ProtoFunctionMemory73 void add_stat(const std::string& s) { 74 bool added = fstats.insert(std::make_pair(s, FStats())).second; 75 casadi_assert(added, "Duplicate stat: '" + s + "'"); 76 } 77 }; 78 79 /** \brief Function memory with temporary work vectors */ 80 struct CASADI_EXPORT FunctionMemory : public ProtoFunctionMemory { 81 }; 82 83 /** \brief Base class for FunctionInternal and LinsolInternal 84 \author Joel Andersson 85 \date 2017 86 */ 87 class CASADI_EXPORT ProtoFunction : public SharedObjectInternal { 88 public: 89 /** \brief Constructor */ 90 ProtoFunction(const std::string& name); 91 92 /** \brief Destructor */ 93 ~ProtoFunction() override = 0; 94 95 /** \brief Construct 96 Prepares the function for evaluation 97 */ 98 void construct(const Dict& opts); 99 100 ///@{ 101 /** \brief Options */ 102 static const Options options_; get_options() const103 virtual const Options& get_options() const { return options_;} 104 ///@} 105 106 /// Reconstruct options dict 107 virtual Dict generate_options(bool is_temp=false) const; 108 109 /** \brief Initialize 110 Initialize and make the object ready for setting arguments and evaluation. 111 This method is typically called after setting options but before evaluating. 112 If passed to another class (in the constructor), this class should invoke 113 this function when initialized. */ 114 virtual void init(const Dict& opts); 115 116 /** \brief Finalize the object creation 117 This function, which visits the class hierarchy in reverse order is run after 118 init() has been completed. 119 */ 120 virtual void finalize(); 121 122 /// Checkout a memory object 123 int checkout() const; 124 125 /// Release a memory object 126 void release(int mem) const; 127 128 /// Memory objects 129 void* memory(int ind) const; 130 131 /** \brief Create memory block */ alloc_mem() const132 virtual void* alloc_mem() const { return new ProtoFunctionMemory(); } 133 134 /** \brief Initalize memory block */ 135 virtual int init_mem(void* mem) const; 136 137 /** \brief Free memory block */ free_mem(void * mem) const138 virtual void free_mem(void *mem) const { delete static_cast<ProtoFunctionMemory*>(mem); } 139 140 /// Get all statistics 141 virtual Dict get_stats(void* mem) const; 142 143 /** \brief Clear all memory (called from destructor) */ 144 void clear_mem(); 145 146 /** \brief C-style formatted printing during evaluation */ 147 void print(const char* fmt, ...) const; 148 149 /** \brief C-style formatted printing to string */ 150 void sprint(char* buf, size_t buf_sz, const char* fmt, ...) const; 151 152 /** \brief Format time in a fixed width 8 format */ 153 void format_time(char* buffer, double time) const; 154 155 /** \brief Print timing statistics */ 156 void print_time(const std::map<std::string, FStats>& fstats) const; 157 158 /** \brief Serialize an object */ 159 void serialize(SerializingStream &s) const; 160 161 /** \brief Serialize an object without type information */ 162 virtual void serialize_body(SerializingStream &s) const; 163 /** \brief Serialize type information */ serialize_type(SerializingStream & s) const164 virtual void serialize_type(SerializingStream &s) const {} 165 166 /** \brief String used to identify the immediate FunctionInternal subclass */ serialize_base_function() const167 virtual std::string serialize_base_function() const { 168 return class_name(); 169 } 170 171 protected: 172 /** \brief Deserializing constructor */ 173 explicit ProtoFunction(DeserializingStream& s); 174 175 /// Name 176 std::string name_; 177 178 /// Verbose printout 179 bool verbose_; 180 181 // Print timing statistics 182 bool print_time_; 183 184 // Print timing statistics 185 bool record_time_; 186 187 #ifdef CASADI_WITH_THREAD 188 /// Mutex for thread safety 189 mutable std::mutex mtx_; 190 #endif // CASADI_WITH_THREAD 191 192 private: 193 /// Memory objects 194 mutable std::vector<void*> mem_; 195 196 /// Unused memory objects 197 mutable std::stack<casadi_int> unused_; 198 }; 199 200 /** \brief Internal class for Function 201 \author Joel Andersson 202 \date 2010-2015 203 */ 204 class CASADI_EXPORT FunctionInternal : public ProtoFunction { 205 friend class Function; 206 public: 207 /** \brief Constructor */ 208 FunctionInternal(const std::string& name); 209 210 /** \brief Destructor */ 211 ~FunctionInternal() override = 0; 212 213 /** \brief Obtain solver name from Adaptor */ getAdaptorSolverName() const214 virtual std::string getAdaptorSolverName() const { return ""; } 215 216 ///@{ 217 /** \brief Options */ 218 static const Options options_; get_options() const219 const Options& get_options() const override { return options_;} 220 ///@} 221 222 /// Reconstruct options dict 223 Dict generate_options(bool is_temp=false) const override; 224 225 /** \brief Initialize */ 226 void init(const Dict& opts) override; 227 228 /** \brief Finalize the object creation */ 229 void finalize() override; 230 231 /** \brief Get a public class instance */ self() const232 Function self() const { return shared_from_this<Function>();} 233 234 // Factory 235 virtual Function factory(const std::string& name, 236 const std::vector<std::string>& s_in, 237 const std::vector<std::string>& s_out, 238 const Function::AuxOut& aux, 239 const Dict& opts) const; 240 241 // Get list of dependency functions 242 virtual std::vector<std::string> get_function() const; 243 244 // Get a dependency function 245 virtual const Function& get_function(const std::string &name) const; 246 247 // Check if a particular dependency exists has_function(const std::string & fname) const248 virtual bool has_function(const std::string& fname) const {return false;} 249 250 /** \brief Which variables enter with some order 251 * \param[in] s_in Input name 252 * \param[in] s_out Output name(s) 253 * \param[in] order Only 1 (linear) and 2 (nonlinear) allowed 254 * \param[in] tr Flip the relationship. Return which expressions contain the variables 255 */ 256 virtual std::vector<bool> which_depends(const std::string& s_in, 257 const std::vector<std::string>& s_out, 258 casadi_int order, bool tr=false) const; 259 260 ///@{ 261 /** \brief Is the class able to propagate seeds through the algorithm? */ has_spfwd() const262 virtual bool has_spfwd() const { return false;} has_sprev() const263 virtual bool has_sprev() const { return false;} 264 ///@} 265 266 ///@{ 267 /** \brief Evaluate numerically */ 268 int eval_gen(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const; 269 virtual int eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const; 270 ///@} 271 272 /** \brief Evaluate with symbolic scalars */ 273 virtual int eval_sx(const SXElem** arg, SXElem** res, 274 casadi_int* iw, SXElem* w, void* mem) const; 275 276 /** \brief Evaluate with symbolic matrices */ 277 virtual void eval_mx(const MXVector& arg, MXVector& res, 278 bool always_inline, bool never_inline) const; 279 280 ///@{ 281 /** \brief Evaluate with DM matrices */ 282 virtual std::vector<DM> eval_dm(const std::vector<DM>& arg) const; has_eval_dm() const283 virtual bool has_eval_dm() const { return false;} 284 ///@} 285 286 ///@{ 287 /** \brief Evaluate a function, overloaded */ eval_gen(const SXElem ** arg,SXElem ** res,casadi_int * iw,SXElem * w,void * mem) const288 int eval_gen(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w, void* mem) const { 289 return eval_sx(arg, res, iw, w, mem); 290 } eval_gen(const bvec_t ** arg,bvec_t ** res,casadi_int * iw,bvec_t * w,void * mem) const291 int eval_gen(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const { 292 return sp_forward(arg, res, iw, w, mem); 293 } 294 ///@} 295 296 ///@{ 297 /** \brief Call a function, overloaded */ 298 void call_gen(const MXVector& arg, MXVector& res, casadi_int npar, 299 bool always_inline, bool never_inline) const; 300 301 template<typename D> 302 void call_gen(const std::vector<Matrix<D> >& arg, std::vector<Matrix<D> >& res, 303 casadi_int npar, bool always_inline, bool never_inline) const; 304 ///@} 305 306 /** \brief Call a function, templated */ 307 template<typename M> 308 void call(const std::vector<M>& arg, std::vector<M>& res, 309 bool always_inline, bool never_inline) const; 310 311 ///@{ 312 /** Helper function 313 * 314 * \param npar[in] normal usage: 1, disallow pararallel calls: -1 315 * \param npar[out] required number of parallel calls (or -1) 316 */ 317 static bool check_mat(const Sparsity& arg, const Sparsity& inp, casadi_int& npar); 318 ///@} 319 320 ///@{ 321 /** \brief Check if input arguments have correct length and dimensions 322 * 323 * Raises errors. 324 * 325 * \param npar[in] normal usage: 1, disallow pararallel calls: -1 326 * \param[out] npar: max number of horizontal repetitions across all arguments (or -1) 327 */ 328 template<typename M> 329 void check_arg(const std::vector<M>& arg, casadi_int& npar) const; 330 ///@} 331 332 ///@{ 333 /** \brief Check if output arguments have correct length and dimensions 334 * 335 * Raises errors. 336 * 337 * \param npar[in] normal usage: 1, disallow pararallel calls: -1 338 * \param[out] npar: max number of horizontal repetitions across all arguments (or -1) 339 */ 340 template<typename M> 341 void check_res(const std::vector<M>& res, casadi_int& npar) const; 342 ///@} 343 344 /** \brief Check if input arguments that needs to be replaced 345 * 346 * Raises errors 347 * 348 * \param npar[in] normal usage: 1, disallow pararallel calls: -1 349 * \param[out] npar: max number of horizontal repetitions across all arguments (or -1) 350 */ 351 template<typename M> bool 352 matching_arg(const std::vector<M>& arg, casadi_int& npar) const; 353 354 /** \brief Check if output arguments that needs to be replaced 355 * 356 * Raises errors 357 * 358 * \param npar[in] normal usage: 1, disallow pararallel calls: -1 359 * \param[out] npar: max number of horizontal repetitions across all arguments (or -1) 360 */ 361 template<typename M> bool 362 matching_res(const std::vector<M>& arg, casadi_int& npar) const; 363 364 /** \brief Replace 0-by-0 inputs 365 */ 366 template<typename M> std::vector<M> 367 replace_arg(const std::vector<M>& arg, casadi_int npar) const; 368 369 /** \brief Project sparsities 370 * */ 371 template<typename M> std::vector<M> 372 project_arg(const std::vector<M>& arg, casadi_int npar) const; 373 374 /** \brief Project sparsities 375 * */ 376 template<typename M> std::vector<M> 377 project_res(const std::vector<M>& arg, casadi_int npar) const; 378 379 /** \brief Replace 0-by-0 outputs */ 380 template<typename M> std::vector<M> 381 replace_res(const std::vector<M>& res, casadi_int npar) const; 382 383 /** \brief Replace 0-by-0 forward seeds */ 384 template<typename M> std::vector<std::vector<M>> 385 replace_fseed(const std::vector<std::vector<M>>& fseed, casadi_int npar) const; 386 387 /** \brief Replace 0-by-0 reverse seeds */ 388 template<typename M> std::vector<std::vector<M>> 389 replace_aseed(const std::vector<std::vector<M>>& aseed, casadi_int npar) const; 390 391 /** \brief Convert from/to input/output lists/map */ 392 /// @{ 393 template<typename M> 394 std::map<std::string, M> convert_arg(const std::vector<M>& arg) const; 395 template<typename M> 396 std::vector<M> convert_arg(const std::map<std::string, M>& arg) const; 397 template<typename M> 398 std::map<std::string, M> convert_res(const std::vector<M>& res) const; 399 template<typename M> 400 std::vector<M> convert_res(const std::map<std::string, M>& res) const; 401 /// @} 402 403 /** \brief Convert from/to flat vector of input/output nonzeros */ 404 /// @{ 405 std::vector<double> nz_in(const std::vector<DM>& arg) const; 406 std::vector<double> nz_out(const std::vector<DM>& res) const; 407 std::vector<DM> nz_in(const std::vector<double>& arg) const; 408 std::vector<DM> nz_out(const std::vector<double>& res) const; 409 ///@} 410 is_diff_out(casadi_int i)411 virtual bool is_diff_out(casadi_int i) { return true; } is_diff_in(casadi_int i)412 virtual bool is_diff_in(casadi_int i) { return true; } 413 414 ///@{ 415 /** \brief Forward mode AD, virtual functions overloaded in derived classes */ 416 virtual void call_forward(const std::vector<MX>& arg, const std::vector<MX>& res, 417 const std::vector<std::vector<MX> >& fseed, 418 std::vector<std::vector<MX> >& fsens, 419 bool always_inline, bool never_inline) const; 420 virtual void call_forward(const std::vector<SX>& arg, const std::vector<SX>& res, 421 const std::vector<std::vector<SX> >& fseed, 422 std::vector<std::vector<SX> >& fsens, 423 bool always_inline, bool never_inline) const; 424 ///@} 425 426 ///@{ 427 /** \brief Reverse mode, virtual functions overloaded in derived classes */ 428 virtual void call_reverse(const std::vector<MX>& arg, const std::vector<MX>& res, 429 const std::vector<std::vector<MX> >& aseed, 430 std::vector<std::vector<MX> >& asens, 431 bool always_inline, bool never_inline) const; 432 virtual void call_reverse(const std::vector<SX>& arg, const std::vector<SX>& res, 433 const std::vector<std::vector<SX> >& aseed, 434 std::vector<std::vector<SX> >& asens, 435 bool always_inline, bool never_inline) const; 436 ///@} 437 438 /** \brief Parallel evaluation */ 439 std::vector<MX> mapsum_mx(const std::vector<MX > &arg, const std::string& parallelization); 440 441 /** \brief Do the derivative functions need nondifferentiated outputs? */ uses_output() const442 virtual bool uses_output() const {return false;} 443 444 ///@{ 445 /** \brief Return Jacobian of all input elements with respect to all output elements */ 446 Function jacobian() const; has_jacobian() const447 virtual bool has_jacobian() const { return false;} 448 virtual Function get_jacobian(const std::string& name, 449 const std::vector<std::string>& inames, 450 const std::vector<std::string>& onames, 451 const Dict& opts) const; 452 ///@} 453 454 ///@{ 455 /** \brief Return Jacobian of all input elements with respect to all output elements */ 456 Function jac() const; has_jac() const457 virtual bool has_jac() const { return false;} 458 virtual Function get_jac(const std::string& name, 459 const std::vector<std::string>& inames, 460 const std::vector<std::string>& onames, 461 const Dict& opts) const; 462 ///@} 463 464 ///@{ 465 /** \brief Return function that calculates forward derivatives 466 * forward(nfwd) returns a cached instance if available, 467 * and calls <tt>Function get_forward(casadi_int nfwd)</tt> 468 * if no cached version is available. 469 */ 470 Function forward(casadi_int nfwd) const; has_forward(casadi_int nfwd) const471 virtual bool has_forward(casadi_int nfwd) const { return false;} 472 virtual Function get_forward(casadi_int nfwd, const std::string& name, 473 const std::vector<std::string>& inames, 474 const std::vector<std::string>& onames, 475 const Dict& opts) const; 476 ///@} 477 478 ///@{ 479 /** \brief Return function that calculates adjoint derivatives 480 * reverse(nadj) returns a cached instance if available, 481 * and calls <tt>Function get_reverse(casadi_int nadj)</tt> 482 * if no cached version is available. 483 */ 484 Function reverse(casadi_int nadj) const; has_reverse(casadi_int nadj) const485 virtual bool has_reverse(casadi_int nadj) const { return false;} 486 virtual Function get_reverse(casadi_int nadj, const std::string& name, 487 const std::vector<std::string>& inames, 488 const std::vector<std::string>& onames, 489 const Dict& opts) const; 490 ///@} 491 492 /** \brief returns a new function with a selection of inputs/outputs of the original */ 493 virtual Function slice(const std::string& name, const std::vector<casadi_int>& order_in, 494 const std::vector<casadi_int>& order_out, const Dict& opts) const; 495 496 /** \brief Get oracle */ 497 virtual const Function& oracle() const; 498 499 /** \brief Can derivatives be calculated in any way? */ 500 bool has_derivative() const; 501 502 /** \brief Weighting factor for chosing forward/reverse mode */ 503 virtual double ad_weight() const; 504 505 /** \brief Weighting factor for chosing forward/reverse mode, 506 sparsity propagation */ 507 virtual double sp_weight() const; 508 509 ///@{ 510 /** \brief Get Jacobian sparsity */ 511 Sparsity jacobian_sparsity() const; has_jacobian_sparsity() const512 virtual bool has_jacobian_sparsity() const { return false;} get_jacobian_sparsity() const513 virtual Sparsity get_jacobian_sparsity() const { return Sparsity(); } 514 ///@} 515 516 ///@{ 517 /** \brief Get function input(s) and output(s) */ 518 virtual const SX sx_in(casadi_int ind) const; 519 virtual const SX sx_out(casadi_int ind) const; 520 virtual const std::vector<SX> sx_in() const; 521 virtual const std::vector<SX> sx_out() const; 522 virtual const MX mx_in(casadi_int ind) const; 523 virtual const MX mx_out(casadi_int ind) const; 524 virtual const std::vector<MX> mx_in() const; 525 virtual const std::vector<MX> mx_out() const; 526 const DM dm_in(casadi_int ind) const; 527 const DM dm_out(casadi_int ind) const; 528 const std::vector<DM> dm_in() const; 529 const std::vector<DM> dm_out() const; 530 ///@} 531 532 /// Get free variables (MX) 533 virtual std::vector<MX> free_mx() const; 534 535 /// Get free variables (SX) 536 virtual std::vector<SX> free_sx() const; 537 538 /** \brief Does the function have free variables */ has_free() const539 virtual bool has_free() const { return false;} 540 541 /** \brief Extract the functions needed for the Lifted Newton method */ 542 virtual void generate_lifted(Function& vdef_fcn, Function& vinit_fcn) const; 543 544 /** \brief Get the number of atomic operations */ 545 virtual casadi_int n_instructions() const; 546 547 /** \brief Get an atomic operation operator index */ 548 virtual casadi_int instruction_id(casadi_int k) const; 549 550 /** \brief Get the (integer) input arguments of an atomic operation */ 551 virtual std::vector<casadi_int> instruction_input(casadi_int k) const; 552 553 /** \brief Get the floating point output argument of an atomic operation */ 554 virtual double instruction_constant(casadi_int k) const; 555 556 /** \brief Get the (integer) output argument of an atomic operation */ 557 virtual std::vector<casadi_int> instruction_output(casadi_int k) const; 558 559 /** \brief Number of nodes in the algorithm */ 560 virtual casadi_int n_nodes() const; 561 562 /** *\brief get MX expression associated with instruction */ 563 virtual MX instruction_MX(casadi_int k) const; 564 565 /** *\brief get SX expression associated with instructions */ 566 virtual SX instructions_sx() const; 567 568 /** \brief Wrap in an Function instance consisting of only one MX call */ 569 Function wrap() const; 570 571 /** \brief Wrap in an Function instance consisting of only one MX call */ 572 Function wrap_as_needed(const Dict& opts) const; 573 574 /** \brief Get function in cache */ 575 bool incache(const std::string& fname, Function& f, const std::string& suffix="") const; 576 577 /** \brief Save function to cache */ 578 void tocache(const Function& f, const std::string& suffix="") const; 579 580 /** \brief Generate code the function */ 581 void codegen(CodeGenerator& g, const std::string& fname) const; 582 583 /** \brief Generate meta-information allowing a user to evaluate a generated function */ 584 void codegen_meta(CodeGenerator& g) const; 585 586 /** \brief Codegen sparsities */ 587 void codegen_sparsities(CodeGenerator& g) const; 588 589 /** \brief Get name in codegen */ 590 virtual std::string codegen_name(const CodeGenerator& g, bool ns=true) const; 591 592 /** \brief Get thread-local memory object */ 593 std::string codegen_mem(CodeGenerator& g, const std::string& index="mem") const; 594 595 /** \brief Codegen incref for dependencies */ codegen_incref(CodeGenerator & g) const596 virtual void codegen_incref(CodeGenerator& g) const {} 597 598 /** \brief Codegen decref for dependencies */ codegen_decref(CodeGenerator & g) const599 virtual void codegen_decref(CodeGenerator& g) const {} 600 601 /** \brief Codegen decref for alloc_mem */ 602 virtual void codegen_alloc_mem(CodeGenerator& g) const; 603 604 /** \brief Codegen decref for init_mem */ 605 virtual void codegen_init_mem(CodeGenerator& g) const; 606 607 /** \brief Codegen for free_mem */ codegen_free_mem(CodeGenerator & g) const608 virtual void codegen_free_mem(CodeGenerator& g) const {} 609 610 /** \brief Code generate the function */ 611 std::string signature(const std::string& fname) const; 612 613 /** \brief Generate code for the declarations of the C function */ 614 virtual void codegen_declarations(CodeGenerator& g) const; 615 616 /** \brief Generate code for the function body */ 617 virtual void codegen_body(CodeGenerator& g) const; 618 619 /** \brief Thread-local memory object type */ codegen_mem_type() const620 virtual std::string codegen_mem_type() const { return ""; } 621 622 /** \brief Export / Generate C code for the dependency function */ 623 virtual std::string generate_dependencies(const std::string& fname, const Dict& opts) const; 624 625 /** \brief Is codegen supported? */ has_codegen() const626 virtual bool has_codegen() const { return false;} 627 628 /** \brief Jit dependencies */ jit_dependencies(const std::string & fname)629 virtual void jit_dependencies(const std::string& fname) {} 630 631 /** \brief Export function in a specific language */ 632 virtual void export_code(const std::string& lang, 633 std::ostream &stream, const Dict& options) const; 634 635 /** \brief Serialize type information */ 636 void serialize_type(SerializingStream &s) const override; 637 638 /** \brief Serialize an object without type information */ 639 void serialize_body(SerializingStream &s) const override; 640 641 /** \brief Display object */ 642 void disp(std::ostream& stream, bool more) const override; 643 644 /** \brief Print more */ disp_more(std::ostream & stream) const645 virtual void disp_more(std::ostream& stream) const {} 646 647 /** \brief Get function signature: name:(inputs)->(outputs) */ 648 std::string definition() const; 649 650 /** \brief Print dimensions of inputs and outputs */ 651 void print_dimensions(std::ostream &stream) const; 652 653 /** \brief Print list of options */ 654 void print_options(std::ostream &stream) const; 655 656 /** \brief Print all information there is to know about a certain option */ 657 void print_option(const std::string &name, std::ostream &stream) const; 658 659 /** \brief Print free variables */ 660 virtual std::vector<std::string> get_free() const; 661 662 /** \brief Get the unidirectional or bidirectional partition */ 663 void get_partition(casadi_int iind, casadi_int oind, Sparsity& D1, Sparsity& D2, 664 bool compact, bool symmetric, 665 bool allow_forward, bool allow_reverse) const; 666 667 ///@{ 668 /** \brief Number of input/output nonzeros */ 669 casadi_int nnz_in() const; nnz_in(casadi_int ind) const670 casadi_int nnz_in(casadi_int ind) const { return sparsity_in(ind).nnz(); } 671 casadi_int nnz_out() const; nnz_out(casadi_int ind) const672 casadi_int nnz_out(casadi_int ind) const { return sparsity_out(ind).nnz(); } 673 ///@} 674 675 ///@{ 676 /** \brief Number of input/output elements */ 677 casadi_int numel_in() const; numel_in(casadi_int ind) const678 casadi_int numel_in(casadi_int ind) const { return sparsity_in(ind).numel(); } numel_out(casadi_int ind) const679 casadi_int numel_out(casadi_int ind) const { return sparsity_out(ind).numel(); } 680 casadi_int numel_out() const; 681 ///@} 682 683 ///@{ 684 /** \brief Input/output dimensions */ size1_in(casadi_int ind) const685 casadi_int size1_in(casadi_int ind) const { return sparsity_in(ind).size1(); } size2_in(casadi_int ind) const686 casadi_int size2_in(casadi_int ind) const { return sparsity_in(ind).size2(); } size1_out(casadi_int ind) const687 casadi_int size1_out(casadi_int ind) const { return sparsity_out(ind).size1(); } size2_out(casadi_int ind) const688 casadi_int size2_out(casadi_int ind) const { return sparsity_out(ind).size2(); } size_in(casadi_int ind) const689 std::pair<casadi_int, casadi_int> size_in(casadi_int ind) const { 690 return sparsity_in(ind).size(); 691 } size_out(casadi_int ind) const692 std::pair<casadi_int, casadi_int> size_out(casadi_int ind) const { 693 return sparsity_out(ind).size(); 694 } 695 ///@} 696 697 ///@{ 698 /** \brief Input/output sparsity */ sparsity_in(casadi_int ind) const699 const Sparsity& sparsity_in(casadi_int ind) const { return sparsity_in_.at(ind); } sparsity_out(casadi_int ind) const700 const Sparsity& sparsity_out(casadi_int ind) const { return sparsity_out_.at(ind); } 701 ///@} 702 703 ///@{ 704 /** \brief Are all inputs and outputs scalar */ 705 bool all_scalar() const; 706 707 /// Generate the sparsity of a Jacobian block 708 virtual Sparsity getJacSparsity(casadi_int iind, casadi_int oind, bool symmetric) const; 709 710 /// Get the sparsity pattern, forward mode 711 template<bool fwd> 712 Sparsity getJacSparsityGen(casadi_int iind, casadi_int oind, bool symmetric, 713 casadi_int gr_i=1, casadi_int gr_o=1) const; 714 715 /// A flavor of getJacSparsity that does hierarchical block structure recognition 716 Sparsity getJacSparsityHierarchical(casadi_int iind, casadi_int oind) const; 717 718 /** A flavor of getJacSparsity that does hierarchical block 719 * structure recognition for symmetric Jacobians 720 */ 721 Sparsity getJacSparsityHierarchicalSymm(casadi_int iind, casadi_int oind) const; 722 723 /// Get, if necessary generate, the sparsity of a Jacobian block 724 Sparsity& sparsity_jac(casadi_int iind, casadi_int oind, bool compact, bool symmetric) const; 725 726 /// Filter out nonzeros in the full sparsity jacobian according to is_diff_in/out 727 Sparsity jacobian_sparsity_filter(const Sparsity& sp) const; 728 729 /// Get a vector of symbolic variables corresponding to the outputs 730 virtual std::vector<MX> symbolic_output(const std::vector<MX>& arg) const; 731 732 ///@{ 733 /** \brief Number of function inputs and outputs */ 734 virtual size_t get_n_in(); 735 virtual size_t get_n_out(); 736 ///@} 737 738 739 ///@{ 740 /** \brief Names of function input and outputs */ 741 virtual std::string get_name_in(casadi_int i); 742 virtual std::string get_name_out(casadi_int i); 743 ///@} 744 745 /** \brief Get default input value */ get_default_in(casadi_int ind) const746 virtual double get_default_in(casadi_int ind) const { 747 return 0; 748 } 749 750 /** \brief Get largest input value */ get_max_in(casadi_int ind) const751 virtual double get_max_in(casadi_int ind) const { 752 return inf; 753 } 754 755 /** \brief Get smallest input value */ get_min_in(casadi_int ind) const756 virtual double get_min_in(casadi_int ind) const { 757 return -inf; 758 } 759 760 /** \brief Get relative tolerance */ get_reltol() const761 virtual double get_reltol() const { 762 return eps; 763 } 764 765 /** \brief Get absolute tolerance */ get_abstol() const766 virtual double get_abstol() const { 767 return eps; 768 } 769 770 /** \brief Get sparsity of a given input */ 771 virtual Sparsity get_sparsity_in(casadi_int i); 772 773 /** \brief Get sparsity of a given output */ 774 virtual Sparsity get_sparsity_out(casadi_int i); 775 776 /** \brief Get input scheme index by name */ index_in(const std::string & name) const777 casadi_int index_in(const std::string &name) const { 778 for (casadi_int i=0; i<name_in_.size(); ++i) { 779 if (name_in_[i]==name) return i; 780 } 781 casadi_error("FunctionInternal::index_in: could not find entry \"" 782 + name + "\". Available names are: " + str(name_in_) + "."); 783 return -1; 784 } 785 786 /** \brief Get output scheme index by name */ index_out(const std::string & name) const787 casadi_int index_out(const std::string &name) const { 788 for (casadi_int i=0; i<name_out_.size(); ++i) { 789 if (name_out_[i]==name) return i; 790 } 791 casadi_error("FunctionInternal::index_out: could not find entry \"" 792 + name + "\". Available names are: " + str(name_out_) + "."); 793 return -1; 794 } 795 796 /** \brief Propagate sparsity forward */ 797 virtual int sp_forward(const bvec_t** arg, bvec_t** res, 798 casadi_int* iw, bvec_t* w, void* mem) const; 799 800 /** \brief Propagate sparsity backwards */ 801 virtual int sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const; 802 803 /** \brief Get number of temporary variables needed */ 804 void sz_work(size_t& sz_arg, size_t& sz_res, size_t& sz_iw, size_t& sz_w) const; 805 806 /** \brief Get required length of arg field */ sz_arg() const807 size_t sz_arg() const { return sz_arg_per_ + sz_arg_tmp_;} 808 809 /** \brief Get required length of res field */ sz_res() const810 size_t sz_res() const { return sz_res_per_ + sz_res_tmp_;} 811 812 /** \brief Get required length of iw field */ sz_iw() const813 size_t sz_iw() const { return sz_iw_per_ + sz_iw_tmp_;} 814 815 /** \brief Get required length of w field */ sz_w() const816 size_t sz_w() const { return sz_w_per_ + sz_w_tmp_;} 817 818 /** \brief Ensure required length of arg field */ 819 void alloc_arg(size_t sz_arg, bool persistent=false); 820 821 /** \brief Ensure required length of res field */ 822 void alloc_res(size_t sz_res, bool persistent=false); 823 824 /** \brief Ensure required length of iw field */ 825 void alloc_iw(size_t sz_iw, bool persistent=false); 826 827 /** \brief Ensure required length of w field */ 828 void alloc_w(size_t sz_w, bool persistent=false); 829 830 /** \brief Ensure work vectors long enough to evaluate function */ 831 void alloc(const Function& f, bool persistent=false); 832 833 /** \brief Set the (persistent) work vectors */ set_work(void * mem,const double ** & arg,double ** & res,casadi_int * & iw,double * & w) const834 virtual void set_work(void* mem, const double**& arg, double**& res, 835 casadi_int*& iw, double*& w) const {} 836 837 /** \brief Set the (temporary) work vectors */ set_temp(void * mem,const double ** arg,double ** res,casadi_int * iw,double * w) const838 virtual void set_temp(void* mem, const double** arg, double** res, 839 casadi_int* iw, double* w) const {} 840 841 /** \brief Set the (persistent and temporary) work vectors */ 842 void setup(void* mem, const double** arg, double** res, casadi_int* iw, double* w) const; 843 844 ///@{ 845 /** \brief Calculate derivatives by multiplying the full Jacobian and multiplying */ 846 virtual bool fwdViaJac(casadi_int nfwd) const; 847 virtual bool adjViaJac(casadi_int nadj) const; 848 ///@} 849 850 /** Obtain information about function */ 851 virtual Dict info() const; 852 853 /** \brief Generate/retrieve cached serial map */ 854 Function map(casadi_int n, const std::string& parallelization) const; 855 856 /** \brief Export an input file that can be passed to generate C code with a main */ 857 void generate_in(const std::string& fname, const double** arg) const; 858 void generate_out(const std::string& fname, double** res) const; 859 860 bool always_inline_, never_inline_; 861 862 /// Number of inputs and outputs 863 size_t n_in_, n_out_; 864 865 /// Are inputs and outputs differentiable? 866 std::vector<bool> is_diff_in_, is_diff_out_; 867 868 /// Input and output sparsity 869 std::vector<Sparsity> sparsity_in_, sparsity_out_; 870 871 /// Input and output scheme 872 std::vector<std::string> name_in_, name_out_; 873 874 /** \brief Use just-in-time compiler */ 875 bool jit_; 876 877 /** \brief Cleanup jit source file */ 878 bool jit_cleanup_; 879 880 /** \brief Serialize behaviour */ 881 std::string jit_serialize_; 882 883 /** \brief Name if jit source file */ 884 std::string jit_name_; 885 886 std::string jit_base_name_; 887 888 /** \brief Use a temporary name */ 889 bool jit_temp_suffix_; 890 891 /** \brief Numerical evaluation redirected to a C function */ 892 eval_t eval_; 893 894 /** \brief Checkout redirected to a C function */ 895 casadi_checkout_t checkout_; 896 897 /** \brief Release redirected to a C function */ 898 casadi_release_t release_; 899 900 /** \brief Dict of statistics (resulting from evaluate) */ 901 Dict stats_; 902 903 /** \brief Reference counting in codegen? */ 904 bool has_refcount_; 905 906 /// Function cache 907 mutable std::map<std::string, WeakRef> cache_; 908 909 /// Cache for full Jacobian 910 mutable WeakRef jacobian_; 911 912 /// Cache for sparsities of the Jacobian blocks 913 mutable SparseStorage<Sparsity> jac_sparsity_, jac_sparsity_compact_; 914 915 /// Cache for full Jacobian sparsity 916 mutable Sparsity jacobian_sparsity_; 917 918 /// If the function is the derivative of another function 919 Function derivative_of_; 920 921 /// User-set field 922 void* user_data_; 923 924 /// Just-in-time compiler 925 std::string compiler_plugin_; 926 Importer compiler_; 927 Dict jit_options_; 928 929 /// Penalty factor for using a complete Jacobian to calculate directional derivatives 930 double jac_penalty_; 931 932 // Types of derivative calculation permitted 933 bool enable_forward_, enable_reverse_, enable_jacobian_, enable_fd_; 934 bool enable_forward_op_, enable_reverse_op_, enable_jacobian_op_, enable_fd_op_; 935 936 /// Weighting factor for derivative calculation and sparsity pattern calculation 937 double ad_weight_, ad_weight_sp_; 938 939 /// Maximum number of sensitivity directions 940 casadi_int max_num_dir_; 941 942 /// Errors are thrown when NaN is produced 943 bool regularity_check_; 944 945 /// Errors are thrown if numerical values of inputs look bad 946 bool inputs_check_; 947 948 // Finite difference step 949 Dict fd_options_; 950 951 // Finite difference step size 952 double fd_step_; 953 954 // Finite difference method 955 std::string fd_method_; 956 957 // Print input/output 958 bool print_in_; 959 bool print_out_; 960 961 // Dump input/output 962 bool dump_in_, dump_out_, dump_; 963 964 // Directory to dump to 965 std::string dump_dir_; 966 967 // Format to dump with 968 std::string dump_format_; 969 970 // Forward/reverse options 971 Dict forward_options_, reverse_options_; 972 973 // Store a reference to a custom Jacobian 974 Function custom_jacobian_; 975 976 // Counter for unique names for dumping inputs and output 977 mutable casadi_int dump_count_ = 0; 978 #ifdef CASADI_WITH_THREAD 979 mutable std::mutex dump_count_mtx_; 980 #endif // CASADI_WITH_THREAD 981 982 /** \brief Check if the function is of a particular type */ 983 virtual bool is_a(const std::string& type, bool recursive) const; 984 985 /** \brief Can a derivative direction be skipped */ 986 template<typename MatType> 987 static bool purgable(const std::vector<MatType>& seed); 988 989 /** \brief Symbolic expressions for the forward seeds */ 990 template<typename MatType> 991 std::vector<std::vector<MatType> > 992 fwd_seed(casadi_int nfwd) const; 993 994 /** \brief Symbolic expressions for the adjoint seeds */ 995 template<typename MatType> 996 std::vector<std::vector<MatType> > 997 symbolicAdjSeed(casadi_int nadj, const std::vector<MatType>& v) const; 998 999 /** Unified return status for solvers */ 1000 enum UnifiedReturnStatus { 1001 SOLVER_RET_UNKNOWN, 1002 SOLVER_RET_SUCCESS, 1003 SOLVER_RET_LIMITED, // Out of time 1004 SOLVER_RET_NAN 1005 }; 1006 1007 static std::string string_from_UnifiedReturnStatus(UnifiedReturnStatus status); 1008 1009 /** \brief Deserializing constructor */ 1010 explicit FunctionInternal(DeserializingStream& e); 1011 1012 /** \brief Deserialize with type disambiguation */ 1013 static Function deserialize(DeserializingStream& s); 1014 1015 static std::map<std::string, ProtoFunction* (*)(DeserializingStream&)> deserialize_map; 1016 1017 protected: 1018 /** \brief Populate jac_sparsity_ and jac_sparsity_compact_ during initialization */ 1019 void set_jac_sparsity(const Sparsity& sp); 1020 1021 private: 1022 // @{ 1023 /// Dumping functionality 1024 casadi_int get_dump_id() const; 1025 void dump_in(casadi_int id, const double** arg) const; 1026 void dump_out(casadi_int id, double** res) const; 1027 void dump() const; 1028 // @} 1029 1030 /** \brief Memory that is persistent during a call (but not between calls) */ 1031 size_t sz_arg_per_, sz_res_per_, sz_iw_per_, sz_w_per_; 1032 1033 /** \brief Temporary memory inside a function */ 1034 size_t sz_arg_tmp_, sz_res_tmp_, sz_iw_tmp_, sz_w_tmp_; 1035 }; 1036 1037 // Template implementations 1038 template<typename MatType> purgable(const std::vector<MatType> & v)1039 bool FunctionInternal::purgable(const std::vector<MatType>& v) { 1040 for (auto i=v.begin(); i!=v.end(); ++i) { 1041 if (!i->is_zero()) return false; 1042 } 1043 return true; 1044 } 1045 1046 template<typename MatType> 1047 std::vector<std::vector<MatType> > 1048 FunctionInternal:: fwd_seed(casadi_int nfwd) const1049 fwd_seed(casadi_int nfwd) const { 1050 std::vector<std::vector<MatType>> fseed(nfwd); 1051 for (casadi_int dir=0; dir<nfwd; ++dir) { 1052 fseed[dir].resize(n_in_); 1053 for (casadi_int iind=0; iind<n_in_; ++iind) { 1054 std::string n = "f" + str(dir) + "_" + name_in_[iind]; 1055 Sparsity sp = is_diff_in_[iind] ? sparsity_in(iind) : Sparsity(size_in(iind)); 1056 fseed[dir][iind] = MatType::sym(n, sp); 1057 } 1058 } 1059 return fseed; 1060 } 1061 1062 template<typename MatType> 1063 std::vector<std::vector<MatType> > 1064 FunctionInternal:: symbolicAdjSeed(casadi_int nadj,const std::vector<MatType> & v) const1065 symbolicAdjSeed(casadi_int nadj, const std::vector<MatType>& v) const { 1066 std::vector<std::vector<MatType> > aseed(nadj, v); 1067 for (casadi_int dir=0; dir<nadj; ++dir) { 1068 // Replace symbolic inputs 1069 casadi_int oind=0; 1070 for (typename std::vector<MatType>::iterator i=aseed[dir].begin(); 1071 i!=aseed[dir].end(); 1072 ++i, ++oind) { 1073 // Name of the adjoint seed 1074 std::stringstream ss; 1075 ss << "a"; 1076 if (nadj>1) ss << dir << "_"; 1077 ss << oind; 1078 1079 // Save to matrix 1080 *i = MatType::sym(ss.str(), is_diff_out_[oind] ? i->sparsity() : Sparsity(i->size())); 1081 1082 } 1083 } 1084 return aseed; 1085 } 1086 1087 template<typename M> call(const std::vector<M> & arg,std::vector<M> & res,bool always_inline,bool never_inline) const1088 void FunctionInternal::call(const std::vector<M>& arg, std::vector<M>& res, 1089 bool always_inline, bool never_inline) const { 1090 // If all inputs are scalar ... 1091 if (all_scalar()) { 1092 // ... and some arguments are matrix-valued with matching dimensions ... 1093 bool matrix_call = false; 1094 std::pair<casadi_int, casadi_int> sz; 1095 for (auto&& a : arg) { 1096 if (!a.is_scalar() && !a.is_empty()) { 1097 if (!matrix_call) { 1098 // Matrix call 1099 matrix_call = true; 1100 sz = a.size(); 1101 } else if (a.size()!=sz) { 1102 // Not same dimensions 1103 matrix_call = false; 1104 break; 1105 } 1106 } 1107 } 1108 1109 // ... then, call multiple times 1110 if (matrix_call) { 1111 // Start with zeros 1112 res.resize(n_out_); 1113 M z = M::zeros(sz); 1114 for (auto&& a : res) a = z; 1115 // Call multiple times 1116 std::vector<M> arg1 = arg, res1; 1117 for (casadi_int c=0; c<sz.second; ++c) { 1118 for (casadi_int r=0; r<sz.first; ++r) { 1119 // Get scalar arguments 1120 for (casadi_int i=0; i<arg.size(); ++i) { 1121 if (arg[i].size()==sz) arg1[i] = arg[i](r, c); 1122 } 1123 // Call recursively with scalar arguments 1124 call(arg1, res1, always_inline, never_inline); 1125 // Get results 1126 casadi_assert_dev(res.size() == res1.size()); 1127 for (casadi_int i=0; i<res.size(); ++i) res[i](r, c) = res1[i]; 1128 } 1129 } 1130 // All elements assigned 1131 return; 1132 } 1133 } 1134 1135 // Check if inputs need to be replaced 1136 casadi_int npar = 1; 1137 if (!matching_arg(arg, npar)) { 1138 return call(replace_arg(arg, npar), res, always_inline, never_inline); 1139 } 1140 1141 // Call the type-specific method 1142 call_gen(arg, res, npar, always_inline, never_inline); 1143 } 1144 1145 template<typename M> 1146 std::vector<M> FunctionInternal:: project_arg(const std::vector<M> & arg,casadi_int npar) const1147 project_arg(const std::vector<M>& arg, casadi_int npar) const { 1148 casadi_assert_dev(arg.size()==n_in_); 1149 1150 // Which arguments require mapped evaluation 1151 std::vector<bool> mapped(n_in_); 1152 for (casadi_int i=0; i<n_in_; ++i) { 1153 mapped[i] = arg[i].size2()!=size2_in(i); 1154 } 1155 1156 // Check if matching input sparsity 1157 std::vector<bool> matching(n_in_); 1158 bool any_mismatch = false; 1159 for (casadi_int i=0; i<n_in_; ++i) { 1160 if (mapped[i]) { 1161 matching[i] = arg[i].sparsity().is_stacked(sparsity_in(i), npar); 1162 } else { 1163 matching[i] = arg[i].sparsity()==sparsity_in(i); 1164 } 1165 any_mismatch = any_mismatch || !matching[i]; 1166 } 1167 1168 // Correct input sparsity 1169 if (any_mismatch) { 1170 std::vector<M> arg2(arg); 1171 for (casadi_int i=0; i<n_in_; ++i) { 1172 if (!matching[i]) { 1173 if (mapped[i]) { 1174 arg2[i] = project(arg2[i], repmat(sparsity_in(i), 1, npar)); 1175 } else { 1176 arg2[i] = project(arg2[i], sparsity_in(i)); 1177 } 1178 } 1179 } 1180 return arg2; 1181 } 1182 return arg; 1183 } 1184 1185 template<typename M> 1186 std::vector<M> FunctionInternal:: project_res(const std::vector<M> & arg,casadi_int npar) const1187 project_res(const std::vector<M>& arg, casadi_int npar) const { 1188 return arg; 1189 } 1190 1191 template<typename D> 1192 void FunctionInternal:: call_gen(const std::vector<Matrix<D>> & arg,std::vector<Matrix<D>> & res,casadi_int npar,bool always_inline,bool never_inline) const1193 call_gen(const std::vector<Matrix<D> >& arg, std::vector<Matrix<D> >& res, 1194 casadi_int npar, bool always_inline, bool never_inline) const { 1195 casadi_assert(!never_inline, "Call-nodes only possible in MX expressions"); 1196 std::vector< Matrix<D> > arg2 = project_arg(arg, npar); 1197 1198 // Which arguments require mapped evaluation 1199 std::vector<bool> mapped(n_in_); 1200 for (casadi_int i=0; i<n_in_; ++i) { 1201 mapped[i] = arg[i].size2()!=size2_in(i); 1202 } 1203 1204 // Allocate results 1205 res.resize(n_out_); 1206 for (casadi_int i=0; i<n_out_; ++i) { 1207 if (!res[i].sparsity().is_stacked(sparsity_out(i), npar)) { 1208 res[i] = Matrix<D>::zeros(repmat(sparsity_out(i), 1, npar)); 1209 } 1210 } 1211 1212 // Allocate temporary memory if needed 1213 std::vector<casadi_int> iw_tmp(sz_iw()); 1214 std::vector<D> w_tmp(sz_w()); 1215 1216 // Get pointers to input arguments 1217 std::vector<const D*> argp(sz_arg()); 1218 for (casadi_int i=0; i<n_in_; ++i) argp[i]=get_ptr(arg2[i]); 1219 1220 // Get pointers to output arguments 1221 std::vector<D*> resp(sz_res()); 1222 for (casadi_int i=0; i<n_out_; ++i) resp[i]=get_ptr(res[i]); 1223 1224 // For all parallel calls 1225 for (casadi_int p=0; p<npar; ++p) { 1226 // Call memory-less 1227 if (eval_gen(get_ptr(argp), get_ptr(resp), 1228 get_ptr(iw_tmp), get_ptr(w_tmp), memory(0))) { 1229 casadi_error("Evaluation failed"); 1230 } 1231 // Update offsets 1232 if (p==npar-1) break; 1233 for (casadi_int i=0; i<n_in_; ++i) if (mapped[i]) argp[i] += nnz_in(i); 1234 for (casadi_int i=0; i<n_out_; ++i) resp[i] += nnz_out(i); 1235 } 1236 } 1237 1238 template<typename M> check_arg(const std::vector<M> & arg,casadi_int & npar) const1239 void FunctionInternal::check_arg(const std::vector<M>& arg, casadi_int& npar) const { 1240 casadi_assert(arg.size()==n_in_, "Incorrect number of inputs: Expected " 1241 + str(n_in_) + ", got " + str(arg.size())); 1242 for (casadi_int i=0; i<n_in_; ++i) { 1243 if (!check_mat(arg[i].sparsity(), sparsity_in(i), npar)) { 1244 // Dimensions 1245 std::string d_arg = str(arg[i].size1()) + "-by-" + str(arg[i].size2()); 1246 std::string d_in = str(size1_in(i)) + "-by-" + str(size2_in(i)); 1247 std::string e = "Input " + str(i) + " (" + name_in_[i] + ") has mismatching shape. " 1248 "Got " + d_arg + ". Allowed dimensions, in general, are:\n" 1249 " - The input dimension N-by-M (here " + d_in + ")\n" 1250 " - A scalar, i.e. 1-by-1\n" 1251 " - M-by-N if N=1 or M=1 (i.e. a transposed vector)\n" 1252 " - N-by-M1 if K*M1=M for some K (argument repeated horizontally)\n"; 1253 if (npar!=-1) { 1254 e += " - N-by-P*M, indicating evaluation with multiple arguments (P must be a " 1255 "multiple of " + str(npar) + " for consistency with previous inputs)"; 1256 } 1257 casadi_error(e); 1258 } 1259 } 1260 } 1261 1262 template<typename M> check_res(const std::vector<M> & res,casadi_int & npar) const1263 void FunctionInternal::check_res(const std::vector<M>& res, casadi_int& npar) const { 1264 casadi_assert(res.size()==n_out_, "Incorrect number of outputs: Expected " 1265 + str(n_out_) + ", got " + str(res.size())); 1266 for (casadi_int i=0; i<n_out_; ++i) { 1267 casadi_assert(check_mat(res[i].sparsity(), sparsity_out(i), npar), 1268 "Output " + str(i) + " (" + name_out_[i] + ") has mismatching shape. " 1269 "Expected " + str(size_out(i)) + ", got " + str(res[i].size())); 1270 } 1271 } 1272 1273 template<typename M> matching_arg(const std::vector<M> & arg,casadi_int & npar) const1274 bool FunctionInternal::matching_arg(const std::vector<M>& arg, casadi_int& npar) const { 1275 check_arg(arg, npar); 1276 for (casadi_int i=0; i<n_in_; ++i) { 1277 if (arg.at(i).size1()!=size1_in(i)) return false; 1278 if (arg.at(i).size2()!=size2_in(i) && arg.at(i).size2()!=npar*size2_in(i)) return false; 1279 } 1280 return true; 1281 } 1282 1283 template<typename M> matching_res(const std::vector<M> & res,casadi_int & npar) const1284 bool FunctionInternal::matching_res(const std::vector<M>& res, casadi_int& npar) const { 1285 check_res(res, npar); 1286 for (casadi_int i=0; i<n_out_; ++i) { 1287 if (res.at(i).size1()!=size1_out(i)) return false; 1288 if (res.at(i).size2()!=size2_out(i) && res.at(i).size2()!=npar*size2_out(i)) return false; 1289 } 1290 return true; 1291 } 1292 1293 template<typename M> replace_mat(const M & arg,const Sparsity & inp,casadi_int npar)1294 M replace_mat(const M& arg, const Sparsity& inp, casadi_int npar) { 1295 if (arg.size()==inp.size()) { 1296 // Matching dimensions already 1297 return arg; 1298 } else if (arg.is_empty()) { 1299 // Empty matrix means set zero 1300 return M(inp.size()); 1301 } else if (arg.is_scalar()) { 1302 // Scalar assign means set all 1303 return M(inp, arg); 1304 } else if (arg.is_vector() && inp.size()==std::make_pair(arg.size2(), arg.size1())) { 1305 // Transpose vector 1306 return arg.T(); 1307 } else if (arg.size1()==inp.size1() && arg.size2()>0 && inp.size2()>0 1308 && inp.size2()%arg.size2()==0) { 1309 // Horizontal repmat 1310 return repmat(arg, 1, inp.size2()/arg.size2()); 1311 } else { 1312 casadi_assert_dev(npar!=-1); 1313 // Multiple evaluation 1314 return repmat(arg, 1, (npar*inp.size2())/arg.size2()); 1315 } 1316 } 1317 1318 template<typename M> 1319 std::vector<M> FunctionInternal:: replace_arg(const std::vector<M> & arg,casadi_int npar) const1320 replace_arg(const std::vector<M>& arg, casadi_int npar) const { 1321 std::vector<M> r(arg.size()); 1322 for (casadi_int i=0; i<r.size(); ++i) r[i] = replace_mat(arg[i], sparsity_in(i), npar); 1323 return r; 1324 } 1325 1326 template<typename M> 1327 std::vector<M> FunctionInternal:: replace_res(const std::vector<M> & res,casadi_int npar) const1328 replace_res(const std::vector<M>& res, casadi_int npar) const { 1329 std::vector<M> r(res.size()); 1330 for (casadi_int i=0; i<r.size(); ++i) r[i] = replace_mat(res[i], sparsity_out(i), npar); 1331 return r; 1332 } 1333 1334 template<typename M> 1335 std::vector<std::vector<M> > FunctionInternal:: replace_fseed(const std::vector<std::vector<M>> & fseed,casadi_int npar) const1336 replace_fseed(const std::vector<std::vector<M> >& fseed, casadi_int npar) const { 1337 std::vector<std::vector<M> > r(fseed.size()); 1338 for (casadi_int d=0; d<r.size(); ++d) r[d] = replace_arg(fseed[d], npar); 1339 return r; 1340 } 1341 1342 template<typename M> 1343 std::vector<std::vector<M> > FunctionInternal:: replace_aseed(const std::vector<std::vector<M>> & aseed,casadi_int npar) const1344 replace_aseed(const std::vector<std::vector<M> >& aseed, casadi_int npar) const { 1345 std::vector<std::vector<M> > r(aseed.size()); 1346 for (casadi_int d=0; d<r.size(); ++d) r[d] = replace_res(aseed[d], npar); 1347 return r; 1348 } 1349 1350 template<typename M> 1351 std::map<std::string, M> FunctionInternal:: convert_arg(const std::vector<M> & arg) const1352 convert_arg(const std::vector<M>& arg) const { 1353 casadi_assert(arg.size()==n_in_, "Incorrect number of inputs: Expected " 1354 + str(n_in_) + ", got " + str(arg.size())); 1355 std::map<std::string, M> ret; 1356 for (casadi_int i=0;i<n_in_;++i) { 1357 ret[name_in_[i]] = arg[i]; 1358 } 1359 return ret; 1360 } 1361 1362 template<typename M> 1363 std::vector<M> FunctionInternal:: convert_arg(const std::map<std::string,M> & arg) const1364 convert_arg(const std::map<std::string, M>& arg) const { 1365 // Get default inputs 1366 std::vector<M> arg_v(n_in_); 1367 for (casadi_int i=0; i<arg_v.size(); ++i) { 1368 arg_v[i] = get_default_in(i); 1369 } 1370 1371 // Assign provided inputs 1372 for (auto&& e : arg) { 1373 arg_v.at(index_in(e.first)) = e.second; 1374 } 1375 1376 return arg_v; 1377 } 1378 1379 template<typename M> 1380 std::map<std::string, M> FunctionInternal:: convert_res(const std::vector<M> & res) const1381 convert_res(const std::vector<M>& res) const { 1382 casadi_assert(res.size()==n_out_, "Incorrect number of outputs: Expected " 1383 + str(n_out_) + ", got " + str(res.size())); 1384 std::map<std::string, M> ret; 1385 for (casadi_int i=0;i<n_out_;++i) { 1386 ret[name_out_[i]] = res[i]; 1387 } 1388 return ret; 1389 } 1390 1391 template<typename M> 1392 std::vector<M> FunctionInternal:: convert_res(const std::map<std::string,M> & res) const1393 convert_res(const std::map<std::string, M>& res) const { 1394 // Get default inputs 1395 std::vector<M> res_v(n_out_); 1396 for (casadi_int i=0; i<res_v.size(); ++i) { 1397 res_v[i] = std::numeric_limits<double>::quiet_NaN(); 1398 } 1399 1400 // Assign provided inputs 1401 for (auto&& e : res) { 1402 M a = e.second; 1403 res_v.at(index_out(e.first)) = a; 1404 } 1405 return res_v; 1406 } 1407 1408 } // namespace casadi 1409 1410 /// \endcond 1411 1412 #endif // CASADI_FUNCTION_INTERNAL_HPP 1413