sx_function.hpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 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_SX_FUNCTION_HPP
27 #define CASADI_SX_FUNCTION_HPP
28 
29 #include "x_function.hpp"
30 
32 
33 namespace casadi {
37  struct ScalarAtomic {
38  int op;
39  int i0;
40  union {
41  double d;
42  struct { int i1, i2; };
43  };
44  };
45 
53 class CASADI_EXPORT SXFunction :
54  public XFunction<SXFunction, Matrix<SXElem>, SXNode>{
55  public:
59  SXFunction(const std::string& name,
60  const std::vector<Matrix<SXElem> >& inputv,
61  const std::vector<Matrix<SXElem> >& outputv,
62  const std::vector<std::string>& name_in,
63  const std::vector<std::string>& name_out);
64 
68  ~SXFunction() override;
69 
73  int eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const override;
74 
75  void trace_instruction(std::ostream& trace, casadi_int k, const double* w,
76  bool output) const;
77 
81  int eval_sx(const SXElem** arg, SXElem** res,
82  casadi_int* iw, SXElem* w, void* mem,
83  bool always_inline, bool never_inline) const override;
84 
88  void eval_mx(const MXVector& arg, MXVector& res,
89  bool always_inline, bool never_inline) const override;
90 
92  bool should_inline(bool with_sx, bool always_inline, bool never_inline) const override;
93 
97  void ad_forward(const std::vector<std::vector<SX> >& fseed,
98  std::vector<std::vector<SX> >& fsens) const;
99 
103  void ad_reverse(const std::vector<std::vector<SX> >& aseed,
104  std::vector<std::vector<SX> >& asens) const;
105 
109  bool is_smooth() const;
110 
111  // print an element of an algorithm
112  std::string print(const ScalarAtomic& a) const;
113 
114  // Print the input arguments of an instruction
115  void print_arg(std::ostream &stream, casadi_int k, const ScalarAtomic& el,
116  const double* w) const;
117 
118  // Print the input arguments of an instruction
119  void print_arg(CodeGenerator& g, casadi_int k, const ScalarAtomic& el) const;
120 
121  // Print the output arguments of an instruction
122  void print_res(std::ostream &stream, casadi_int k, const ScalarAtomic& el,
123  const double* w) const;
124 
125  // Print the output arguments of an instruction
126  void print_res(CodeGenerator& g, casadi_int k, const ScalarAtomic& el) const;
127 
131  void disp_more(std::ostream& stream) const override;
132 
136  std::string class_name() const override {return "SXFunction";}
137 
141  bool is_a(const std::string& type, bool recursive) const override;
142 
144 
147  const SX sx_in(casadi_int ind) const override;
148  const std::vector<SX> sx_in() const override;
150 
152  std::vector<SX> free_sx() const override {
153  std::vector<SX> ret(free_vars_.size());
154  std::copy(free_vars_.begin(), free_vars_.end(), ret.begin());
155  return ret;
156  }
157 
161  bool has_free() const override { return !free_vars_.empty();}
162 
166  std::vector<std::string> get_free() const override {
167  std::vector<std::string> ret;
168  for (auto&& e : free_vars_) ret.push_back(e.name());
169  return ret;
170  }
171 
175  std::vector<std::string> get_function() const override;
176 
180  const Function& get_function(const std::string &name) const override;
181 
185  SX hess(casadi_int iind=0, casadi_int oind=0);
186 
190  casadi_int n_instructions() const override { return algorithm_.size();}
191 
195  casadi_int instruction_id(casadi_int k) const override { return algorithm_.at(k).op;}
196 
200  std::vector<casadi_int> instruction_input(casadi_int k) const override {
201  auto e = algorithm_.at(k);
202  if (e.op==OP_CALL) {
203  const ExtendedAlgEl& m = call_.el[e.i1];
204  return vector_static_cast<casadi_int>(m.dep);
205  } else if (casadi_math<double>::ndeps(e.op)==2 || e.op==OP_INPUT) {
206  return {e.i1, e.i2};
207  } else if (casadi_math<double>::ndeps(e.op)==1) {
208  return {e.i1};
209  } else {
210  return {};
211  }
212  }
213 
217  double instruction_constant(casadi_int k) const override {
218  return algorithm_.at(k).d;
219  }
220 
224  std::vector<casadi_int> instruction_output(casadi_int k) const override {
225  auto e = algorithm_.at(k);
226  if (e.op==OP_CALL) {
227  const ExtendedAlgEl& m = call_.el[e.i1];
228  return vector_static_cast<casadi_int>(m.res);
229  } else if (e.op==OP_OUTPUT) {
230  return {e.i0, e.i2};
231  } else {
232  return {e.i0};
233  }
234  }
235 
239  casadi_int n_nodes() const override { return algorithm_.size() - nnz_out();}
240 
248  typedef ScalarAtomic AlgEl;
249 
253  template<typename T>
254  struct TapeEl {
255  T d[2];
256  };
257 
261  std::vector<AlgEl> algorithm_;
262 
263  // Work vector size
264  size_t worksize_;
265 
267  std::vector<SXElem> free_vars_;
268 
270  std::vector<SXElem> operations_;
271 
273  std::vector<SXElem> constants_;
274 
276  std::vector<double> default_in_;
277 
279  std::vector<bool> copy_elision_;
280 
282  bool print_instructions_;
283  bool dump_trace_ = false;
284 
288  void serialize_body(SerializingStream &s) const override;
289 
290  // call node information that won't fit into AlgEl
291  struct ExtendedAlgEl {
292  ExtendedAlgEl(const Function& fun);
293  Function f;
294  // Work vector indices of the arguments (cfr AlgEl::arg)
295  std::vector<int> dep;
296  // Work vector indices of the results (cfr AlgEl::res)
297  std::vector<int> res;
298 
299  std::vector<int> copy_elision_arg;
300  std::vector<int> copy_elision_offset;
301 
302  // Following fields are redundant but will increase eval speed
303  casadi_int n_dep;
304  casadi_int n_res;
305  casadi_int f_n_in;
306  casadi_int f_n_out;
307  std::vector<int> f_nnz_in;
308  std::vector<int> f_nnz_out;
309  };
310 
312  struct CallInfo {
313  // Maximum memory requirements across all call nodes
314  size_t sz_arg = 0, sz_res = 0, sz_iw = 0, sz_w = 0;
315  size_t sz_w_arg = 0, sz_w_res = 0;
316  std::vector<ExtendedAlgEl> el;
317  } call_;
318 
322  static ProtoFunction* deserialize(DeserializingStream& s);
323 
324  static std::vector<SX> order(const std::vector<SX>& expr);
325 
327 
330  static const Options options_;
331  const Options& get_options() const override { return options_;}
333 
335  Dict generate_options(const std::string& target="clone") const override;
336 
340  void init(const Dict& opts) override;
341 
345  void init_copy_elision();
346 
350  size_t codegen_sz_w(const CodeGenerator& g) const override;
351 
355  void codegen_declarations(CodeGenerator& g) const override;
356 
360  void codegen_body(CodeGenerator& g) const override;
361 
365  int sp_forward(const bvec_t** arg, bvec_t** res,
366  casadi_int* iw, bvec_t* w, void* mem) const override;
367 
371  int eval_activity(const bvec_t** arg, bvec_t** res,
372  casadi_int* iw, bvec_t* w, void* mem) const override;
373 
377  int sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const override;
378 
382  SX instructions_sx() const override;
383 
384  // Get all embedded functions, recursively
385  void find(std::map<FunctionInternal*, std::pair<Function, size_t> >& all_fun,
386  casadi_int max_depth) const override;
387 
391  void change_option(const std::string& option_name, const GenericType& option_value) override;
392 
396  double get_default_in(casadi_int ind) const override { return default_in_.at(ind);}
397 
401  void export_code_body(const std::string& lang,
402  std::ostream &stream, const Dict& options) const override;
403 
405  bool just_in_time_opencl_;
406 
408  bool just_in_time_sparsity_;
409 
411  bool live_variables_;
412 
413 protected:
414  template<typename T>
415  void call_fwd(const AlgEl& e, const T** arg, T** res, casadi_int* iw, T* w) const;
416 
417  // Activity propagation through a call node
418  void call_activity(const AlgEl& e, const bvec_t** arg, bvec_t** res,
419  casadi_int* iw, bvec_t* w) const;
420 
421  template<typename T>
422  void call_rev(const AlgEl& e, T** arg, T** res, casadi_int* iw, T* w) const;
423 
424  template<typename T, typename CT>
425  void call_setup(const ExtendedAlgEl& m,
426  CT*** call_arg, T*** call_res, casadi_int** call_iw, T** call_w, T** nz_in, T** nz_out) const;
427 
431  explicit SXFunction(DeserializingStream& s);
432 };
433 
434 
435 } // namespace casadi
436 
438 #endif // CASADI_SX_FUNCTION_HPP
The casadi namespace.
Definition: archiver.hpp:32
std::vector< MX > MXVector
Definition: mx.hpp:1107
Matrix< SXElem > SX
Definition: sx_fwd.hpp:32
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.