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_internal.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  };
85 
92  class CASADI_EXPORT ProtoFunction : public SharedObjectInternal {
93  public:
97  ProtoFunction(const std::string& name);
98 
102  ~ProtoFunction() override = 0;
103 
109  void construct(const Dict& opts);
110 
112 
115  static const Options options_;
116  virtual const Options& get_options() const { return options_;}
118 
120  virtual Dict generate_options(const std::string& target) const;
121 
125  void print_options(std::ostream &stream) const;
126 
130  void print_option(const std::string &name, std::ostream &stream) const;
131 
135  bool has_option(const std::string &option_name) const;
136 
140  virtual void change_option(const std::string& option_name, const GenericType& option_value);
141 
150  virtual void init(const Dict& opts);
151 
158  virtual void finalize();
159 
161  int checkout() const;
162 
164  void release(int mem) const;
165 
167  void* memory(int ind) const;
168 
172  virtual void* alloc_mem() const { return new ProtoFunctionMemory(); }
173 
177  virtual int init_mem(void* mem) const;
178 
182  virtual void free_mem(void *mem) const { delete static_cast<ProtoFunctionMemory*>(mem); }
183 
185  virtual Dict get_stats(void* mem) const;
186 
190  void clear_mem();
191 
195  void print(const char* fmt, ...) const;
196 
200  void sprint(char* buf, size_t buf_sz, const char* fmt, ...) const;
201 
205  void format_time(char* buffer, double time) const;
206 
210  void print_time(const std::map<std::string, FStats>& fstats) const;
211 
215  void serialize(SerializingStream &s) const;
216 
220  virtual void serialize_body(SerializingStream &s) const;
224  virtual void serialize_type(SerializingStream &s) const {}
225 
229  virtual std::string serialize_base_function() const {
230  return class_name();
231  }
232 
234  std::string name_;
235 
237  bool verbose_;
238 
239  // Print timing statistics
240  bool print_time_;
241 
242  // Print timing statistics
243  bool record_time_;
244 
246  bool regularity_check_;
247 
249  bool error_on_fail_;
250 
251  protected:
255  explicit ProtoFunction(DeserializingStream& s);
256 
257 #ifdef CASADI_WITH_THREAD
259  mutable std::mutex mtx_;
260 #endif // CASADI_WITH_THREAD
261 
262  private:
264  mutable std::vector<void*> mem_;
265 
267  mutable std::stack<int> unused_;
268  };
269 
276  class CASADI_EXPORT FunctionInternal : public ProtoFunction {
277  friend class Function;
278  public:
282  FunctionInternal(const std::string& name);
283 
287  ~FunctionInternal() override = 0;
288 
292  virtual std::string getAdaptorSolverName() const { return ""; }
293 
295 
298  static const Options options_;
299  const Options& get_options() const override { return options_;}
301 
303  Dict generate_options(const std::string& target) const override;
304 
308  void change_option(const std::string& option_name, const GenericType& option_value) override;
309 
313  void init(const Dict& opts) override;
314 
318  void finalize() override;
319 
323  Function self() const { return shared_from_this<Function>();}
324 
325  // Factory
326  virtual Function factory(const std::string& name,
327  const std::vector<std::string>& s_in,
328  const std::vector<std::string>& s_out,
329  const Function::AuxOut& aux,
330  const Dict& opts) const;
331 
332  // Get list of dependency functions
333  virtual std::vector<std::string> get_function() const;
334 
335  // Get a dependency function
336  virtual const Function& get_function(const std::string &name) const;
337 
338  // Check if a particular dependency exists
339  virtual bool has_function(const std::string& fname) const {return false;}
340 
341  // Add embedded function to map, helper function
342  void add_embedded(std::map<FunctionInternal*, Function>& all_fun,
343  const Function& dep, casadi_int max_depth) const;
344 
345  // Get all embedded functions, recursively
346  virtual void find(std::map<FunctionInternal*, Function>& all_fun, casadi_int max_depth) const {}
347 
356  virtual std::vector<bool> which_depends(const std::string& s_in,
357  const std::vector<std::string>& s_out,
358  casadi_int order, bool tr=false) const;
359 
361 
364  virtual bool has_spfwd() const { return false;}
365  virtual bool has_sprev() const { return false;}
367 
369 
372  int eval_gen(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const;
373  virtual int eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const;
375 
379  virtual int eval_sx(const SXElem** arg, SXElem** res,
380  casadi_int* iw, SXElem* w, void* mem) const;
381 
385  virtual void eval_mx(const MXVector& arg, MXVector& res,
386  bool always_inline, bool never_inline) const;
387 
389 
392  virtual std::vector<DM> eval_dm(const std::vector<DM>& arg) const;
393  virtual bool has_eval_dm() const { return false;}
395 
397 
400  int eval_gen(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w, void* mem) const {
401  return eval_sx(arg, res, iw, w, mem);
402  }
403  int eval_gen(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const {
404  return sp_forward(arg, res, iw, w, mem);
405  }
407 
409 
412  void call_gen(const MXVector& arg, MXVector& res, casadi_int npar,
413  bool always_inline, bool never_inline) const;
414 
415  template<typename D>
416  void call_gen(const std::vector<Matrix<D> >& arg, std::vector<Matrix<D> >& res,
417  casadi_int npar, bool always_inline, bool never_inline) const;
419 
423  template<typename M>
424  void call(const std::vector<M>& arg, std::vector<M>& res,
425  bool always_inline, bool never_inline) const;
426 
428 
433  static bool check_mat(const Sparsity& arg, const Sparsity& inp, casadi_int& npar);
435 
437 
445  template<typename M>
446  void check_arg(const std::vector<M>& arg, casadi_int& npar) const;
448 
450 
458  template<typename M>
459  void check_res(const std::vector<M>& res, casadi_int& npar) const;
461 
470  template<typename M> bool
471  matching_arg(const std::vector<M>& arg, casadi_int& npar) const;
472 
481  template<typename M> bool
482  matching_res(const std::vector<M>& arg, casadi_int& npar) const;
483 
487  template<typename M> std::vector<M>
488  replace_arg(const std::vector<M>& arg, casadi_int npar) const;
489 
493  template<typename M> std::vector<M>
494  project_arg(const std::vector<M>& arg, casadi_int npar) const;
495 
499  template<typename M> std::vector<M>
500  project_res(const std::vector<M>& arg, casadi_int npar) const;
501 
505  template<typename M> std::vector<M>
506  replace_res(const std::vector<M>& res, casadi_int npar) const;
507 
511  template<typename M> std::vector<std::vector<M>>
512  replace_fseed(const std::vector<std::vector<M>>& fseed, casadi_int npar) const;
513 
517  template<typename M> std::vector<std::vector<M>>
518  replace_aseed(const std::vector<std::vector<M>>& aseed, casadi_int npar) const;
519 
524  template<typename M>
525  std::map<std::string, M> convert_arg(const std::vector<M>& arg) const;
526  template<typename M>
527  std::vector<M> convert_arg(const std::map<std::string, M>& arg) const;
528  template<typename M>
529  std::map<std::string, M> convert_res(const std::vector<M>& res) const;
530  template<typename M>
531  std::vector<M> convert_res(const std::map<std::string, M>& res) const;
533 
538  std::vector<double> nz_in(const std::vector<DM>& arg) const;
539  std::vector<double> nz_out(const std::vector<DM>& res) const;
540  std::vector<DM> nz_in(const std::vector<double>& arg) const;
541  std::vector<DM> nz_out(const std::vector<double>& res) const;
543 
545 
548  virtual void call_forward(const std::vector<MX>& arg, const std::vector<MX>& res,
549  const std::vector<std::vector<MX> >& fseed,
550  std::vector<std::vector<MX> >& fsens,
551  bool always_inline, bool never_inline) const;
552  virtual void call_forward(const std::vector<SX>& arg, const std::vector<SX>& res,
553  const std::vector<std::vector<SX> >& fseed,
554  std::vector<std::vector<SX> >& fsens,
555  bool always_inline, bool never_inline) const;
557 
559 
562  virtual void call_reverse(const std::vector<MX>& arg, const std::vector<MX>& res,
563  const std::vector<std::vector<MX> >& aseed,
564  std::vector<std::vector<MX> >& asens,
565  bool always_inline, bool never_inline) const;
566  virtual void call_reverse(const std::vector<SX>& arg, const std::vector<SX>& res,
567  const std::vector<std::vector<SX> >& aseed,
568  std::vector<std::vector<SX> >& asens,
569  bool always_inline, bool never_inline) const;
571 
575  std::vector<MX> mapsum_mx(const std::vector<MX > &arg, const std::string& parallelization);
576 
580  virtual bool uses_output() const {return false;}
581 
583 
586  Function jacobian() const;
587  virtual bool has_jacobian() const { return false;}
588  virtual Function get_jacobian(const std::string& name,
589  const std::vector<std::string>& inames,
590  const std::vector<std::string>& onames,
591  const Dict& opts) const;
593 
595 
599  Sparsity& jac_sparsity(casadi_int oind, casadi_int iind, bool compact, bool symmetric) const;
600  virtual bool has_jac_sparsity(casadi_int oind, casadi_int iind) const { return false;}
601  virtual Sparsity get_jac_sparsity(casadi_int oind, casadi_int iind, bool symmetric) const;
603 
605  static std::string forward_name(const std::string& fcn, casadi_int nfwd) {
606  return "fwd" + str(nfwd) + "_" + fcn;
607  }
608 
610  std::string diff_prefix(const std::string& prefix) const;
611 
613 
620  Function forward(casadi_int nfwd) const;
621  virtual bool has_forward(casadi_int nfwd) const { return false;}
622  virtual Function get_forward(casadi_int nfwd, const std::string& name,
623  const std::vector<std::string>& inames,
624  const std::vector<std::string>& onames,
625  const Dict& opts) const;
627 
629  static std::string reverse_name(const std::string& fcn, casadi_int nadj) {
630  return "adj" + str(nadj) + "_" + fcn;
631  }
632 
634 
641  Function reverse(casadi_int nadj) const;
642  virtual bool has_reverse(casadi_int nadj) const { return false;}
643  virtual Function get_reverse(casadi_int nadj, const std::string& name,
644  const std::vector<std::string>& inames,
645  const std::vector<std::string>& onames,
646  const Dict& opts) const;
648 
652  template<typename MatType>
653  static MatType ensure_stacked(const MatType& v, const Sparsity& sp, casadi_int n);
654 
658  virtual Function slice(const std::string& name, const std::vector<casadi_int>& order_in,
659  const std::vector<casadi_int>& order_out, const Dict& opts) const;
660 
664  virtual const Function& oracle() const;
665 
669  bool has_derivative() const;
670 
674  virtual double ad_weight() const;
675 
681  virtual double sp_weight() const;
682 
684 
687  virtual const SX sx_in(casadi_int ind) const;
688  virtual const SX sx_out(casadi_int ind) const;
689  virtual const std::vector<SX> sx_in() const;
690  virtual const std::vector<SX> sx_out() const;
691  virtual const MX mx_in(casadi_int ind) const;
692  virtual const MX mx_out(casadi_int ind) const;
693  virtual const std::vector<MX> mx_in() const;
694  virtual const std::vector<MX> mx_out() const;
695  const DM dm_in(casadi_int ind) const;
696  const DM dm_out(casadi_int ind) const;
697  const std::vector<DM> dm_in() const;
698  const std::vector<DM> dm_out() const;
700 
702  virtual std::vector<MX> free_mx() const;
703 
705  virtual std::vector<SX> free_sx() const;
706 
710  virtual bool has_free() const { return false;}
711 
715  virtual void generate_lifted(Function& vdef_fcn, Function& vinit_fcn) const;
716 
720  virtual casadi_int n_instructions() const;
721 
725  virtual casadi_int instruction_id(casadi_int k) const;
726 
730  virtual std::vector<casadi_int> instruction_input(casadi_int k) const;
731 
735  virtual double instruction_constant(casadi_int k) const;
736 
740  virtual std::vector<casadi_int> instruction_output(casadi_int k) const;
741 
745  virtual casadi_int n_nodes() const;
746 
750  virtual MX instruction_MX(casadi_int k) const;
751 
755  virtual SX instructions_sx() const;
756 
760  Function wrap() const;
761 
765  Function wrap_as_needed(const Dict& opts) const;
766 
770  Dict cache() const;
771 
775  bool incache(const std::string& fname, Function& f, const std::string& suffix="") const;
776 
780  void tocache(const Function& f, const std::string& suffix="") const;
781 
785  void codegen(CodeGenerator& g, const std::string& fname) const;
786 
790  void codegen_meta(CodeGenerator& g) const;
791 
795  void codegen_sparsities(CodeGenerator& g) const;
796 
800  virtual std::string codegen_name(const CodeGenerator& g, bool ns=true) const;
801 
805  std::string codegen_mem(CodeGenerator& g, const std::string& index="mem") const;
806 
810  virtual void codegen_incref(CodeGenerator& g) const {}
811 
815  virtual void codegen_decref(CodeGenerator& g) const {}
816 
820  virtual void codegen_alloc_mem(CodeGenerator& g) const;
821 
825  virtual void codegen_init_mem(CodeGenerator& g) const;
826 
830  virtual void codegen_free_mem(CodeGenerator& g) const {}
831 
835  virtual void codegen_checkout(CodeGenerator& g) const;
836 
840  virtual void codegen_release(CodeGenerator& g) const;
841 
845  std::string signature(const std::string& fname) const;
846 
850  std::string signature_unrolled(const std::string& fname) const;
851 
855  virtual void codegen_declarations(CodeGenerator& g) const;
856 
860  virtual void codegen_body(CodeGenerator& g) const;
861 
865  virtual std::string codegen_mem_type() const { return ""; }
866 
870  virtual std::string generate_dependencies(const std::string& fname, const Dict& opts) const;
871 
875  virtual bool has_codegen() const { return false;}
876 
880  virtual void jit_dependencies(const std::string& fname) {}
881 
885  virtual void export_code(const std::string& lang,
886  std::ostream &stream, const Dict& options) const;
887 
891  void serialize_type(SerializingStream &s) const override;
892 
896  void serialize_body(SerializingStream &s) const override;
897 
901  void disp(std::ostream& stream, bool more) const override;
902 
906  virtual void disp_more(std::ostream& stream) const {}
907 
911  std::string definition() const;
912 
916  void print_dimensions(std::ostream &stream) const;
917 
921  virtual std::vector<std::string> get_free() const;
922 
926  void get_partition(casadi_int iind, casadi_int oind, Sparsity& D1, Sparsity& D2,
927  bool compact, bool symmetric,
928  bool allow_forward, bool allow_reverse) const;
929 
931 
934  casadi_int nnz_in() const;
935  casadi_int nnz_in(casadi_int ind) const { return sparsity_in(ind).nnz(); }
936  casadi_int nnz_out() const;
937  casadi_int nnz_out(casadi_int ind) const { return sparsity_out(ind).nnz(); }
939 
941 
944  casadi_int numel_in() const;
945  casadi_int numel_in(casadi_int ind) const { return sparsity_in(ind).numel(); }
946  casadi_int numel_out(casadi_int ind) const { return sparsity_out(ind).numel(); }
947  casadi_int numel_out() const;
949 
951 
954  casadi_int size1_in(casadi_int ind) const { return sparsity_in(ind).size1(); }
955  casadi_int size2_in(casadi_int ind) const { return sparsity_in(ind).size2(); }
956  casadi_int size1_out(casadi_int ind) const { return sparsity_out(ind).size1(); }
957  casadi_int size2_out(casadi_int ind) const { return sparsity_out(ind).size2(); }
958  std::pair<casadi_int, casadi_int> size_in(casadi_int ind) const {
959  return sparsity_in(ind).size();
960  }
961  std::pair<casadi_int, casadi_int> size_out(casadi_int ind) const {
962  return sparsity_out(ind).size();
963  }
965 
967 
970  const Sparsity& sparsity_in(casadi_int ind) const { return sparsity_in_.at(ind); }
971  const Sparsity& sparsity_out(casadi_int ind) const { return sparsity_out_.at(ind); }
973 
975 
978  bool all_scalar() const;
979 
981  virtual bool jac_is_symm(casadi_int oind, casadi_int iind) const;
982 
984  Sparsity to_compact(casadi_int oind, casadi_int iind, const Sparsity& sp) const;
985 
987  Sparsity from_compact(casadi_int oind, casadi_int iind, const Sparsity& sp) const;
988 
990  template<bool fwd>
991  Sparsity get_jac_sparsity_gen(casadi_int oind, casadi_int iind) const;
992 
994  Sparsity get_jac_sparsity_hierarchical(casadi_int oind, casadi_int iind) const;
995 
999  Sparsity get_jac_sparsity_hierarchical_symm(casadi_int oind, casadi_int iind) const;
1000 
1002  virtual std::vector<MX> symbolic_output(const std::vector<MX>& arg) const;
1003 
1005 
1008  virtual size_t get_n_in();
1009  virtual size_t get_n_out();
1011 
1012 
1014 
1017  virtual std::string get_name_in(casadi_int i);
1018  virtual std::string get_name_out(casadi_int i);
1020 
1024  virtual double get_default_in(casadi_int ind) const {
1025  return 0;
1026  }
1027 
1031  virtual double get_max_in(casadi_int ind) const {
1032  return inf;
1033  }
1034 
1038  virtual double get_min_in(casadi_int ind) const {
1039  return -inf;
1040  }
1041 
1042  virtual std::vector<double> get_nominal_in(casadi_int ind) const {
1043  return std::vector<double>(nnz_in(ind), 1.);
1044  }
1045 
1046  virtual std::vector<double> get_nominal_out(casadi_int ind) const {
1047  return std::vector<double>(nnz_out(ind), 1.);
1048  }
1049 
1053  virtual double get_reltol() const {
1054  return eps;
1055  }
1056 
1060  virtual double get_abstol() const {
1061  return eps;
1062  }
1063 
1067  virtual Sparsity get_sparsity_in(casadi_int i);
1068 
1072  virtual Sparsity get_sparsity_out(casadi_int i);
1073 
1077  virtual bool get_diff_in(casadi_int i) { return true; }
1078 
1082  virtual bool get_diff_out(casadi_int i) { return true; }
1083 
1087  casadi_int index_in(const std::string &name) const {
1088  for (casadi_int i=0; i<name_in_.size(); ++i) {
1089  if (name_in_[i]==name) return i;
1090  }
1091  casadi_error("FunctionInternal::index_in: could not find entry \""
1092  + name + "\". Available names are: " + str(name_in_) + ".");
1093  return -1;
1094  }
1095 
1099  casadi_int index_out(const std::string &name) const {
1100  for (casadi_int i=0; i<name_out_.size(); ++i) {
1101  if (name_out_[i]==name) return i;
1102  }
1103  casadi_error("FunctionInternal::index_out: could not find entry \""
1104  + name + "\". Available names are: " + str(name_out_) + ".");
1105  return -1;
1106  }
1107 
1111  virtual int sp_forward(const bvec_t** arg, bvec_t** res,
1112  casadi_int* iw, bvec_t* w, void* mem) const;
1113 
1117  virtual int sp_forward_block(const bvec_t** arg, bvec_t** res,
1118  casadi_int* iw, bvec_t* w, void* mem, casadi_int oind, casadi_int iind) const;
1119 
1123  virtual int sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const;
1124 
1128  void sz_work(size_t& sz_arg, size_t& sz_res, size_t& sz_iw, size_t& sz_w) const;
1129 
1133  size_t sz_arg() const { return sz_arg_per_ + sz_arg_tmp_;}
1134 
1138  size_t sz_res() const { return sz_res_per_ + sz_res_tmp_;}
1139 
1143  size_t sz_iw() const { return sz_iw_per_ + sz_iw_tmp_;}
1144 
1148  size_t sz_w() const { return sz_w_per_ + sz_w_tmp_;}
1149 
1153  void alloc_arg(size_t sz_arg, bool persistent=false);
1154 
1158  void alloc_res(size_t sz_res, bool persistent=false);
1159 
1163  void alloc_iw(size_t sz_iw, bool persistent=false);
1164 
1168  void alloc_w(size_t sz_w, bool persistent=false);
1169 
1173  void alloc(const Function& f, bool persistent=false, int num_threads=1);
1174 
1178  virtual void set_work(void* mem, const double**& arg, double**& res,
1179  casadi_int*& iw, double*& w) const {}
1180 
1184  virtual void set_temp(void* mem, const double** arg, double** res,
1185  casadi_int* iw, double* w) const {}
1186 
1190  void setup(void* mem, const double** arg, double** res, casadi_int* iw, double* w) const;
1191 
1193 
1196  virtual bool fwdViaJac(casadi_int nfwd) const;
1197  virtual bool adjViaJac(casadi_int nadj) const;
1199 
1201  virtual Dict info() const;
1202 
1206  Function map(casadi_int n, const std::string& parallelization) const;
1207 
1211  void generate_in(const std::string& fname, const double** arg) const;
1212  void generate_out(const std::string& fname, double** res) const;
1213 
1214  bool always_inline_, never_inline_;
1215 
1217  size_t n_in_, n_out_;
1218 
1220  std::vector<bool> is_diff_in_, is_diff_out_;
1221 
1223  std::vector<Sparsity> sparsity_in_, sparsity_out_;
1224 
1226  std::vector<std::string> name_in_, name_out_;
1227 
1231  bool jit_;
1232 
1236  bool jit_cleanup_;
1237 
1241  std::string jit_serialize_;
1242 
1246  std::string jit_name_;
1247 
1248  std::string jit_base_name_;
1249 
1253  bool jit_temp_suffix_;
1254 
1258  eval_t eval_;
1259 
1263  casadi_checkout_t checkout_;
1264 
1268  casadi_release_t release_;
1269 
1273  Dict stats_;
1274 
1278  bool has_refcount_;
1279 
1283  Dict cache_init_;
1284 
1286  mutable std::map<std::string, WeakRef> cache_;
1287 
1289  mutable std::vector<Sparsity> jac_sparsity_[2];
1290 
1292  Function derivative_of_;
1293 
1295  void* user_data_;
1296 
1298  std::string compiler_plugin_;
1299  Importer compiler_;
1300  Dict jit_options_;
1301 
1303  double jac_penalty_;
1304 
1305  // Types of derivative calculation permitted
1306  bool enable_forward_, enable_reverse_, enable_jacobian_, enable_fd_;
1307  bool enable_forward_op_, enable_reverse_op_, enable_jacobian_op_, enable_fd_op_;
1308 
1310  double ad_weight_, ad_weight_sp_;
1311 
1313  casadi_int max_num_dir_;
1314 
1316  bool inputs_check_;
1317 
1318  // Finite difference step
1319  Dict fd_options_;
1320 
1321  // Finite difference step size
1322  double fd_step_;
1323 
1324  // Finite difference method
1325  std::string fd_method_;
1326 
1327  // Print input/output
1328  bool print_in_;
1329  bool print_out_;
1330 
1331  // Warn when number of inputs or outputs exceed this value
1332  casadi_int max_io_;
1333 
1334  // Dump input/output
1335  bool dump_in_, dump_out_, dump_;
1336 
1337  // Directory to dump to
1338  std::string dump_dir_;
1339 
1340  // Format to dump with
1341  std::string dump_format_;
1342 
1343  // Forward/reverse/Jacobian options
1344  Dict forward_options_, reverse_options_, jacobian_options_, der_options_;
1345 
1346  // Store a reference to a custom Jacobian
1347  Function custom_jacobian_;
1348 
1349  // Counter for unique names for dumping inputs and output
1350  mutable casadi_int dump_count_ = 0;
1351 #ifdef CASADI_WITH_THREAD
1352  mutable std::mutex dump_count_mtx_;
1353 #endif // CASADI_WITH_THREAD
1354 
1358  virtual bool is_a(const std::string& type, bool recursive) const;
1359 
1363  template<typename MatType>
1364  static bool purgable(const std::vector<MatType>& seed);
1365 
1369  template<typename MatType>
1370  std::vector<std::vector<MatType> >
1371  fwd_seed(casadi_int nfwd) const;
1372 
1376  template<typename MatType>
1377  std::vector<std::vector<MatType> >
1378  symbolicAdjSeed(casadi_int nadj, const std::vector<MatType>& v) const;
1379 
1380  static std::string string_from_UnifiedReturnStatus(UnifiedReturnStatus status);
1381 
1385  explicit FunctionInternal(DeserializingStream& e);
1386 
1390  static Function deserialize(DeserializingStream& s);
1391  static std::map<std::string, ProtoFunction* (*)(DeserializingStream&)> deserialize_map;
1392 
1396  void print_in(std::ostream &stream, const double** arg, bool truncate) const;
1397 
1401  void print_out(std::ostream &stream, double** res, bool truncate) const;
1402 
1403  protected:
1407  void set_jac_sparsity(casadi_int oind, casadi_int iind, const Sparsity& sp);
1408 
1409  private:
1410  // @{
1412  casadi_int get_dump_id() const;
1413  void dump_in(casadi_int id, const double** arg) const;
1414  void dump_out(casadi_int id, double** res) const;
1415  void dump() const;
1416  // @}
1417 
1421  size_t sz_arg_per_, sz_res_per_, sz_iw_per_, sz_w_per_;
1422 
1426  size_t sz_arg_tmp_, sz_res_tmp_, sz_iw_tmp_, sz_w_tmp_;
1427  };
1428 
1429  // Template implementations
1430  template<typename MatType>
1431  bool FunctionInternal::purgable(const std::vector<MatType>& v) {
1432  for (auto i=v.begin(); i!=v.end(); ++i) {
1433  if (!i->is_zero()) return false;
1434  }
1435  return true;
1436  }
1437 
1438  template<typename MatType>
1439  std::vector<std::vector<MatType> >
1440  FunctionInternal::
1441  fwd_seed(casadi_int nfwd) const {
1442  std::vector<std::vector<MatType>> fseed(nfwd);
1443  for (casadi_int dir=0; dir<nfwd; ++dir) {
1444  fseed[dir].resize(n_in_);
1445  for (casadi_int iind=0; iind<n_in_; ++iind) {
1446  std::string n = "f" + str(dir) + "_" + name_in_[iind];
1447  Sparsity sp = is_diff_in_[iind] ? sparsity_in(iind) : Sparsity(size_in(iind));
1448  fseed[dir][iind] = MatType::sym(n, sp);
1449  }
1450  }
1451  return fseed;
1452  }
1453 
1454  template<typename MatType>
1455  std::vector<std::vector<MatType> >
1456  FunctionInternal::
1457  symbolicAdjSeed(casadi_int nadj, const std::vector<MatType>& v) const {
1458  std::vector<std::vector<MatType> > aseed(nadj, v);
1459  for (casadi_int dir=0; dir<nadj; ++dir) {
1460  // Replace symbolic inputs
1461  casadi_int oind=0;
1462  for (typename std::vector<MatType>::iterator i=aseed[dir].begin();
1463  i!=aseed[dir].end();
1464  ++i, ++oind) {
1465  // Name of the adjoint seed
1466  std::stringstream ss;
1467  ss << "a";
1468  if (nadj>1) ss << dir << "_";
1469  ss << oind;
1470 
1471  // Save to matrix
1472  *i = MatType::sym(ss.str(), is_diff_out_[oind] ? i->sparsity() : Sparsity(i->size()));
1473 
1474  }
1475  }
1476  return aseed;
1477  }
1478 
1479  template<typename M>
1480  void FunctionInternal::call(const std::vector<M>& arg, std::vector<M>& res,
1481  bool always_inline, bool never_inline) const {
1482  // If all inputs are scalar ...
1483  if (all_scalar()) {
1484  // ... and some arguments are matrix-valued with matching dimensions ...
1485  bool matrix_call = false;
1486  std::pair<casadi_int, casadi_int> sz;
1487  for (auto&& a : arg) {
1488  if (!a.is_scalar() && !a.is_empty()) {
1489  if (!matrix_call) {
1490  // Matrix call
1491  matrix_call = true;
1492  sz = a.size();
1493  } else if (a.size()!=sz) {
1494  // Not same dimensions
1495  matrix_call = false;
1496  break;
1497  }
1498  }
1499  }
1500 
1501  // ... then, call multiple times
1502  if (matrix_call) {
1503  // Start with zeros
1504  res.resize(n_out_);
1505  M z = M::zeros(sz);
1506  for (auto&& a : res) a = z;
1507  // Call multiple times
1508  std::vector<M> arg1 = arg, res1;
1509  for (casadi_int c=0; c<sz.second; ++c) {
1510  for (casadi_int r=0; r<sz.first; ++r) {
1511  // Get scalar arguments
1512  for (casadi_int i=0; i<arg.size(); ++i) {
1513  if (arg[i].size()==sz) arg1[i] = arg[i](r, c);
1514  }
1515  // Call recursively with scalar arguments
1516  call(arg1, res1, always_inline, never_inline);
1517  // Get results
1518  casadi_assert_dev(res.size() == res1.size());
1519  for (casadi_int i=0; i<res.size(); ++i) res[i](r, c) = res1[i];
1520  }
1521  }
1522  // All elements assigned
1523  return;
1524  }
1525  }
1526 
1527  // Check if inputs need to be replaced
1528  casadi_int npar = 1;
1529  if (!matching_arg(arg, npar)) {
1530  return call(replace_arg(arg, npar), res, always_inline, never_inline);
1531  }
1532 
1533  // Call the type-specific method
1534  call_gen(arg, res, npar, always_inline, never_inline);
1535  }
1536 
1537  template<typename M>
1538  std::vector<M> FunctionInternal::
1539  project_arg(const std::vector<M>& arg, casadi_int npar) const {
1540  casadi_assert_dev(arg.size()==n_in_);
1541 
1542  // Which arguments require mapped evaluation
1543  std::vector<bool> mapped(n_in_);
1544  for (casadi_int i=0; i<n_in_; ++i) {
1545  mapped[i] = arg[i].size2()!=size2_in(i);
1546  }
1547 
1548  // Check if matching input sparsity
1549  std::vector<bool> matching(n_in_);
1550  bool any_mismatch = false;
1551  for (casadi_int i=0; i<n_in_; ++i) {
1552  if (mapped[i]) {
1553  matching[i] = arg[i].sparsity().is_stacked(sparsity_in(i), npar);
1554  } else {
1555  matching[i] = arg[i].sparsity()==sparsity_in(i);
1556  }
1557  any_mismatch = any_mismatch || !matching[i];
1558  }
1559 
1560  // Correct input sparsity
1561  if (any_mismatch) {
1562  std::vector<M> arg2(arg);
1563  for (casadi_int i=0; i<n_in_; ++i) {
1564  if (!matching[i]) {
1565  if (mapped[i]) {
1566  arg2[i] = project(arg2[i], repmat(sparsity_in(i), 1, npar));
1567  } else {
1568  arg2[i] = project(arg2[i], sparsity_in(i));
1569  }
1570  }
1571  }
1572  return arg2;
1573  }
1574  return arg;
1575  }
1576 
1577  template<typename M>
1578  std::vector<M> FunctionInternal::
1579  project_res(const std::vector<M>& arg, casadi_int npar) const {
1580  return arg;
1581  }
1582 
1583  template<typename D>
1584  void FunctionInternal::
1585  call_gen(const std::vector<Matrix<D> >& arg, std::vector<Matrix<D> >& res,
1586  casadi_int npar, bool always_inline, bool never_inline) const {
1587  casadi_assert(!never_inline, "Call-nodes only possible in MX expressions");
1588  std::vector< Matrix<D> > arg2 = project_arg(arg, npar);
1589 
1590  // Which arguments require mapped evaluation
1591  std::vector<bool> mapped(n_in_);
1592  for (casadi_int i=0; i<n_in_; ++i) {
1593  mapped[i] = arg[i].size2()!=size2_in(i);
1594  }
1595 
1596  // Allocate results
1597  res.resize(n_out_);
1598  for (casadi_int i=0; i<n_out_; ++i) {
1599  if (!res[i].sparsity().is_stacked(sparsity_out(i), npar)) {
1600  res[i] = Matrix<D>::zeros(repmat(sparsity_out(i), 1, npar));
1601  }
1602  }
1603 
1604  // Allocate temporary memory if needed
1605  std::vector<casadi_int> iw_tmp(sz_iw());
1606  std::vector<D> w_tmp(sz_w());
1607 
1608  // Get pointers to input arguments
1609  std::vector<const D*> argp(sz_arg());
1610  for (casadi_int i=0; i<n_in_; ++i) argp[i]=get_ptr(arg2[i]);
1611 
1612  // Get pointers to output arguments
1613  std::vector<D*> resp(sz_res());
1614  for (casadi_int i=0; i<n_out_; ++i) resp[i]=get_ptr(res[i]);
1615 
1616  // For all parallel calls
1617  for (casadi_int p=0; p<npar; ++p) {
1618  // Call memory-less
1619  if (eval_gen(get_ptr(argp), get_ptr(resp),
1620  get_ptr(iw_tmp), get_ptr(w_tmp), memory(0))) {
1621  if (error_on_fail_) casadi_error("Evaluation failed");
1622  }
1623  // Update offsets
1624  if (p==npar-1) break;
1625  for (casadi_int i=0; i<n_in_; ++i) if (mapped[i]) argp[i] += nnz_in(i);
1626  for (casadi_int i=0; i<n_out_; ++i) resp[i] += nnz_out(i);
1627  }
1628  }
1629 
1630  template<typename M>
1631  void FunctionInternal::check_arg(const std::vector<M>& arg, casadi_int& npar) const {
1632  casadi_assert(arg.size()==n_in_, "Incorrect number of inputs: Expected "
1633  + str(n_in_) + ", got " + str(arg.size()));
1634  for (casadi_int i=0; i<n_in_; ++i) {
1635  if (!check_mat(arg[i].sparsity(), sparsity_in(i), npar)) {
1636  // Dimensions
1637  std::string d_arg = str(arg[i].size1()) + "-by-" + str(arg[i].size2());
1638  std::string d_in = str(size1_in(i)) + "-by-" + str(size2_in(i));
1639  std::string e = "Input " + str(i) + " (" + name_in_[i] + ") has mismatching shape. "
1640  "Got " + d_arg + ". Allowed dimensions, in general, are:\n"
1641  " - The input dimension N-by-M (here " + d_in + ")\n"
1642  " - A scalar, i.e. 1-by-1\n"
1643  " - M-by-N if N=1 or M=1 (i.e. a transposed vector)\n"
1644  " - N-by-M1 if K*M1=M for some K (argument repeated horizontally)\n";
1645  if (npar!=-1) {
1646  e += " - N-by-P*M, indicating evaluation with multiple arguments (P must be a "
1647  "multiple of " + str(npar) + " for consistency with previous inputs)";
1648  }
1649  casadi_error(e);
1650  }
1651  }
1652  }
1653 
1654  template<typename M>
1655  void FunctionInternal::check_res(const std::vector<M>& res, casadi_int& npar) const {
1656  casadi_assert(res.size()==n_out_, "Incorrect number of outputs: Expected "
1657  + str(n_out_) + ", got " + str(res.size()));
1658  for (casadi_int i=0; i<n_out_; ++i) {
1659  casadi_assert(check_mat(res[i].sparsity(), sparsity_out(i), npar),
1660  "Output " + str(i) + " (" + name_out_[i] + ") has mismatching shape. "
1661  "Expected " + str(size_out(i)) + ", got " + str(res[i].size()));
1662  }
1663  }
1664 
1665  template<typename M>
1666  bool FunctionInternal::matching_arg(const std::vector<M>& arg, casadi_int& npar) const {
1667  check_arg(arg, npar);
1668  for (casadi_int i=0; i<n_in_; ++i) {
1669  if (arg.at(i).size1()!=size1_in(i)) return false;
1670  if (arg.at(i).size2()!=size2_in(i) && arg.at(i).size2()!=npar*size2_in(i)) return false;
1671  }
1672  return true;
1673  }
1674 
1675  template<typename M>
1676  bool FunctionInternal::matching_res(const std::vector<M>& res, casadi_int& npar) const {
1677  check_res(res, npar);
1678  for (casadi_int i=0; i<n_out_; ++i) {
1679  if (res.at(i).size1()!=size1_out(i)) return false;
1680  if (res.at(i).size2()!=size2_out(i) && res.at(i).size2()!=npar*size2_out(i)) return false;
1681  }
1682  return true;
1683  }
1684 
1685  template<typename M>
1686  M replace_mat(const M& arg, const Sparsity& inp, casadi_int npar) {
1687  if (arg.size()==inp.size()) {
1688  // Matching dimensions already
1689  return arg;
1690  } else if (arg.is_empty()) {
1691  // Empty matrix means set zero
1692  return M(inp.size());
1693  } else if (arg.is_scalar()) {
1694  // Scalar assign means set all
1695  return M(inp, arg);
1696  } else if (arg.is_vector() && inp.size()==std::make_pair(arg.size2(), arg.size1())) {
1697  // Transpose vector
1698  return arg.T();
1699  } else if (arg.size1()==inp.size1() && arg.size2()>0 && inp.size2()>0
1700  && inp.size2()%arg.size2()==0) {
1701  // Horizontal repmat
1702  return repmat(arg, 1, inp.size2()/arg.size2());
1703  } else {
1704  casadi_assert_dev(npar!=-1);
1705  // Multiple evaluation
1706  return repmat(arg, 1, (npar*inp.size2())/arg.size2());
1707  }
1708  }
1709 
1710  template<typename M>
1711  std::vector<M> FunctionInternal::
1712  replace_arg(const std::vector<M>& arg, casadi_int npar) const {
1713  std::vector<M> r(arg.size());
1714  for (casadi_int i=0; i<r.size(); ++i) r[i] = replace_mat(arg[i], sparsity_in(i), npar);
1715  return r;
1716  }
1717 
1718  template<typename M>
1719  std::vector<M> FunctionInternal::
1720  replace_res(const std::vector<M>& res, casadi_int npar) const {
1721  std::vector<M> r(res.size());
1722  for (casadi_int i=0; i<r.size(); ++i) r[i] = replace_mat(res[i], sparsity_out(i), npar);
1723  return r;
1724  }
1725 
1726  template<typename M>
1727  std::vector<std::vector<M> > FunctionInternal::
1728  replace_fseed(const std::vector<std::vector<M> >& fseed, casadi_int npar) const {
1729  std::vector<std::vector<M> > r(fseed.size());
1730  for (casadi_int d=0; d<r.size(); ++d) r[d] = replace_arg(fseed[d], npar);
1731  return r;
1732  }
1733 
1734  template<typename M>
1735  std::vector<std::vector<M> > FunctionInternal::
1736  replace_aseed(const std::vector<std::vector<M> >& aseed, casadi_int npar) const {
1737  std::vector<std::vector<M> > r(aseed.size());
1738  for (casadi_int d=0; d<r.size(); ++d) r[d] = replace_res(aseed[d], npar);
1739  return r;
1740  }
1741 
1742  template<typename M>
1743  std::map<std::string, M> FunctionInternal::
1744  convert_arg(const std::vector<M>& arg) const {
1745  casadi_assert(arg.size()==n_in_, "Incorrect number of inputs: Expected "
1746  + str(n_in_) + ", got " + str(arg.size()));
1747  std::map<std::string, M> ret;
1748  for (casadi_int i=0;i<n_in_;++i) {
1749  ret[name_in_[i]] = arg[i];
1750  }
1751  return ret;
1752  }
1753 
1754  template<typename M>
1755  std::vector<M> FunctionInternal::
1756  convert_arg(const std::map<std::string, M>& arg) const {
1757  // Get default inputs
1758  std::vector<M> arg_v(n_in_);
1759  for (casadi_int i=0; i<arg_v.size(); ++i) {
1760  arg_v[i] = get_default_in(i);
1761  }
1762 
1763  // Assign provided inputs
1764  for (auto&& e : arg) {
1765  arg_v.at(index_in(e.first)) = e.second;
1766  }
1767 
1768  return arg_v;
1769  }
1770 
1771  template<typename M>
1772  std::map<std::string, M> FunctionInternal::
1773  convert_res(const std::vector<M>& res) const {
1774  casadi_assert(res.size()==n_out_, "Incorrect number of outputs: Expected "
1775  + str(n_out_) + ", got " + str(res.size()));
1776  std::map<std::string, M> ret;
1777  for (casadi_int i=0;i<n_out_;++i) {
1778  ret[name_out_[i]] = res[i];
1779  }
1780  return ret;
1781  }
1782 
1783  template<typename M>
1784  std::vector<M> FunctionInternal::
1785  convert_res(const std::map<std::string, M>& res) const {
1786  // Get default inputs
1787  std::vector<M> res_v(n_out_);
1788  for (casadi_int i=0; i<res_v.size(); ++i) {
1789  res_v[i] = std::numeric_limits<double>::quiet_NaN();
1790  }
1791 
1792  // Assign provided inputs
1793  for (auto&& e : res) {
1794  M a = e.second;
1795  res_v.at(index_out(e.first)) = a;
1796  }
1797  return res_v;
1798  }
1799 
1800  template<typename MatType>
1801  MatType FunctionInternal::ensure_stacked(const MatType& v, const Sparsity& sp, casadi_int n) {
1802  // Check dimensions
1803  if (v.size1() == sp.size1() && v.size2() == n * sp.size2()) {
1804  // Ensure that sparsity is a horizontal multiple of original input, or has no entries
1805  if (v.nnz() != 0 && !v.sparsity().is_stacked(sp, n)) {
1806  return project(v, repmat(sp, 1, n));
1807  }
1808  } else {
1809  // Correct empty sparsity
1810  casadi_assert_dev(v.is_empty());
1811  return MatType(sp.size1(), sp.size2() * n);
1812  }
1813  // No correction needed
1814  return v;
1815  }
1816 
1817 } // namespace casadi
1818 
1820 
1821 #endif // CASADI_FUNCTION_INTERNAL_HPP
std::map< std::string, std::vector< std::string > > AuxOut
Definition: function.hpp:395
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.
std::vector< MX > MXVector
Definition: mx.hpp:940
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