function_internal.hpp
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  * KU 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 "options.hpp"
35 #include "shared_object.hpp"
36 #include "timing.hpp"
37 #ifdef CASADI_WITH_THREAD
38 #ifdef CASADI_WITH_THREAD_MINGW
39 #include <mingw.mutex.h>
40 #else // CASADI_WITH_THREAD_MINGW
41 #include <mutex>
42 #endif // CASADI_WITH_THREAD_MINGW
43 #endif //CASADI_WITH_THREAD
44 
45 // This macro is for documentation purposes
46 #define INPUTSCHEME(name)
47 
48 // This macro is for documentation purposes
49 #define OUTPUTSCHEME(name)
50 
52 
53 namespace casadi {
54  template<typename T>
55  std::vector<std::pair<std::string, T>> zip(const std::vector<std::string>& id,
56  const std::vector<T>& mat) {
57  casadi_assert_dev(id.size()==mat.size());
58  std::vector<std::pair<std::string, T>> r(id.size());
59  for (casadi_uint i=0; i<r.size(); ++i) r[i] = std::make_pair(id[i], mat[i]);
60  return r;
61  }
62 
66  struct CASADI_EXPORT ProtoFunctionMemory {
67  // Function specific statistics
68  std::map<std::string, FStats> fstats;
69 
70  // Short-hand for "total" fstats
71  FStats* t_total;
72 
73  // Add a statistic
74  void add_stat(const std::string& s) {
75  bool added = fstats.insert(std::make_pair(s, FStats())).second;
76  casadi_assert(added, "Duplicate stat: '" + s + "'");
77  }
78  };
79 
83  struct CASADI_EXPORT FunctionMemory : public ProtoFunctionMemory {
84  bool stats_available;
85  FunctionMemory() : stats_available(false) {}
86  };
87 
94  class CASADI_EXPORT ProtoFunction : public SharedObjectInternal {
95  public:
99  ProtoFunction(const std::string& name);
100 
104  ~ProtoFunction() override = 0;
105 
111  void construct(const Dict& opts);
112 
114 
117  static const Options options_;
118  virtual const Options& get_options() const { return options_;}
120 
122  virtual Dict generate_options(const std::string& target) const;
123 
127  void print_options(std::ostream &stream) const;
128 
132  void print_option(const std::string &name, std::ostream &stream) const;
133 
137  bool has_option(const std::string &option_name) const;
138 
142  virtual void change_option(const std::string& option_name, const GenericType& option_value);
143 
152  virtual void init(const Dict& opts);
153 
160  virtual void finalize();
161 
163  int checkout() const;
164 
166  void release(int mem) const;
167 
169  void* memory(int ind) const;
170 
172  bool has_memory(int ind) const;
173 
179  virtual void check_mem_count(casadi_int n) const { }
180 
184  virtual void* alloc_mem() const { return new ProtoFunctionMemory(); }
185 
189  virtual int init_mem(void* mem) const;
190 
194  virtual void free_mem(void *mem) const { delete static_cast<ProtoFunctionMemory*>(mem); }
195 
197  virtual Dict get_stats(void* mem) const;
198 
202  void clear_mem();
203 
207  void print(const char* fmt, ...) const;
208 
212  void sprint(char* buf, size_t buf_sz, const char* fmt, ...) const;
213 
217  void format_time(char* buffer, double time) const;
218 
222  void print_time(const std::map<std::string, FStats>& fstats) const;
223 
227  void serialize(SerializingStream &s) const;
228 
232  virtual void serialize_body(SerializingStream &s) const;
236  virtual void serialize_type(SerializingStream &s) const {}
237 
241  virtual std::string serialize_base_function() const {
242  return class_name();
243  }
244 
246  std::string name_;
247 
249  bool verbose_;
250 
251  // Print timing statistics
252  bool print_time_;
253 
254  // Print timing statistics
255  bool record_time_;
256 
258  bool regularity_check_;
259 
261  bool error_on_fail_;
262 
263  protected:
267  explicit ProtoFunction(DeserializingStream& s);
268 
269 #ifdef CASADI_WITH_THREAD
271  mutable std::mutex mtx_;
272 #endif // CASADI_WITH_THREAD
273 
274  private:
276  mutable std::vector<void*> mem_;
277 
279  mutable std::stack<int> unused_;
280  };
281 
288  class CASADI_EXPORT FunctionInternal : public ProtoFunction {
289  friend class Function;
290  public:
294  FunctionInternal(const std::string& name);
295 
299  ~FunctionInternal() override = 0;
300 
304  virtual std::string getAdaptorSolverName() const { return ""; }
305 
307 
310  static const Options options_;
311  const Options& get_options() const override { return options_;}
313 
315  Dict generate_options(const std::string& target) const override;
316 
320  void change_option(const std::string& option_name, const GenericType& option_value) override;
321 
325  void init(const Dict& opts) override;
326 
330  void finalize() override;
331 
335  void* alloc_mem() const override { return new FunctionMemory(); }
336 
340  void free_mem(void *mem) const override { delete static_cast<FunctionMemory*>(mem); }
341 
343  Dict get_stats(void* mem) const override;
344 
348  Function self() const { return shared_from_this<Function>();}
349 
350  // Factory
351  virtual Function factory(const std::string& name,
352  const std::vector<std::string>& s_in,
353  const std::vector<std::string>& s_out,
354  const Function::AuxOut& aux,
355  const Dict& opts) const;
356 
357  // Get list of dependency functions
358  virtual std::vector<std::string> get_function() const;
359 
360  // Get a dependency function
361  virtual const Function& get_function(const std::string &name) const;
362 
363  // Check if a particular dependency exists
364  virtual bool has_function(const std::string& fname) const {return false;}
365 
366  // Add embedded function to map, helper function
367  void add_embedded(std::map<FunctionInternal*, Function>& all_fun,
368  const Function& dep, casadi_int max_depth) const;
369 
370  // Get all embedded functions, recursively
371  virtual void find(std::map<FunctionInternal*, Function>& all_fun, casadi_int max_depth) const {}
372 
381  virtual std::vector<bool> which_depends(const std::string& s_in,
382  const std::vector<std::string>& s_out,
383  casadi_int order, bool tr=false) const;
384 
386 
389  virtual bool has_spfwd() const { return false;}
390  virtual bool has_sprev() const { return false;}
392 
394 
397  int eval_gen(const double** arg, double** res, casadi_int* iw, double* w, void* mem,
398  bool always_inline, bool never_inline) const;
399  virtual int eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const;
401 
405  virtual int eval_sx(const SXElem** arg, SXElem** res,
406  casadi_int* iw, SXElem* w, void* mem, bool always_inline, bool never_inline) const;
407 
411  virtual void eval_mx(const MXVector& arg, MXVector& res,
412  bool always_inline, bool never_inline) const;
413 
415 
418  virtual std::vector<DM> eval_dm(const std::vector<DM>& arg) const;
419  virtual bool has_eval_dm() const { return false;}
421 
423 
426  int eval_gen(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w, void* mem,
427  bool always_inline, bool never_inline) const {
428  return eval_sx(arg, res, iw, w, mem, always_inline, never_inline);
429  }
430  int eval_gen(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem,
431  bool always_inline, bool never_inline) const {
432  return sp_forward(arg, res, iw, w, mem);
433  }
435 
437 
440  void call_gen(const MXVector& arg, MXVector& res, casadi_int npar,
441  bool always_inline, bool never_inline) const;
442 
443  template<typename D>
444  void call_gen(const std::vector<Matrix<D> >& arg, std::vector<Matrix<D> >& res,
445  casadi_int npar, bool always_inline, bool never_inline) const;
447 
451  template<typename M>
452  void call(const std::vector<M>& arg, std::vector<M>& res,
453  bool always_inline, bool never_inline) const;
454 
456 
461  static bool check_mat(const Sparsity& arg, const Sparsity& inp, casadi_int& npar);
463 
465 
473  template<typename M>
474  void check_arg(const std::vector<M>& arg, casadi_int& npar) const;
476 
478 
486  template<typename M>
487  void check_res(const std::vector<M>& res, casadi_int& npar) const;
489 
498  template<typename M> bool
499  matching_arg(const std::vector<M>& arg, casadi_int& npar) const;
500 
509  template<typename M> bool
510  matching_res(const std::vector<M>& arg, casadi_int& npar) const;
511 
515  template<typename M> std::vector<M>
516  replace_arg(const std::vector<M>& arg, casadi_int npar) const;
517 
521  template<typename M> std::vector<M>
522  project_arg(const std::vector<M>& arg, casadi_int npar) const;
523 
527  template<typename M> std::vector<M>
528  project_res(const std::vector<M>& arg, casadi_int npar) const;
529 
533  template<typename M> std::vector<M>
534  replace_res(const std::vector<M>& res, casadi_int npar) const;
535 
539  template<typename M> std::vector<std::vector<M>>
540  replace_fseed(const std::vector<std::vector<M>>& fseed, casadi_int npar) const;
541 
545  template<typename M> std::vector<std::vector<M>>
546  replace_aseed(const std::vector<std::vector<M>>& aseed, casadi_int npar) const;
547 
552  template<typename M>
553  std::map<std::string, M> convert_arg(const std::vector<M>& arg) const;
554  template<typename M>
555  std::vector<M> convert_arg(const std::map<std::string, M>& arg) const;
556  template<typename M>
557  std::map<std::string, M> convert_res(const std::vector<M>& res) const;
558  template<typename M>
559  std::vector<M> convert_res(const std::map<std::string, M>& res) const;
561 
566  std::vector<double> nz_in(const std::vector<DM>& arg) const;
567  std::vector<double> nz_out(const std::vector<DM>& res) const;
568  std::vector<DM> nz_in(const std::vector<double>& arg) const;
569  std::vector<DM> nz_out(const std::vector<double>& res) const;
571 
573 
576  virtual void call_forward(const std::vector<MX>& arg, const std::vector<MX>& res,
577  const std::vector<std::vector<MX> >& fseed,
578  std::vector<std::vector<MX> >& fsens,
579  bool always_inline, bool never_inline) const;
580  virtual void call_forward(const std::vector<SX>& arg, const std::vector<SX>& res,
581  const std::vector<std::vector<SX> >& fseed,
582  std::vector<std::vector<SX> >& fsens,
583  bool always_inline, bool never_inline) const;
585 
587 
590  virtual void call_reverse(const std::vector<MX>& arg, const std::vector<MX>& res,
591  const std::vector<std::vector<MX> >& aseed,
592  std::vector<std::vector<MX> >& asens,
593  bool always_inline, bool never_inline) const;
594  virtual void call_reverse(const std::vector<SX>& arg, const std::vector<SX>& res,
595  const std::vector<std::vector<SX> >& aseed,
596  std::vector<std::vector<SX> >& asens,
597  bool always_inline, bool never_inline) const;
599 
603  std::vector<MX> mapsum_mx(const std::vector<MX > &arg, const std::string& parallelization);
604 
608  virtual bool uses_output() const {return false;}
609 
611 
614  Function jacobian() const;
615  virtual bool has_jacobian() const { return false;}
616  virtual Function get_jacobian(const std::string& name,
617  const std::vector<std::string>& inames,
618  const std::vector<std::string>& onames,
619  const Dict& opts) const;
621 
623 
627  Sparsity& jac_sparsity(casadi_int oind, casadi_int iind, bool compact, bool symmetric) const;
628  virtual bool has_jac_sparsity(casadi_int oind, casadi_int iind) const { return false;}
629  virtual Sparsity get_jac_sparsity(casadi_int oind, casadi_int iind, bool symmetric) const;
631 
633  static std::string forward_name(const std::string& fcn, casadi_int nfwd) {
634  return "fwd" + str(nfwd) + "_" + fcn;
635  }
636 
638  std::string diff_prefix(const std::string& prefix) const;
639 
641 
648  Function forward(casadi_int nfwd) const;
649  virtual bool has_forward(casadi_int nfwd) const { return false;}
650  virtual Function get_forward(casadi_int nfwd, const std::string& name,
651  const std::vector<std::string>& inames,
652  const std::vector<std::string>& onames,
653  const Dict& opts) const;
655 
657  static std::string reverse_name(const std::string& fcn, casadi_int nadj) {
658  return "adj" + str(nadj) + "_" + fcn;
659  }
660 
662 
669  Function reverse(casadi_int nadj) const;
670  virtual bool has_reverse(casadi_int nadj) const { return false;}
671  virtual Function get_reverse(casadi_int nadj, const std::string& name,
672  const std::vector<std::string>& inames,
673  const std::vector<std::string>& onames,
674  const Dict& opts) const;
676 
680  template<typename MatType>
681  static MatType ensure_stacked(const MatType& v, const Sparsity& sp, casadi_int n);
682 
686  virtual Function slice(const std::string& name, const std::vector<casadi_int>& order_in,
687  const std::vector<casadi_int>& order_out, const Dict& opts) const;
688 
692  virtual const Function& oracle() const;
693 
697  bool has_derivative() const;
698 
702  virtual double ad_weight() const;
703 
709  virtual double sp_weight() const;
710 
712 
715  virtual const SX sx_in(casadi_int ind) const;
716  virtual const SX sx_out(casadi_int ind) const;
717  virtual const std::vector<SX> sx_in() const;
718  virtual const std::vector<SX> sx_out() const;
719  virtual const MX mx_in(casadi_int ind) const;
720  virtual const MX mx_out(casadi_int ind) const;
721  virtual const std::vector<MX> mx_in() const;
722  virtual const std::vector<MX> mx_out() const;
723  const DM dm_in(casadi_int ind) const;
724  const DM dm_out(casadi_int ind) const;
725  const std::vector<DM> dm_in() const;
726  const std::vector<DM> dm_out() const;
728 
730  virtual std::vector<MX> free_mx() const;
731 
733  virtual std::vector<SX> free_sx() const;
734 
738  virtual bool has_free() const { return false;}
739 
743  virtual void generate_lifted(Function& vdef_fcn, Function& vinit_fcn) const;
744 
748  virtual casadi_int n_instructions() const;
749 
753  virtual casadi_int instruction_id(casadi_int k) const;
754 
758  virtual std::vector<casadi_int> instruction_input(casadi_int k) const;
759 
763  virtual double instruction_constant(casadi_int k) const;
764 
768  virtual std::vector<casadi_int> instruction_output(casadi_int k) const;
769 
773  virtual casadi_int n_nodes() const;
774 
778  virtual MX instruction_MX(casadi_int k) const;
779 
783  virtual SX instructions_sx() const;
784 
788  Function wrap() const;
789 
793  Function wrap_as_needed(const Dict& opts) const;
794 
798  Dict cache() const;
799 
803  bool incache(const std::string& fname, Function& f, const std::string& suffix="") const;
804 
808  void tocache(const Function& f, const std::string& suffix="") const;
809 
810 
814  void tocache_if_missing(Function& f, const std::string& suffix="") const;
815 
819  void codegen(CodeGenerator& g, const std::string& fname) const;
820 
824  void codegen_meta(CodeGenerator& g) const;
825 
829  void codegen_sparsities(CodeGenerator& g) const;
830 
834  virtual std::string codegen_name(const CodeGenerator& g, bool ns=true) const;
835 
839  std::string codegen_mem(CodeGenerator& g, const std::string& index="mem") const;
840 
844  virtual void codegen_incref(CodeGenerator& g) const {}
845 
849  virtual void codegen_decref(CodeGenerator& g) const {}
850 
854  virtual void codegen_alloc_mem(CodeGenerator& g) const;
855 
859  virtual void codegen_init_mem(CodeGenerator& g) const;
860 
864  virtual void codegen_free_mem(CodeGenerator& g) const {}
865 
869  virtual void codegen_checkout(CodeGenerator& g) const;
870 
874  virtual void codegen_release(CodeGenerator& g) const;
875 
879  std::string signature(const std::string& fname) const;
880 
884  std::string signature_unrolled(const std::string& fname) const;
885 
889  virtual void codegen_declarations(CodeGenerator& g) const;
890 
894  virtual void codegen_body(CodeGenerator& g) const;
895 
899  virtual std::string codegen_mem_type() const { return ""; }
900 
904  virtual std::string generate_dependencies(const std::string& fname, const Dict& opts) const;
905 
909  virtual bool has_codegen() const { return false;}
910 
914  virtual void jit_dependencies(const std::string& fname) {}
915 
919  virtual void export_code(const std::string& lang,
920  std::ostream &stream, const Dict& options) const;
921 
925  void serialize_type(SerializingStream &s) const override;
926 
930  void serialize_body(SerializingStream &s) const override;
931 
935  void disp(std::ostream& stream, bool more) const override;
936 
940  virtual void disp_more(std::ostream& stream) const {}
941 
945  std::string definition() const;
946 
950  void print_dimensions(std::ostream &stream) const;
951 
955  virtual std::vector<std::string> get_free() const;
956 
960  void get_partition(casadi_int iind, casadi_int oind, Sparsity& D1, Sparsity& D2,
961  bool compact, bool symmetric,
962  bool allow_forward, bool allow_reverse) const;
963 
965 
968  casadi_int nnz_in() const;
969  casadi_int nnz_in(casadi_int ind) const { return sparsity_in(ind).nnz(); }
970  casadi_int nnz_out() const;
971  casadi_int nnz_out(casadi_int ind) const { return sparsity_out(ind).nnz(); }
973 
975 
978  casadi_int numel_in() const;
979  casadi_int numel_in(casadi_int ind) const { return sparsity_in(ind).numel(); }
980  casadi_int numel_out(casadi_int ind) const { return sparsity_out(ind).numel(); }
981  casadi_int numel_out() const;
983 
985 
988  casadi_int size1_in(casadi_int ind) const { return sparsity_in(ind).size1(); }
989  casadi_int size2_in(casadi_int ind) const { return sparsity_in(ind).size2(); }
990  casadi_int size1_out(casadi_int ind) const { return sparsity_out(ind).size1(); }
991  casadi_int size2_out(casadi_int ind) const { return sparsity_out(ind).size2(); }
992  std::pair<casadi_int, casadi_int> size_in(casadi_int ind) const {
993  return sparsity_in(ind).size();
994  }
995  std::pair<casadi_int, casadi_int> size_out(casadi_int ind) const {
996  return sparsity_out(ind).size();
997  }
999 
1001 
1004  const Sparsity& sparsity_in(casadi_int ind) const { return sparsity_in_.at(ind); }
1005  const Sparsity& sparsity_out(casadi_int ind) const { return sparsity_out_.at(ind); }
1007 
1009 
1012  bool all_scalar() const;
1013 
1015  virtual bool jac_is_symm(casadi_int oind, casadi_int iind) const;
1016 
1018  Sparsity to_compact(casadi_int oind, casadi_int iind, const Sparsity& sp) const;
1019 
1021  Sparsity from_compact(casadi_int oind, casadi_int iind, const Sparsity& sp) const;
1022 
1024  template<bool fwd>
1025  Sparsity get_jac_sparsity_gen(casadi_int oind, casadi_int iind) const;
1026 
1028  Sparsity get_jac_sparsity_hierarchical(casadi_int oind, casadi_int iind) const;
1029 
1033  Sparsity get_jac_sparsity_hierarchical_symm(casadi_int oind, casadi_int iind) const;
1034 
1036  virtual std::vector<MX> symbolic_output(const std::vector<MX>& arg) const;
1037 
1039 
1042  virtual size_t get_n_in();
1043  virtual size_t get_n_out();
1045 
1046 
1048 
1051  virtual std::string get_name_in(casadi_int i);
1052  virtual std::string get_name_out(casadi_int i);
1054 
1058  virtual double get_default_in(casadi_int ind) const {
1059  return 0;
1060  }
1061 
1065  virtual double get_max_in(casadi_int ind) const {
1066  return inf;
1067  }
1068 
1072  virtual double get_min_in(casadi_int ind) const {
1073  return -inf;
1074  }
1075 
1076  virtual std::vector<double> get_nominal_in(casadi_int ind) const {
1077  return std::vector<double>(nnz_in(ind), 1.);
1078  }
1079 
1080  virtual std::vector<double> get_nominal_out(casadi_int ind) const {
1081  return std::vector<double>(nnz_out(ind), 1.);
1082  }
1083 
1087  virtual double get_reltol() const {
1088  return eps;
1089  }
1090 
1094  virtual double get_abstol() const {
1095  return eps;
1096  }
1097 
1101  virtual Sparsity get_sparsity_in(casadi_int i);
1102 
1106  virtual Sparsity get_sparsity_out(casadi_int i);
1107 
1111  virtual bool get_diff_in(casadi_int i) { return true; }
1112 
1116  virtual bool get_diff_out(casadi_int i) { return true; }
1117 
1121  casadi_int index_in(const std::string &name) const {
1122  for (casadi_int i=0; i<name_in_.size(); ++i) {
1123  if (name_in_[i]==name) return i;
1124  }
1125  casadi_error("FunctionInternal::index_in: could not find entry \""
1126  + name + "\". Available names are: " + str(name_in_) + ".");
1127  return -1;
1128  }
1129 
1133  casadi_int index_out(const std::string &name) const {
1134  for (casadi_int i=0; i<name_out_.size(); ++i) {
1135  if (name_out_[i]==name) return i;
1136  }
1137  casadi_error("FunctionInternal::index_out: could not find entry \""
1138  + name + "\". Available names are: " + str(name_out_) + ".");
1139  return -1;
1140  }
1141 
1145  virtual int sp_forward(const bvec_t** arg, bvec_t** res,
1146  casadi_int* iw, bvec_t* w, void* mem) const;
1147 
1151  virtual int sp_forward_block(const bvec_t** arg, bvec_t** res,
1152  casadi_int* iw, bvec_t* w, void* mem, casadi_int oind, casadi_int iind) const;
1153 
1157  virtual int sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const;
1158 
1162  void sz_work(size_t& sz_arg, size_t& sz_res, size_t& sz_iw, size_t& sz_w) const;
1163 
1167  size_t sz_arg() const { return sz_arg_per_ + sz_arg_tmp_;}
1168 
1172  size_t sz_res() const { return sz_res_per_ + sz_res_tmp_;}
1173 
1177  size_t sz_iw() const { return sz_iw_per_ + sz_iw_tmp_;}
1178 
1182  size_t sz_w() const { return sz_w_per_ + sz_w_tmp_;}
1183 
1188  virtual size_t codegen_sz_arg(const CodeGenerator& g) const;
1189  virtual size_t codegen_sz_res(const CodeGenerator& g) const;
1190  virtual size_t codegen_sz_iw(const CodeGenerator& g) const;
1191  virtual size_t codegen_sz_w(const CodeGenerator& g) const;
1193 
1197  void alloc_arg(size_t sz_arg, bool persistent=false);
1198 
1202  void alloc_res(size_t sz_res, bool persistent=false);
1203 
1207  void alloc_iw(size_t sz_iw, bool persistent=false);
1208 
1212  void alloc_w(size_t sz_w, bool persistent=false);
1213 
1217  void alloc(const Function& f, bool persistent=false, int num_threads=1);
1218 
1222  virtual void set_work(void* mem, const double**& arg, double**& res,
1223  casadi_int*& iw, double*& w) const {}
1224 
1228  virtual void set_temp(void* mem, const double** arg, double** res,
1229  casadi_int* iw, double* w) const {}
1230 
1234  void setup(void* mem, const double** arg, double** res, casadi_int* iw, double* w) const;
1235 
1237 
1240  virtual bool fwdViaJac(casadi_int nfwd) const;
1241  virtual bool adjViaJac(casadi_int nadj) const;
1243 
1245  virtual Dict info() const;
1246 
1250  Function map(casadi_int n, const std::string& parallelization) const;
1251 
1255  void generate_in(const std::string& fname, const double** arg) const;
1256  void generate_out(const std::string& fname, double** res) const;
1257 
1258  bool always_inline_, never_inline_;
1259 
1261  size_t n_in_, n_out_;
1262 
1264  std::vector<bool> is_diff_in_, is_diff_out_;
1265 
1267  std::vector<Sparsity> sparsity_in_, sparsity_out_;
1268 
1270  std::vector<std::string> name_in_, name_out_;
1271 
1275  bool jit_;
1276 
1280  bool jit_cleanup_;
1281 
1285  std::string jit_serialize_;
1286 
1290  std::string jit_name_;
1291 
1292  std::string jit_base_name_;
1293 
1297  bool jit_temp_suffix_;
1298 
1302  eval_t eval_;
1303 
1307  casadi_checkout_t checkout_;
1308 
1312  casadi_release_t release_;
1313 
1317  Dict stats_;
1318 
1322  bool has_refcount_;
1323 
1327  Dict cache_init_;
1328 
1330  mutable WeakCache<std::string, Function> cache_;
1331 
1333  mutable std::vector<Sparsity> jac_sparsity_[2];
1334 
1335 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
1337  mutable std::mutex jac_sparsity_mtx_;
1338 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
1339 
1341  Function derivative_of_;
1342 
1344  void* user_data_;
1345 
1347  std::string compiler_plugin_;
1348  Importer compiler_;
1349  Dict jit_options_;
1350 
1352  double jac_penalty_;
1353 
1354  // Types of derivative calculation permitted
1355  bool enable_forward_, enable_reverse_, enable_jacobian_, enable_fd_;
1356  bool enable_forward_op_, enable_reverse_op_, enable_jacobian_op_, enable_fd_op_;
1357 
1359  double ad_weight_, ad_weight_sp_;
1360 
1362  casadi_int max_num_dir_;
1363 
1365  bool inputs_check_;
1366 
1367  // Finite difference step
1368  Dict fd_options_;
1369 
1370  // Finite difference step size
1371  double fd_step_;
1372 
1373  // Finite difference method
1374  std::string fd_method_;
1375 
1376  // Print input/output
1377  bool print_in_;
1378  bool print_out_;
1379 
1380  // Warn when number of inputs or outputs exceed this value
1381  casadi_int max_io_;
1382 
1383  // Dump input/output
1384  bool dump_in_, dump_out_, dump_;
1385 
1386  // Directory to dump to
1387  std::string dump_dir_;
1388 
1389  // Format to dump with
1390  std::string dump_format_;
1391 
1392  // Forward/reverse/Jacobian options
1393  Dict forward_options_, reverse_options_, jacobian_options_, der_options_;
1394 
1395  // Store a reference to a custom Jacobian
1396  Function custom_jacobian_;
1397 
1398  // Counter for unique names for dumping inputs and output
1399 #ifdef CASADI_WITH_THREAD
1400  mutable std::atomic<casadi_int> dump_count_;
1401 #else
1402  mutable casadi_int dump_count_;
1403 #endif // CASADI_WITH_THREAD
1404 
1408  virtual bool is_a(const std::string& type, bool recursive) const;
1409 
1413  virtual void merge(const std::vector<MX>& arg,
1414  std::vector<MX>& subs_from, std::vector<MX>& subs_to) const;
1415 
1419  template<typename MatType>
1420  static bool purgable(const std::vector<MatType>& seed);
1421 
1425  template<typename MatType>
1426  std::vector<std::vector<MatType> >
1427  fwd_seed(casadi_int nfwd) const;
1428 
1432  template<typename MatType>
1433  std::vector<std::vector<MatType> >
1434  symbolicAdjSeed(casadi_int nadj, const std::vector<MatType>& v) const;
1435 
1436  static std::string string_from_UnifiedReturnStatus(UnifiedReturnStatus status);
1437 
1441  explicit FunctionInternal(DeserializingStream& e);
1442 
1446  static Function deserialize(DeserializingStream& s);
1447  static std::map<std::string, ProtoFunction* (*)(DeserializingStream&)> deserialize_map;
1448 
1452  void print_in(std::ostream &stream, const double** arg, bool truncate) const;
1453 
1457  void print_out(std::ostream &stream, double** res, bool truncate) const;
1458 
1459  protected:
1463  void set_jac_sparsity(casadi_int oind, casadi_int iind, const Sparsity& sp);
1464 
1465  private:
1466  // @{
1468  casadi_int get_dump_id() const;
1469  void dump_in(casadi_int id, const double** arg) const;
1470  void dump_out(casadi_int id, double** res) const;
1471  void dump() const;
1472  // @}
1473 
1477  size_t sz_arg_per_, sz_res_per_, sz_iw_per_, sz_w_per_;
1478 
1482  size_t sz_arg_tmp_, sz_res_tmp_, sz_iw_tmp_, sz_w_tmp_;
1483  };
1484 
1485  // Template implementations
1486  template<typename MatType>
1487  bool FunctionInternal::purgable(const std::vector<MatType>& v) {
1488  for (auto i=v.begin(); i!=v.end(); ++i) {
1489  if (!i->is_zero()) return false;
1490  }
1491  return true;
1492  }
1493 
1494  template<typename MatType>
1495  std::vector<std::vector<MatType> >
1496  FunctionInternal::
1497  fwd_seed(casadi_int nfwd) const {
1498  std::vector<std::vector<MatType>> fseed(nfwd);
1499  for (casadi_int dir=0; dir<nfwd; ++dir) {
1500  fseed[dir].resize(n_in_);
1501  for (casadi_int iind=0; iind<n_in_; ++iind) {
1502  std::string n = "f" + str(dir) + "_" + name_in_[iind];
1503  Sparsity sp = is_diff_in_[iind] ? sparsity_in(iind) : Sparsity(size_in(iind));
1504  fseed[dir][iind] = MatType::sym(n, sp);
1505  }
1506  }
1507  return fseed;
1508  }
1509 
1510  template<typename MatType>
1511  std::vector<std::vector<MatType> >
1512  FunctionInternal::
1513  symbolicAdjSeed(casadi_int nadj, const std::vector<MatType>& v) const {
1514  std::vector<std::vector<MatType> > aseed(nadj, v);
1515  for (casadi_int dir=0; dir<nadj; ++dir) {
1516  // Replace symbolic inputs
1517  casadi_int oind=0;
1518  for (typename std::vector<MatType>::iterator i=aseed[dir].begin();
1519  i!=aseed[dir].end();
1520  ++i, ++oind) {
1521  // Name of the adjoint seed
1522  std::stringstream ss;
1523  ss << "a";
1524  if (nadj>1) ss << dir << "_";
1525  ss << oind;
1526 
1527  // Save to matrix
1528  *i = MatType::sym(ss.str(), is_diff_out_[oind] ? i->sparsity() : Sparsity(i->size()));
1529 
1530  }
1531  }
1532  return aseed;
1533  }
1534 
1535  template<typename M>
1536  void FunctionInternal::call(const std::vector<M>& arg, std::vector<M>& res,
1537  bool always_inline, bool never_inline) const {
1538  // If all inputs are scalar ...
1539  if (all_scalar()) {
1540  // ... and some arguments are matrix-valued with matching dimensions ...
1541  bool matrix_call = false;
1542  std::pair<casadi_int, casadi_int> sz;
1543  for (auto&& a : arg) {
1544  if (!a.is_scalar() && !a.is_empty()) {
1545  if (!matrix_call) {
1546  // Matrix call
1547  matrix_call = true;
1548  sz = a.size();
1549  } else if (a.size()!=sz) {
1550  // Not same dimensions
1551  matrix_call = false;
1552  break;
1553  }
1554  }
1555  }
1556 
1557  // ... then, call multiple times
1558  if (matrix_call) {
1559  // Start with zeros
1560  res.resize(n_out_);
1561  M z = M::zeros(sz);
1562  for (auto&& a : res) a = z;
1563  // Call multiple times
1564  std::vector<M> arg1 = arg, res1;
1565  for (casadi_int c=0; c<sz.second; ++c) {
1566  for (casadi_int r=0; r<sz.first; ++r) {
1567  // Get scalar arguments
1568  for (casadi_int i=0; i<arg.size(); ++i) {
1569  if (arg[i].size()==sz) arg1[i] = arg[i](r, c);
1570  }
1571  // Call recursively with scalar arguments
1572  call(arg1, res1, always_inline, never_inline);
1573  // Get results
1574  casadi_assert_dev(res.size() == res1.size());
1575  for (casadi_int i=0; i<res.size(); ++i) res[i](r, c) = res1[i];
1576  }
1577  }
1578  // All elements assigned
1579  return;
1580  }
1581  }
1582 
1583  // Check if inputs need to be replaced
1584  casadi_int npar = 1;
1585  if (!matching_arg(arg, npar)) {
1586  return call(replace_arg(arg, npar), res, always_inline, never_inline);
1587  }
1588 
1589  // Call the type-specific method
1590  call_gen(arg, res, npar, always_inline, never_inline);
1591  }
1592 
1593  template<typename M>
1594  std::vector<M> FunctionInternal::
1595  project_arg(const std::vector<M>& arg, casadi_int npar) const {
1596  casadi_assert_dev(arg.size()==n_in_);
1597 
1598  // Which arguments require mapped evaluation
1599  std::vector<bool> mapped(n_in_);
1600  for (casadi_int i=0; i<n_in_; ++i) {
1601  mapped[i] = arg[i].size2()!=size2_in(i);
1602  }
1603 
1604  // Check if matching input sparsity
1605  std::vector<bool> matching(n_in_);
1606  bool any_mismatch = false;
1607  for (casadi_int i=0; i<n_in_; ++i) {
1608  if (mapped[i]) {
1609  matching[i] = arg[i].sparsity().is_stacked(sparsity_in(i), npar);
1610  } else {
1611  matching[i] = arg[i].sparsity()==sparsity_in(i);
1612  }
1613  any_mismatch = any_mismatch || !matching[i];
1614  }
1615 
1616  // Correct input sparsity
1617  if (any_mismatch) {
1618  std::vector<M> arg2(arg);
1619  for (casadi_int i=0; i<n_in_; ++i) {
1620  if (!matching[i]) {
1621  if (mapped[i]) {
1622  arg2[i] = project(arg2[i], repmat(sparsity_in(i), 1, npar));
1623  } else {
1624  arg2[i] = project(arg2[i], sparsity_in(i));
1625  }
1626  }
1627  }
1628  return arg2;
1629  }
1630  return arg;
1631  }
1632 
1633  template<typename M>
1634  std::vector<M> FunctionInternal::
1635  project_res(const std::vector<M>& arg, casadi_int npar) const {
1636  return arg;
1637  }
1638 
1639  template<typename D>
1640  void FunctionInternal::
1641  call_gen(const std::vector<Matrix<D> >& arg, std::vector<Matrix<D> >& res,
1642  casadi_int npar, bool always_inline, bool never_inline) const {
1643  std::vector< Matrix<D> > arg2 = project_arg(arg, npar);
1644 
1645  // Which arguments require mapped evaluation
1646  std::vector<bool> mapped(n_in_);
1647  for (casadi_int i=0; i<n_in_; ++i) {
1648  mapped[i] = arg[i].size2()!=size2_in(i);
1649  }
1650 
1651  // Allocate results
1652  res.resize(n_out_);
1653  for (casadi_int i=0; i<n_out_; ++i) {
1654  if (!res[i].sparsity().is_stacked(sparsity_out(i), npar)) {
1655  res[i] = Matrix<D>::zeros(repmat(sparsity_out(i), 1, npar));
1656  }
1657  }
1658 
1659  // Allocate temporary memory if needed
1660  std::vector<casadi_int> iw_tmp(sz_iw());
1661  std::vector<D> w_tmp(sz_w());
1662 
1663  // Get pointers to input arguments
1664  std::vector<const D*> argp(sz_arg());
1665  for (casadi_int i=0; i<n_in_; ++i) argp[i]=get_ptr(arg2[i]);
1666 
1667  // Get pointers to output arguments
1668  std::vector<D*> resp(sz_res());
1669  for (casadi_int i=0; i<n_out_; ++i) resp[i]=get_ptr(res[i]);
1670 
1671  // For all parallel calls
1672  for (casadi_int p=0; p<npar; ++p) {
1673  // Call memory-less
1674  if (eval_gen(get_ptr(argp), get_ptr(resp),
1675  get_ptr(iw_tmp), get_ptr(w_tmp), memory(0),
1676  always_inline, never_inline)) {
1677  if (error_on_fail_) casadi_error("Evaluation failed");
1678  }
1679  // Update offsets
1680  if (p==npar-1) break;
1681  for (casadi_int i=0; i<n_in_; ++i) if (mapped[i]) argp[i] += nnz_in(i);
1682  for (casadi_int i=0; i<n_out_; ++i) resp[i] += nnz_out(i);
1683  }
1684  }
1685 
1686  template<typename M>
1687  void FunctionInternal::check_arg(const std::vector<M>& arg, casadi_int& npar) const {
1688  casadi_assert(arg.size()==n_in_, "Incorrect number of inputs: Expected "
1689  + str(n_in_) + ", got " + str(arg.size()));
1690  for (casadi_int i=0; i<n_in_; ++i) {
1691  if (!check_mat(arg[i].sparsity(), sparsity_in(i), npar)) {
1692  // Dimensions
1693  std::string d_arg = str(arg[i].size1()) + "-by-" + str(arg[i].size2());
1694  std::string d_in = str(size1_in(i)) + "-by-" + str(size2_in(i));
1695  std::string e = "Input " + str(i) + " (" + name_in_[i] + ") has mismatching shape. "
1696  "Got " + d_arg + ". Allowed dimensions, in general, are:\n"
1697  " - The input dimension N-by-M (here " + d_in + ")\n"
1698  " - A scalar, i.e. 1-by-1\n"
1699  " - M-by-N if N=1 or M=1 (i.e. a transposed vector)\n"
1700  " - N-by-M1 if K*M1=M for some K (argument repeated horizontally)\n";
1701  if (npar!=-1) {
1702  e += " - N-by-P*M, indicating evaluation with multiple arguments (P must be a "
1703  "multiple of " + str(npar) + " for consistency with previous inputs)";
1704  }
1705  casadi_error(e);
1706  }
1707  }
1708  }
1709 
1710  template<typename M>
1711  void FunctionInternal::check_res(const std::vector<M>& res, casadi_int& npar) const {
1712  casadi_assert(res.size()==n_out_, "Incorrect number of outputs: Expected "
1713  + str(n_out_) + ", got " + str(res.size()));
1714  for (casadi_int i=0; i<n_out_; ++i) {
1715  casadi_assert(check_mat(res[i].sparsity(), sparsity_out(i), npar),
1716  "Output " + str(i) + " (" + name_out_[i] + ") has mismatching shape. "
1717  "Expected " + str(size_out(i)) + ", got " + str(res[i].size()));
1718  }
1719  }
1720 
1721  template<typename M>
1722  bool FunctionInternal::matching_arg(const std::vector<M>& arg, casadi_int& npar) const {
1723  check_arg(arg, npar);
1724  for (casadi_int i=0; i<n_in_; ++i) {
1725  if (arg.at(i).size1()!=size1_in(i)) return false;
1726  if (arg.at(i).size2()!=size2_in(i) && arg.at(i).size2()!=npar*size2_in(i)) return false;
1727  }
1728  return true;
1729  }
1730 
1731  template<typename M>
1732  bool FunctionInternal::matching_res(const std::vector<M>& res, casadi_int& npar) const {
1733  check_res(res, npar);
1734  for (casadi_int i=0; i<n_out_; ++i) {
1735  if (res.at(i).size1()!=size1_out(i)) return false;
1736  if (res.at(i).size2()!=size2_out(i) && res.at(i).size2()!=npar*size2_out(i)) return false;
1737  }
1738  return true;
1739  }
1740 
1741  template<typename M>
1742  M replace_mat(const M& arg, const Sparsity& inp, casadi_int npar) {
1743  if (arg.size()==inp.size()) {
1744  // Matching dimensions already
1745  return arg;
1746  } else if (arg.is_empty()) {
1747  // Empty matrix means set zero
1748  return M(inp.size());
1749  } else if (arg.is_scalar()) {
1750  // Scalar assign means set all
1751  return M(inp, arg);
1752  } else if (arg.is_vector() && inp.size()==std::make_pair(arg.size2(), arg.size1())) {
1753  // Transpose vector
1754  return arg.T();
1755  } else if (arg.size1()==inp.size1() && arg.size2()>0 && inp.size2()>0
1756  && inp.size2()%arg.size2()==0) {
1757  // Horizontal repmat
1758  return repmat(arg, 1, inp.size2()/arg.size2());
1759  } else {
1760  casadi_assert_dev(npar!=-1);
1761  // Multiple evaluation
1762  return repmat(arg, 1, (npar*inp.size2())/arg.size2());
1763  }
1764  }
1765 
1766  template<typename M>
1767  std::vector<M> FunctionInternal::
1768  replace_arg(const std::vector<M>& arg, casadi_int npar) const {
1769  std::vector<M> r(arg.size());
1770  for (casadi_int i=0; i<r.size(); ++i) r[i] = replace_mat(arg[i], sparsity_in(i), npar);
1771  return r;
1772  }
1773 
1774  template<typename M>
1775  std::vector<M> FunctionInternal::
1776  replace_res(const std::vector<M>& res, casadi_int npar) const {
1777  std::vector<M> r(res.size());
1778  for (casadi_int i=0; i<r.size(); ++i) r[i] = replace_mat(res[i], sparsity_out(i), npar);
1779  return r;
1780  }
1781 
1782  template<typename M>
1783  std::vector<std::vector<M> > FunctionInternal::
1784  replace_fseed(const std::vector<std::vector<M> >& fseed, casadi_int npar) const {
1785  std::vector<std::vector<M> > r(fseed.size());
1786  for (casadi_int d=0; d<r.size(); ++d) r[d] = replace_arg(fseed[d], npar);
1787  return r;
1788  }
1789 
1790  template<typename M>
1791  std::vector<std::vector<M> > FunctionInternal::
1792  replace_aseed(const std::vector<std::vector<M> >& aseed, casadi_int npar) const {
1793  std::vector<std::vector<M> > r(aseed.size());
1794  for (casadi_int d=0; d<r.size(); ++d) r[d] = replace_res(aseed[d], npar);
1795  return r;
1796  }
1797 
1798  template<typename M>
1799  std::map<std::string, M> FunctionInternal::
1800  convert_arg(const std::vector<M>& arg) const {
1801  casadi_assert(arg.size()==n_in_, "Incorrect number of inputs: Expected "
1802  + str(n_in_) + ", got " + str(arg.size()));
1803  std::map<std::string, M> ret;
1804  for (casadi_int i=0;i<n_in_;++i) {
1805  ret[name_in_[i]] = arg[i];
1806  }
1807  return ret;
1808  }
1809 
1810  template<typename M>
1811  std::vector<M> FunctionInternal::
1812  convert_arg(const std::map<std::string, M>& arg) const {
1813  // Get default inputs
1814  std::vector<M> arg_v(n_in_);
1815  for (casadi_int i=0; i<arg_v.size(); ++i) {
1816  arg_v[i] = get_default_in(i);
1817  }
1818 
1819  // Assign provided inputs
1820  for (auto&& e : arg) {
1821  arg_v.at(index_in(e.first)) = e.second;
1822  }
1823 
1824  return arg_v;
1825  }
1826 
1827  template<typename M>
1828  std::map<std::string, M> FunctionInternal::
1829  convert_res(const std::vector<M>& res) const {
1830  casadi_assert(res.size()==n_out_, "Incorrect number of outputs: Expected "
1831  + str(n_out_) + ", got " + str(res.size()));
1832  std::map<std::string, M> ret;
1833  for (casadi_int i=0;i<n_out_;++i) {
1834  ret[name_out_[i]] = res[i];
1835  }
1836  return ret;
1837  }
1838 
1839  template<typename M>
1840  std::vector<M> FunctionInternal::
1841  convert_res(const std::map<std::string, M>& res) const {
1842  // Get default inputs
1843  std::vector<M> res_v(n_out_);
1844  for (casadi_int i=0; i<res_v.size(); ++i) {
1845  res_v[i] = std::numeric_limits<double>::quiet_NaN();
1846  }
1847 
1848  // Assign provided inputs
1849  for (auto&& e : res) {
1850  M a = e.second;
1851  res_v.at(index_out(e.first)) = a;
1852  }
1853  return res_v;
1854  }
1855 
1856  template<typename MatType>
1857  MatType FunctionInternal::ensure_stacked(const MatType& v, const Sparsity& sp, casadi_int n) {
1858  // Check dimensions
1859  if (v.size1() == sp.size1() && v.size2() == n * sp.size2()) {
1860  // Ensure that sparsity is a horizontal multiple of original input, or has no entries
1861  if (v.nnz() != 0 && !v.sparsity().is_stacked(sp, n)) {
1862  return project(v, repmat(sp, 1, n));
1863  }
1864  } else {
1865  // Correct empty sparsity
1866  casadi_assert_dev(v.is_empty());
1867  return MatType(sp.size1(), sp.size2() * n);
1868  }
1869  // No correction needed
1870  return v;
1871  }
1872 
1873 } // namespace casadi
1874 
1876 
1877 #endif // CASADI_FUNCTION_INTERNAL_HPP
std::map< std::string, std::vector< std::string > > AuxOut
Definition: function.hpp:404
static Matrix< Scalar > zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
The casadi namespace.
Definition: archiver.hpp:32
std::vector< MX > MXVector
Definition: mx.hpp:1006
Matrix< SXElem > SX
Definition: sx_fwd.hpp:32
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
Matrix< double > DM
Definition: dm_fwd.hpp:33
UnifiedReturnStatus