function_internal.cpp
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, Kobe Bergmans
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 #include "function_internal.hpp"
27 #include "casadi_call.hpp"
28 #include "call_sx.hpp"
29 #include "casadi_misc.hpp"
30 #include "global_options.hpp"
31 #include "external.hpp"
32 #include "finite_differences.hpp"
33 #include "serializing_stream.hpp"
34 #include "mx_function.hpp"
35 #include "sx_function.hpp"
36 #include "rootfinder_impl.hpp"
37 #include "map.hpp"
38 #include "mapsum.hpp"
39 #include "switch.hpp"
40 #include "interpolant_impl.hpp"
41 #include "nlpsol_impl.hpp"
42 #include "conic_impl.hpp"
43 #include "integrator_impl.hpp"
44 #include "external_impl.hpp"
45 #include "fmu_function.hpp"
46 #include "blazing_spline_impl.hpp"
47 #include "onnx_function_impl.hpp"
48 #include "filesystem_impl.hpp"
49 
50 #include <cctype>
51 #include <typeinfo>
52 #ifdef WITH_DL
53 #include <cstdlib>
54 #include <ctime>
55 #endif // WITH_DL
56 #include <iomanip>
57 
58 namespace casadi {
59 
60  ProtoFunction::ProtoFunction(const std::string& name) : name_(name) {
61  // Default options (can be overridden in derived classes)
62  verbose_ = false;
63  print_time_ = false;
64  record_time_ = false;
65  regularity_check_ = false;
66  error_on_fail_ = true;
67  }
68 
69  FunctionInternal::FunctionInternal(const std::string& name) : ProtoFunction(name) {
70  // Make sure valid function name
72  casadi_error("Function name is not valid. A valid function name is a std::string "
73  "starting with a letter followed by letters, numbers or "
74  "non-consecutive underscores. It may also not match the keywords "
75  "'null', 'jac' or 'hess'. Got '" + name_ + "'");
76  }
77 
78  // By default, reverse mode is about twice as expensive as forward mode
79  ad_weight_ = 0.33; // i.e. nf <= 2*na <=> 1/3*nf <= (1-1/3)*na, forward when tie
80  // Both modes equally expensive by default (no "taping" needed)
81  ad_weight_sp_ = 0.49; // Forward when tie
82  always_inline_ = false;
83  never_inline_ = false;
84  jac_penalty_ = 2;
86  user_data_ = nullptr;
87  inputs_check_ = true;
88  jit_ = false;
89  jit_cleanup_ = true;
90  jit_serialize_ = "source";
91  jit_base_name_ = "jit_tmp";
92  jit_temp_suffix_ = true;
93  compiler_plugin_ = CASADI_STR(CASADI_DEFAULT_COMPILER_PLUGIN);
94 
95  eval_ = nullptr;
96  checkout_ = nullptr;
97  release_ = nullptr;
98  incref_ = nullptr;
99  decref_ = nullptr;
100  has_refcount_ = false;
101  enable_forward_op_ = true;
102  enable_reverse_op_ = true;
103  enable_jacobian_op_ = true;
104  enable_fd_op_ = false;
105  print_in_ = false;
106  print_out_ = false;
107  print_canonical_ = false;
108  max_io_ = 10000;
109  dump_in_ = false;
110  dump_out_ = false;
111  dump_dir_ = ".";
112  dump_format_ = "mtx";
113  dump_ = false;
114  sz_arg_tmp_ = 0;
115  sz_res_tmp_ = 0;
116  sz_iw_tmp_ = 0;
117  sz_w_tmp_ = 0;
118  sz_arg_per_ = 0;
119  sz_res_per_ = 0;
120  sz_iw_per_ = 0;
121  sz_w_per_ = 0;
122 
123  dump_count_ = 0;
124  }
125 
127  for (void* m : mem_) {
128  if (m!=nullptr) casadi_warning("Memory object has not been properly freed");
129  }
130  mem_.clear();
131  }
132 
134  if (decref_) decref_();
135  if (jit_cleanup_ && jit_) {
136  std::string jit_name = jit_directory_ + jit_name_ + ".c";
137  if (remove(jit_name.c_str())) casadi_warning("Failed to remove " + jit_name);
138  }
139  }
140 
141  void ProtoFunction::construct(const Dict& opts) {
142  // Sanitize dictionary is needed
143  if (!Options::is_sane(opts)) {
144  // Call recursively
146  return;
147  }
148 
149  // Make sure all options exist
150  get_options().check(opts);
151 
152  // Initialize the class hierarchy
153  try {
154  init(opts);
155  } catch(std::exception& e) {
156  casadi_error("Error calling " + class_name() + "::init for '" + name_ + "':\n"
157  + std::string(e.what()));
158  }
159 
160  // Revisit class hierarchy in reverse order
161  try {
162  finalize();
163  } catch(std::exception& e) {
164  casadi_error("Error calling " + class_name() + "::finalize for '" + name_ + "':\n"
165  + std::string(e.what()));
166  }
167  }
168 
170  = {{},
171  {{"verbose",
172  {OT_BOOL,
173  "Verbose evaluation -- for debugging"}},
174  {"print_time",
175  {OT_BOOL,
176  "print information about execution time. Implies record_time."}},
177  {"record_time",
178  {OT_BOOL,
179  "record information about execution time, for retrieval with stats()."}},
180  {"regularity_check",
181  {OT_BOOL,
182  "Throw exceptions when NaN or Inf appears during evaluation"}},
183  {"error_on_fail",
184  {OT_BOOL,
185  "Throw exceptions when function evaluation fails (default true)."}}
186  }
187  };
188 
189  const Options FunctionInternal::options_
191  {{"ad_weight",
192  {OT_DOUBLE,
193  "Weighting factor for derivative calculation."
194  "When there is an option of either using forward or reverse mode "
195  "directional derivatives, the condition ad_weight*nf<=(1-ad_weight)*na "
196  "is used where nf and na are estimates of the number of forward/reverse "
197  "mode directional derivatives needed. By default, ad_weight is calculated "
198  "automatically, but this can be overridden by setting this option. "
199  "In particular, 0 means forcing forward mode and 1 forcing reverse mode. "
200  "Leave unset for (class specific) heuristics."}},
201  {"ad_weight_sp",
202  {OT_DOUBLE,
203  "Weighting factor for sparsity pattern calculation calculation."
204  "Overrides default behavior. Set to 0 and 1 to force forward and "
205  "reverse mode respectively. Cf. option \"ad_weight\". "
206  "When set to -1, sparsity is completely ignored and dense matrices are used."}},
207  {"always_inline",
208  {OT_BOOL,
209  "Force inlining."}},
210  {"never_inline",
211  {OT_BOOL,
212  "Forbid inlining."}},
213  {"jac_penalty",
214  {OT_DOUBLE,
215  "When requested for a number of forward/reverse directions, "
216  "it may be cheaper to compute first the full jacobian and then "
217  "multiply with seeds, rather than obtain the requested directions "
218  "in a straightforward manner. "
219  "Casadi uses a heuristic to decide which is cheaper. "
220  "A high value of 'jac_penalty' makes it less likely for the heurstic "
221  "to chose the full Jacobian strategy. "
222  "The special value -1 indicates never to use the full Jacobian strategy"}},
223  {"user_data",
224  {OT_VOIDPTR,
225  "A user-defined field that can be used to identify "
226  "the function or pass additional information"}},
227  {"inputs_check",
228  {OT_BOOL,
229  "Throw exceptions when the numerical values of the inputs don't make sense"}},
230  {"gather_stats",
231  {OT_BOOL,
232  "Deprecated option (ignored): Statistics are now always collected."}},
233  {"jit",
234  {OT_BOOL,
235  "Use just-in-time compiler to speed up the evaluation"}},
236  {"jit_cleanup",
237  {OT_BOOL,
238  "Cleanup up the temporary source file that jit creates. Default: true"}},
239  {"jit_serialize",
240  {OT_STRING,
241  "Specify behaviour when serializing a jitted function: SOURCE|link|embed."}},
242  {"jit_name",
243  {OT_STRING,
244  "The file name used to write out code. "
245  "The actual file names used depend on 'jit_temp_suffix' and include extensions. "
246  "Default: 'jit_tmp'"}},
247  {"jit_temp_suffix",
248  {OT_BOOL,
249  "Use a temporary (seemingly random) filename suffix for generated code and libraries. "
250  "This is desired for thread-safety. "
251  "This behaviour may defeat caching compiler wrappers. "
252  "Default: true"}},
253  {"compiler",
254  {OT_STRING,
255  "Just-in-time compiler plugin to be used."}},
256  {"jit_options",
257  {OT_DICT,
258  "Options to be passed to the jit compiler."}},
259  {"codegen_options",
260  {OT_DICT,
261  "Options to be passed to the code generator of jit, e.g. {\"stats\": true} to "
262  "record statistics inside the compiled code. Default: none"}},
263  {"derivative_of",
264  {OT_FUNCTION,
265  "The function is a derivative of another function. "
266  "The type of derivative (directional derivative, Jacobian) "
267  "is inferred from the function name."}},
268  {"max_num_dir",
269  {OT_INT,
270  "Specify the maximum number of directions for derivative functions."
271  " Overrules the builtin optimized_num_dir."}},
272  {"enable_forward",
273  {OT_BOOL,
274  "Enable derivative calculation using generated functions for"
275  " Jacobian-times-vector products - typically using forward mode AD"
276  " - if available. [default: true]"}},
277  {"enable_reverse",
278  {OT_BOOL,
279  "Enable derivative calculation using generated functions for"
280  " transposed Jacobian-times-vector products - typically using reverse mode AD"
281  " - if available. [default: true]"}},
282  {"enable_jacobian",
283  {OT_BOOL,
284  "Enable derivative calculation using generated functions for"
285  " Jacobians of all differentiable outputs with respect to all differentiable inputs"
286  " - if available. [default: true]"}},
287  {"enable_fd",
288  {OT_BOOL,
289  "Enable derivative calculation by finite differencing. [default: false]]"}},
290  {"fd_options",
291  {OT_DICT,
292  "Options to be passed to the finite difference instance"}},
293  {"fd_method",
294  {OT_STRING,
295  "Method for finite differencing [default 'central']"}},
296  {"print_in",
297  {OT_BOOL,
298  "Print numerical values of inputs [default: false]"}},
299  {"print_out",
300  {OT_BOOL,
301  "Print numerical values of outputs [default: false]"}},
302  {"print_canonical",
303  {OT_BOOL,
304  "When printing numerical matrices, use a format that is "
305  "exact and reproducible in generated C code."}},
306  {"max_io",
307  {OT_INT,
308  "Acceptable number of inputs and outputs. Warn if exceeded."}},
309  {"dump_in",
310  {OT_BOOL,
311  "Dump numerical values of inputs to file (readable with DM.from_file) [default: false] "
312  "A counter is used to generate unique names. "
313  "The counter may be reset using reset_dump_count."}},
314  {"dump_out",
315  {OT_BOOL,
316  "Dump numerical values of outputs to file (readable with DM.from_file) [default: false] "
317  "A counter is used to generate unique names. "
318  "The counter may be reset using reset_dump_count."}},
319  {"dump",
320  {OT_BOOL,
321  "Dump function to file upon first evaluation. [false]"}},
322  {"dump_dir",
323  {OT_STRING,
324  "Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]"}},
325  {"dump_format",
326  {OT_STRING,
327  "Choose file format to dump matrices. See DM.from_file [mtx]"}},
328  {"forward_options",
329  {OT_DICT,
330  "Options to be passed to a forward mode constructor"}},
331  {"reverse_options",
332  {OT_DICT,
333  "Options to be passed to a reverse mode constructor"}},
334  {"jacobian_options",
335  {OT_DICT,
336  "Options to be passed to a Jacobian constructor"}},
337  {"der_options",
338  {OT_DICT,
339  "Default options to be used to populate forward_options, reverse_options, and "
340  "jacobian_options before those options are merged in."}},
341  {"custom_jacobian",
342  {OT_FUNCTION,
343  "Override CasADi's AD. Use together with 'jac_penalty': 0. "
344  "Note: Highly experimental. Syntax may break often."}},
345  {"is_diff_in",
346  {OT_BOOLVECTOR,
347  "Indicate for each input if it should be differentiable."}},
348  {"is_diff_out",
349  {OT_BOOLVECTOR,
350  "Indicate for each output if it should be differentiable."}},
351  {"post_expand",
352  {OT_BOOL,
353  "After construction, expand this Function. Default: False"}},
354  {"post_expand_options",
355  {OT_DICT,
356  "Options to be passed to post-construction expansion. Default: empty"}},
357  {"cache",
358  {OT_DICT,
359  "Prepopulate the function cache. Default: empty"}},
360  {"external_transform",
362  "List of external_transform instruction arguments. Default: empty"}}
363  }
364  };
365 
366  void ProtoFunction::init(const Dict& opts) {
367  // Read options
368  for (auto&& op : opts) {
369  if (op.first=="verbose") {
370  verbose_ = op.second;
371  } else if (op.first=="print_time") {
372  print_time_ = op.second;
373  } else if (op.first=="record_time") {
374  record_time_ = op.second;
375  } else if (op.first=="regularity_check") {
376  regularity_check_ = op.second;
377  } else if (op.first=="error_on_fail") {
378  error_on_fail_ = op.second;
379  }
380  }
381  }
382 
383  Dict ProtoFunction::generate_options(const std::string& target) const {
384  Dict opts;
385  opts["verbose"] = verbose_;
386  opts["print_time"] = print_time_;
387  opts["record_time"] = record_time_;
388  opts["regularity_check"] = regularity_check_;
389  opts["error_on_fail"] = error_on_fail_;
390  return opts;
391  }
392 
393  Dict FunctionInternal::generate_options(const std::string& target) const {
394  Dict opts = ProtoFunction::generate_options(target);
395  opts["jac_penalty"] = jac_penalty_;
396  opts["user_data"] = user_data_;
397  opts["inputs_check"] = inputs_check_;
398  if (target!="tmp") opts["jit"] = jit_;
399  opts["jit_cleanup"] = jit_cleanup_;
400  opts["jit_serialize"] = jit_serialize_;
401  opts["compiler"] = compiler_plugin_;
402  opts["jit_options"] = jit_options_;
403  opts["codegen_options"] = codegen_options_;
404  opts["jit_name"] = jit_base_name_;
405  opts["jit_temp_suffix"] = jit_temp_suffix_;
406  opts["ad_weight"] = ad_weight_;
407  opts["ad_weight_sp"] = ad_weight_sp_;
408  opts["always_inline"] = always_inline_;
409  opts["never_inline"] = never_inline_;
410  opts["max_num_dir"] = max_num_dir_;
411  if (target=="clone" || target=="tmp") {
412  opts["enable_forward"] = enable_forward_op_;
413  opts["enable_reverse"] = enable_reverse_op_;
414  opts["enable_jacobian"] = enable_jacobian_op_;
415  opts["enable_fd"] = enable_fd_op_;
416  opts["reverse_options"] = reverse_options_;
417  opts["forward_options"] = forward_options_;
418  opts["jacobian_options"] = jacobian_options_;
419  opts["der_options"] = der_options_;
420  opts["derivative_of"] = derivative_of_;
421  }
422  opts["fd_options"] = fd_options_;
423  opts["fd_method"] = fd_method_;
424  opts["print_in"] = print_in_;
425  opts["print_out"] = print_out_;
426  opts["print_canonical"] = print_canonical_;
427  opts["max_io"] = max_io_;
428  opts["dump_in"] = dump_in_;
429  opts["dump_out"] = dump_out_;
430  opts["dump_dir"] = dump_dir_;
431  opts["dump_format"] = dump_format_;
432  opts["dump"] = dump_;
433  if (target=="clone") {
434  opts["is_diff_in"] = is_diff_in_;
435  opts["is_diff_out"] = is_diff_out_;
436  }
437  if (target=="forward") {
438  opts["is_diff_in"] = join(is_diff_in_, is_diff_out_, is_diff_in_);
439  opts["is_diff_out"] = is_diff_out_;
440  }
441  if (target=="reverse") {
442  opts["is_diff_in"] = join(is_diff_in_, is_diff_out_, is_diff_out_);
443  opts["is_diff_out"] = is_diff_in_;
444  }
445  return opts;
446  }
447 
448  void FunctionInternal::change_option(const std::string& option_name,
449  const GenericType& option_value) {
450  if (option_name == "print_in") {
451  print_in_ = option_value;
452  } else if (option_name == "print_out") {
453  print_out_ = option_value;
454  } else if (option_name == "print_canonical") {
455  print_canonical_ = option_value;
456  } else if (option_name=="ad_weight") {
457  ad_weight_ = option_value;
458  } else if (option_name=="ad_weight_sp") {
459  ad_weight_sp_ = option_value;
460  } else if (option_name=="dump") {
461  dump_ = option_value;
462  } else if (option_name=="dump_in") {
463  dump_in_ = option_value;
464  } else if (option_name=="dump_out") {
465  dump_out_ = option_value;
466  } else if (option_name=="dump_dir") {
467  dump_dir_ = option_value.to_string();
468  } else if (option_name=="dump_format") {
469  dump_format_ = option_value.to_string();
470  } else {
471  // Option not found - continue to base classes
472  ProtoFunction::change_option(option_name, option_value);
473  }
474  }
475 
477  dump_count_ = 0;
478  }
479 
480  void FunctionInternal::init(const Dict& opts) {
481  // Call the initialization method of the base class
482  ProtoFunction::init(opts);
483 
484  // Default options
485  fd_step_ = 1e-8;
486 
487  // Read options
488  for (auto&& op : opts) {
489  if (op.first=="jac_penalty") {
490  jac_penalty_ = op.second;
491  } else if (op.first=="user_data") {
492  user_data_ = op.second.to_void_pointer();
493  } else if (op.first=="inputs_check") {
494  inputs_check_ = op.second;
495  } else if (op.first=="gather_stats") {
496  casadi_warning("Deprecated option \"gather_stats\": Always enabled");
497  } else if (op.first=="jit") {
498  jit_ = op.second;
499  } else if (op.first=="jit_cleanup") {
500  jit_cleanup_ = op.second;
501  } else if (op.first=="jit_serialize") {
502  jit_serialize_ = op.second.to_string();
503  casadi_assert(jit_serialize_=="source" || jit_serialize_=="link" || jit_serialize_=="embed",
504  "jit_serialize option not understood. Pick one of source, link, embed.");
505  } else if (op.first=="compiler") {
506  compiler_plugin_ = op.second.to_string();
507  } else if (op.first=="jit_options") {
508  jit_options_ = op.second;
509  } else if (op.first=="codegen_options") {
510  codegen_options_ = op.second;
511  } else if (op.first=="jit_name") {
512  jit_base_name_ = op.second.to_string();
513  } else if (op.first=="jit_temp_suffix") {
514  jit_temp_suffix_ = op.second;
515  } else if (op.first=="derivative_of") {
516  derivative_of_ = op.second;
517  } else if (op.first=="ad_weight") {
518  ad_weight_ = op.second;
519  } else if (op.first=="ad_weight_sp") {
520  ad_weight_sp_ = op.second;
521  } else if (op.first=="max_num_dir") {
522  max_num_dir_ = op.second;
523  } else if (op.first=="enable_forward") {
524  enable_forward_op_ = op.second;
525  } else if (op.first=="enable_reverse") {
526  enable_reverse_op_ = op.second;
527  } else if (op.first=="enable_jacobian") {
528  enable_jacobian_op_ = op.second;
529  } else if (op.first=="enable_fd") {
530  enable_fd_op_ = op.second;
531  } else if (op.first=="fd_options") {
532  fd_options_ = op.second;
533  } else if (op.first=="fd_method") {
534  fd_method_ = op.second.to_string();
535  } else if (op.first=="print_in") {
536  print_in_ = op.second;
537  } else if (op.first=="print_out") {
538  print_out_ = op.second;
539  } else if (op.first=="print_canonical") {
540  print_canonical_ = op.second;
541  } else if (op.first=="max_io") {
542  max_io_ = op.second;
543  } else if (op.first=="dump_in") {
544  dump_in_ = op.second;
545  } else if (op.first=="dump_out") {
546  dump_out_ = op.second;
547  } else if (op.first=="dump") {
548  dump_ = op.second;
549  } else if (op.first=="dump_dir") {
550  dump_dir_ = op.second.to_string();
551  } else if (op.first=="dump_format") {
552  dump_format_ = op.second.to_string();
553  } else if (op.first=="forward_options") {
554  forward_options_ = op.second;
555  } else if (op.first=="reverse_options") {
556  reverse_options_ = op.second;
557  } else if (op.first=="jacobian_options") {
558  jacobian_options_ = op.second;
559  } else if (op.first=="der_options") {
560  der_options_ = op.second;
561  } else if (op.first=="custom_jacobian") {
562  custom_jacobian_ = op.second.to_function();
563  casadi_assert(custom_jacobian_.name() == "jac_" + name_,
564  "Inconsistent naming of custom Jacobian, expected: jac_" + name_);
566  } else if (op.first=="always_inline") {
567  always_inline_ = op.second;
568  } else if (op.first=="never_inline") {
569  never_inline_ = op.second;
570  } else if (op.first=="is_diff_in") {
571  is_diff_in_ = op.second;
572  } else if (op.first=="is_diff_out") {
573  is_diff_out_ = op.second;
574  } else if (op.first=="cache") {
575  cache_init_ = op.second;
576  }
577  }
578 
579  // print_time implies record_time
580  if (print_time_) record_time_ = true;
581 
582  // Verbose?
583  if (verbose_) casadi_message(name_ + "::init");
584 
585  // Get the number of inputs
586  n_in_ = get_n_in();
587  if (max_io_ > 0 && n_in_ > max_io_) {
588  casadi_warning("Function " + name_ + " has many inputs (" + str(n_in_) + " > "
589  + "max_io (=" + str(max_io_) + ")). "
590  + "Changing the problem formulation is strongly encouraged.");
591  }
592 
593  // Get the number of outputs
594  n_out_ = get_n_out();
595  if (max_io_ > 0 && n_out_ > max_io_) {
596  casadi_warning("Function " + name_ + " has many outputs (" + str(n_out_) + " > "
597  + "max_io (=" + str(max_io_) + ")). "
598  + "Changing the problem formulation is strongly encouraged.");
599  }
600 
601  // Query which inputs are differentiable if not already provided
602  if (is_diff_in_.empty()) {
603  is_diff_in_.resize(n_in_);
604  for (casadi_int i = 0; i < n_in_; ++i) is_diff_in_[i] = get_diff_in(i);
605  } else {
606  casadi_assert(n_in_ == is_diff_in_.size(), "Function " + name_ + " has " + str(n_in_)
607  + " inputs, but is_diff_in has length " + str(is_diff_in_.size()) + ".");
608  }
609 
610  // Query which outputs are differentiable if not already provided
611  if (is_diff_out_.empty()) {
612  is_diff_out_.resize(n_out_);
613  for (casadi_int i = 0; i < n_out_; ++i) is_diff_out_[i] = get_diff_out(i);
614  } else {
615  casadi_assert(n_out_ == is_diff_out_.size(), "Function " + name_ + " has " + str(n_out_)
616  + " outputs, but is_diff_out has length " + str(is_diff_out_.size()) + ".");
617  }
618 
619  // Query input sparsities if not already provided
620  if (sparsity_in_.empty()) {
621  sparsity_in_.resize(n_in_);
622  for (casadi_int i=0; i<n_in_; ++i) sparsity_in_[i] = get_sparsity_in(i);
623  } else {
624  casadi_assert(sparsity_in_.size() == n_in_, "Function " + name_ + " has " + str(n_in_)
625  + " inputs, but sparsity_in has length " + str(sparsity_in_.size()) + ".");
626  }
627 
628  // Query output sparsities if not already provided
629  if (sparsity_out_.empty()) {
630  sparsity_out_.resize(n_out_);
631  for (casadi_int i=0; i<n_out_; ++i) sparsity_out_[i] = get_sparsity_out(i);
632  } else {
633  casadi_assert(sparsity_out_.size() == n_out_, "Function " + name_ + " has " + str(n_out_)
634  + " outputs, but sparsity_out has length " + str(sparsity_out_.size()) + ".");
635  }
636 
637  // Query input names if not already provided
638  if (name_in_.empty()) {
639  name_in_.resize(n_in_);
640  for (casadi_int i=0; i<n_in_; ++i) name_in_[i] = get_name_in(i);
641  } else {
642  casadi_assert(name_in_.size()==n_in_, "Function " + name_ + " has " + str(n_in_)
643  + " inputs, but name_in has length " + str(name_in_.size()) + ".");
644  }
645 
646  // Query output names if not already provided
647  if (name_out_.empty()) {
648  name_out_.resize(n_out_);
649  for (casadi_int i=0; i<n_out_; ++i) name_out_[i] = get_name_out(i);
650  } else {
651  casadi_assert(name_out_.size()==n_out_, "Function " + name_ + " has " + str(n_out_)
652  + " outputs, but name_out has length " + str(name_out_.size()) + ".");
653  }
654 
655  // Prepopulate function cache
656  for (auto&& c : cache_init_) {
657  const Function& f = c.second;
658  if (c.first != f.name()) {
659  casadi_warning("Cannot add '" + c.first + "' a.k.a. '" + f.name()
660  + "' to cache. Mismatching names not implemented.");
661  } else {
662  tocache(f);
663  }
664  }
665 
666  // Allocate memory for function inputs and outputs
667  sz_arg_per_ += n_in_;
668  sz_res_per_ += n_out_;
669 
670  // Type of derivative calculations enabled
675 
676  alloc_arg(0);
677  alloc_res(0);
678  }
679 
680  std::string FunctionInternal::get_name_in(casadi_int i) {
681  if (!derivative_of_.is_null()) {
682  std::string n = derivative_of_.name();
683  if (name_ == "jac_" + n || name_ == "adj1_" + n) {
684  if (i < derivative_of_.n_in()) {
685  // Same as nondifferentiated function
686  return derivative_of_.name_in(i);
687  } else if (i < derivative_of_.n_in() + derivative_of_.n_out()) {
688  // Nondifferentiated output
689  return "out_" + derivative_of_.name_out(i - derivative_of_.n_in());
690  } else {
691  // Adjoint seed
692  return "adj_" + derivative_of_.name_out(i - derivative_of_.n_in()
693  - derivative_of_.n_out());
694  }
695  }
696  }
697  // Default name
698  return "i" + str(i);
699  }
700 
701  std::string FunctionInternal::get_name_out(casadi_int i) {
702  if (!derivative_of_.is_null()) {
703  std::string n = derivative_of_.name();
704  if (name_ == "jac_" + n) {
705  // Jacobian block
706  casadi_int oind = i / derivative_of_.n_in(), iind = i % derivative_of_.n_in();
707  return "jac_" + derivative_of_.name_out(oind) + "_" + derivative_of_.name_in(iind);
708  } else if (name_ == "adj1_" + n) {
709  // Adjoint sensitivity
710  return "adj_" + derivative_of_.name_in(i);
711  }
712  }
713  // Default name
714  return "o" + str(i);
715  }
716 
717  std::string FunctionInternal::get_jit_directory(const Dict& jit_options) {
718  // Start with default temp work dir
719  std::string jit_directory = GlobalOptions::getTempWorkDir();
720 
721  // Get user-specified directory
722  std::string directory;
723  directory = get_from_dict(jit_options, "directory", std::string(""));
724 
725  // What if directory itself is absolute?
726  if (Filesystem::is_absolute(directory)) {
727  // Override
728  jit_directory = directory;
729  } else {
730  jit_directory = jit_directory + directory;
731  if (Filesystem::is_enabled()) {
732  jit_directory = Filesystem::absolute(jit_directory);
733  }
734  }
735 
736  return Filesystem::ensure_trailing_slash(jit_directory);
737  }
738 
740  if (codegen_needs_mem()) has_refcount_ = true;
741  if (dump_in_ || dump_out_) has_refcount_ = true;
742 
744 
745  // Does any embedded function have reference counting for codegen?
746  for (const Function& f : shared_from_this<Function>().find_functions(0)) {
747  if (f->has_refcount_in_deps_) {
748  has_refcount_in_deps_ = true;
749  break;
750  }
751  }
752 
753  if (jit_) {
756  if (jit_temp_suffix_) {
758  jit_name_ = std::string(jit_name_.begin()+jit_directory_.size(),
759  jit_name_.begin()+jit_name_.size()-2);
760  }
761  if (has_codegen()) {
762  if (compiler_.is_null()) {
763  if (verbose_) casadi_message("Codegenerating function '" + name_ + "'.");
764  // JIT everything
765  Dict opts = codegen_options_;
766  // Override the default to avoid random strings in the generated code
767  if (opts.find("prefix")==opts.end()) opts["prefix"] = "jit";
768  CodeGenerator gen(jit_name_, opts);
769  gen.add(self());
770  if (verbose_) casadi_message("Compiling function '" + name_ + "'..");
772  if (verbose_) casadi_message("Compiling function '" + name_ + "' done.");
773  }
774  // Try to load
778  incref_ = (signal_t) compiler_.get_function(name_ + "_incref");
779  decref_ = (signal_t) compiler_.get_function(name_ + "_decref");
780  casadi_assert(eval_!=nullptr, "Cannot load JIT'ed function.");
781  if (incref_) incref_();
782  } else {
783  // Just jit dependencies
785  }
786  }
787 
788  // Finalize base classes
790 
791  // Dump if requested
792  if (dump_) dump();
793  }
794 
796  // Create memory object
797  int mem = checkout();
798  casadi_assert_dev(mem==0);
799  }
800 
801  void FunctionInternal::generate_in(const std::string& fname, const double** arg) const {
802  // Set up output stream
803  auto of_ptr = Filesystem::ofstream_ptr(fname);
804  std::ostream& of = *of_ptr;
805  normalized_setup(of);
806 
807  // Encode each input
808  for (casadi_int i=0; i<n_in_; ++i) {
809  const double* v = arg[i];
810  for (casadi_int k=0;k<nnz_in(i);++k) {
811  normalized_out(of, v ? v[k] : 0);
812  of << std::endl;
813  }
814  }
815  }
816 
817  void FunctionInternal::generate_out(const std::string& fname, double** res) const {
818  // Set up output stream
819  auto of_ptr = Filesystem::ofstream_ptr(fname);
820  std::ostream& of = *of_ptr;
821  normalized_setup(of);
822 
823  // Encode each input
824  for (casadi_int i=0; i<n_out_; ++i) {
825  const double* v = res[i];
826  for (casadi_int k=0;k<nnz_out(i);++k) {
827  normalized_out(of, v ? v[k] : std::numeric_limits<double>::quiet_NaN());
828  of << std::endl;
829  }
830  }
831  }
832 
834  trace_values(std::ostream& trace, const double* values, casadi_int nnz) {
835  if (!values) {
836  trace << "null";
837  return;
838  }
839  trace << "[";
840  for (casadi_int i = 0; i < nnz; ++i) {
841  if (i) trace << ",";
842  double v = values[i];
843  if (isnan(v)) {
844  trace << "\"nan\"";
845  } else if (isinf(v)) {
846  trace << (v < 0 ? "\"-inf\"" : "\"inf\"");
847  } else {
848  normalized_out(trace, v);
849  }
850  }
851  trace << "]";
852  }
853 
854  std::unique_ptr<std::ostream> FunctionInternal::
855  open_trace(const double** arg, casadi_int dump_id) const {
856  if (dump_id < 0) dump_id = get_dump_id();
857  std::stringstream filename;
858  filename << dump_dir_ << filesep() << name_ << "." << std::setfill('0')
859  << std::setw(6) << dump_id << ".trace.jsonl";
860  auto output = Filesystem::ofstream_ptr(filename.str());
861  std::ostream& trace = *output;
862  normalized_setup(trace);
863  trace << "{\"event\":\"header\",\"format\":\"casadi_trace\",\"version\":1,"
864  << "\"function\":\"" << name_ << "\",\"type\":\"" << class_name()
865  << "\",\"dump_id\":" << dump_id << "}\n";
866  trace << "{\"event\":\"inputs\",\"values\":[";
867  for (casadi_int i = 0; i < n_in_; ++i) {
868  if (i) trace << ",";
869  trace_values(trace, arg[i], nnz_in(i));
870  }
871  trace << "]}\n";
872  return output;
873  }
874 
876  finish_trace(std::ostream& trace, double** res, int ret) const {
877  if (ret == 0) {
878  trace << "{\"event\":\"outputs\",\"values\":[";
879  for (casadi_int i = 0; i < n_out_; ++i) {
880  if (i) trace << ",";
881  trace_values(trace, res[i], nnz_out(i));
882  }
883  trace << "]}\n";
884  }
885  trace << "{\"event\":\"end\",\"status\":" << ret << "}\n";
886  trace.flush();
887  casadi_assert(trace.good(), "Failed to write dump_trace for '" + name_ + "'");
888  }
889 
890  void FunctionInternal::dump_in(casadi_int id, const double** arg) const {
891  std::stringstream ss;
892  ss << std::setfill('0') << std::setw(6) << id;
893  std::string count = ss.str();
894  for (casadi_int i=0;i<n_in_;++i) {
895  DM::to_file(dump_dir_+ filesep() + name_ + "." + count + ".in." + name_in_[i] + "." +
896  dump_format_, sparsity_in_[i], arg[i]);
897  }
898  std::string name = dump_dir_+ filesep() + name_ + "." + count + ".in.txt";
899  if (verbose_) {
900  casadi_message("dump_in for " + name_ + " -> " + name);
901  }
902  generate_in(name, arg);
903  }
904 
905  void FunctionInternal::dump_out(casadi_int id, double** res) const {
906  std::stringstream ss;
907  ss << std::setfill('0') << std::setw(6) << id;
908  std::string count = ss.str();
909  for (casadi_int i=0;i<n_out_;++i) {
910  DM::to_file(dump_dir_+ filesep() + name_ + "." + count + ".out." + name_out_[i] + "." +
911  dump_format_, sparsity_out_[i], res[i]);
912  }
913  std::string name = dump_dir_+ filesep() + name_ + "." + count + ".out.txt";
914  if (verbose_) {
915  casadi_message("dump_out for " + name_ + " -> " + name);
916  }
917  generate_out(name, res);
918  }
919 
920  void FunctionInternal::dump() const {
921  shared_from_this<Function>().save(dump_dir_+ filesep() + name_ + ".casadi");
922  }
923 
924  casadi_int FunctionInternal::get_dump_id() const {
925  return dump_count_++;
926  }
927 
928  int ProtoFunction::init_mem(void* mem) const {
929  auto *m = static_cast<ProtoFunctionMemory*>(mem);
930  if (record_time_) {
931  m->add_stat("total");
932  m->t_total = &m->fstats.at("total");
933  } else {
934  m->t_total = nullptr;
935  }
936  return 0;
937  }
938 
939  void FunctionInternal::print_in(std::ostream &stream, const double** arg, bool truncate) const {
940  stream << "Function " << name_ << " (" << this << ")" << std::endl;
941  for (casadi_int i=0; i<n_in_; ++i) {
942  stream << "Input " << i << " (" << name_in_[i] << "): ";
943  if (arg[i]) {
944  if (print_canonical_) {
945  print_canonical(stream, sparsity_in_[i], arg[i]);
946  } else {
947  DM::print_default(stream, sparsity_in_[i], arg[i], truncate);
948  }
949  stream << std::endl;
950  } else {
951  stream << "NULL" << std::endl;
952  }
953  }
954  }
955 
956  void FunctionInternal::print_out(std::ostream &stream, double** res, bool truncate) const {
957  stream << "Function " << name_ << " (" << this << ")" << std::endl;
958  for (casadi_int i=0; i<n_out_; ++i) {
959  stream << "Output " << i << " (" << name_out_[i] << "): ";
960  if (res[i]) {
961  if (print_canonical_) {
962  print_canonical(stream, sparsity_out_[i], res[i]);
963  } else {
964  DM::print_default(stream, sparsity_out_[i], res[i], truncate);
965  }
966  stream << std::endl;
967  } else {
968  stream << "NULL" << std::endl;
969  }
970  }
971  }
972 
973  void FunctionInternal::print_canonical(std::ostream &stream, casadi_int sz, const double* nz) {
974  StreamStateGuard backup(stream);
975  normalized_setup(stream);
976  if (nz) {
977  stream << "[";
978  for (casadi_int i=0; i<sz; ++i) {
979  if (i>0) stream << ", ";
980  normalized_out(stream, nz[i]);
981  }
982  stream << "]";
983  } else {
984  stream << "NULL";
985  }
986  }
987 
988  void FunctionInternal::print_canonical(std::ostream &stream,
989  const Sparsity& sp, const double* nz) {
990  StreamStateGuard backup(stream);
991  normalized_setup(stream);
992  if (nz) {
993  if (!sp.is_scalar(true)) {
994  stream << sp.dim(false) << ": ";
995  stream << "[";
996  }
997  for (casadi_int i=0; i<sp.nnz(); ++i) {
998  if (i>0) stream << ", ";
999  normalized_out(stream, nz[i]);
1000  }
1001  if (!sp.is_scalar(true)) {
1002  stream << "]";
1003  if (!sp.is_dense()) {
1004  stream << ", colind: [";
1005  for (casadi_int i=0; i<sp.size2()+1; ++i) {
1006  if (i>0) stream << ", ";
1007  stream << sp.colind()[i];
1008  }
1009  stream << "]";
1010  stream << ", row: [";
1011  for (casadi_int i=0; i<sp.nnz(); ++i) {
1012  if (i>0) stream << ", ";
1013  stream << sp.row()[i];
1014  }
1015  stream << "]";
1016  }
1017  }
1018  } else {
1019  stream << "NULL";
1020  }
1021  }
1022 
1023  void FunctionInternal::print_canonical(std::ostream &stream, double a) {
1024  StreamStateGuard backup(stream);
1025  normalized_setup(stream);
1026  normalized_out(stream, a);
1027  }
1028 
1030  eval_gen(const double** arg, double** res, casadi_int* iw, double* w, void* mem,
1031  bool always_inline, bool never_inline) const {
1032  casadi_int dump_id = (dump_in_ || dump_out_ || dump_) ? get_dump_id() : -1;
1033  if (dump_in_) dump_in(dump_id, arg);
1034  if (dump_ && dump_id==0) dump();
1035  if (print_in_) print_in(uout(), arg, false);
1036  auto *m = static_cast<FunctionMemory*>(mem);
1037 
1038  // Avoid memory corruption
1039  for (casadi_int i=0;i<n_in_;++i) {
1040  casadi_assert(arg[i]==nullptr || arg[i]+nnz_in(i)<=w || arg[i]>=w+sz_w(),
1041  "Memory corruption detected for input " + name_in_[i] + ".\n"+
1042  "arg[" + str(i) + "] " + str(arg[i]) + "-" + str(arg[i]+nnz_in(i)) +
1043  " intersects with w " + str(w)+"-"+str(w+sz_w())+".");
1044  }
1045  for (casadi_int i=0;i<n_out_;++i) {
1046  casadi_assert(res[i]==nullptr || res[i]+nnz_out(i)<=w || res[i]>=w+sz_w(),
1047  "Memory corruption detected for output " + name_out_[i]);
1048  }
1049  // Reset statistics
1050  for (auto&& s : m->fstats) s.second.reset();
1051  if (m->t_total) m->t_total->tic();
1052  m->dump_id = dump_id;
1053  int ret;
1054  if (eval_) {
1055  auto *m = static_cast<FunctionMemory*>(mem);
1056  m->stats_available = true;
1057  int mem_ = 0;
1058  if (checkout_) {
1059 #ifdef CASADI_WITH_THREAD
1060  std::lock_guard<std::mutex> lock(mtx_);
1061 #endif //CASADI_WITH_THREAD
1062  mem_ = checkout_();
1063  }
1064  ret = eval_(arg, res, iw, w, mem_);
1065  if (release_) {
1066 #ifdef CASADI_WITH_THREAD
1067  std::lock_guard<std::mutex> lock(mtx_);
1068 #endif //CASADI_WITH_THREAD
1069  release_(mem_);
1070  }
1071  } else {
1072  ret = eval(arg, res, iw, w, mem);
1073  }
1074  if (m->t_total) m->t_total->toc();
1075  // Show statistics
1076  print_time(m->fstats);
1077 
1078  if (dump_out_) dump_out(dump_id, res);
1079  if (print_out_) print_out(uout(), res, false);
1080  // Check all outputs for NaNs
1081  if (regularity_check_) {
1082  for (casadi_int i = 0; i < n_out_; ++i) {
1083  // Skip of not calculated
1084  if (!res[i]) continue;
1085  // Loop over nonzeros
1086  casadi_int nnz = this->nnz_out(i);
1087  for (casadi_int nz = 0; nz < nnz; ++nz) {
1088  if (isnan(res[i][nz]) || isinf(res[i][nz])) {
1089  // Throw readable error message
1090  casadi_error(str(res[i][nz]) + " detected for output " + name_out_[i] + " at "
1091  + sparsity_out(i).repr_el(nz));
1092  }
1093  }
1094  }
1095  }
1096  return ret;
1097  }
1098 
1099  void FunctionInternal::print_dimensions(std::ostream &stream) const {
1100  stream << " Number of inputs: " << n_in_ << std::endl;
1101  for (casadi_int i=0; i<n_in_; ++i) {
1102  stream << " Input " << i << " (\"" << name_in_[i] << "\"): "
1103  << sparsity_in_[i].dim() << std::endl;
1104  }
1105  stream << " Number of outputs: " << n_out_ << std::endl;
1106  for (casadi_int i=0; i<n_out_; ++i) {
1107  stream << " Output " << i << " (\"" << name_out_[i] << "\"): "
1108  << sparsity_out_[i].dim() << std::endl;
1109  }
1110  }
1111 
1112  void ProtoFunction::print_options(std::ostream &stream) const {
1113  get_options().print_all(stream);
1114  }
1115 
1116  void ProtoFunction::print_option(const std::string &name, std::ostream &stream) const {
1117  get_options().print_one(name, stream);
1118  }
1119 
1120  bool ProtoFunction::has_option(const std::string &option_name) const {
1121  return get_options().find(option_name) != nullptr;
1122  }
1123 
1124  void ProtoFunction::change_option(const std::string& option_name,
1125  const GenericType& option_value) {
1126  if (option_name == "verbose") {
1127  verbose_ = option_value;
1128  } else if (option_name == "regularity_check") {
1129  regularity_check_ = option_value;
1130  } else {
1131  // Failure
1132  casadi_error("Option '" + option_name + "' cannot be changed");
1133  }
1134  }
1135 
1136  std::vector<std::string> FunctionInternal::get_free() const {
1137  casadi_assert_dev(!has_free());
1138  return std::vector<std::string>();
1139  }
1140 
1141  std::string FunctionInternal::definition() const {
1142  std::stringstream s;
1143 
1144  // Print name
1145  s << name_ << ":(";
1146  // Print input arguments
1147  for (casadi_int i=0; i<n_in_; ++i) {
1148  if (!is_diff_in_.empty() && !is_diff_in_[i]) s << "#";
1149  s << name_in_[i] << sparsity_in_[i].postfix_dim() << (i==n_in_-1 ? "" : ",");
1150  }
1151  s << ")->(";
1152  // Print output arguments
1153  for (casadi_int i=0; i<n_out_; ++i) {
1154  if (!is_diff_out_.empty() && !is_diff_out_[i]) s << "#";
1155  s << name_out_[i] << sparsity_out_[i].postfix_dim() << (i==n_out_-1 ? "" : ",");
1156  }
1157  s << ")";
1158 
1159  return s.str();
1160  }
1161 
1162  void FunctionInternal::disp(std::ostream &stream, bool more) const {
1163  stream << definition() << " " << class_name();
1164  if (more) {
1165  stream << std::endl;
1166  disp_more(stream);
1167  }
1168  }
1169 
1171  // Return value
1172  Dict ret;
1173 
1174  // Retrieve all Function instances that haven't been deleted
1175  std::vector<std::string> keys;
1176  std::vector<Function> entries;
1177  cache_.cache(keys, entries);
1178 
1179  for (size_t i=0; i<keys.size(); ++i) {
1180  // Get the name of the key
1181  std::string s = keys[i];
1182  casadi_assert_dev(s.size() > 0);
1183  // Replace ':' with '_'
1184  std::replace(s.begin(), s.end(), ':', '_');
1185  // Remove trailing underscore, if any
1186  if (s.back() == '_') s.resize(s.size() - 1);
1187  // Add entry to function return
1188  ret[s] = entries[i];
1189  }
1190 
1191  return ret;
1192  }
1193 
1194  bool FunctionInternal::incache(const std::string& fname, Function& f,
1195  const std::string& suffix) const {
1196  return cache_.incache(fname + ":" + suffix, f);
1197  }
1198 
1199  void FunctionInternal::tocache(const Function& f, const std::string& suffix) const {
1200  cache_.tocache(f.name() + ":" + suffix, f);
1201  }
1202 
1203  void FunctionInternal::tocache_if_missing(Function& f, const std::string& suffix) const {
1204  cache_.tocache_if_missing(f.name() + ":" + suffix, f);
1205  }
1206 
1207  Function FunctionInternal::map(casadi_int n, const std::string& parallelization) const {
1208  Function f;
1209  if (parallelization=="serial") {
1210  // Serial maps are cached
1211  std::string fname = "map" + str(n) + "_" + name_;
1212  if (!incache(fname, f)) {
1213  // Create new serial map
1214  f = Map::create(parallelization, self(), n);
1215  casadi_assert_dev(f.name()==fname);
1216  // Save in cache
1217  tocache_if_missing(f);
1218  }
1219  } else {
1220  // Non-serial maps are not cached
1221  f = Map::create(parallelization, self(), n);
1222  }
1223  return f;
1224  }
1225 
1227  return wrap_as_needed("wrap_" + name_, opts);
1228  }
1229 
1230  Function FunctionInternal::wrap_as_needed(const std::string& name, const Dict& opts) const {
1231  if (opts.empty() && name==name_) return shared_from_this<Function>();
1232  // Options
1233  Dict my_opts = opts;
1234  my_opts["derivative_of"] = derivative_of_;
1235  if (my_opts.find("ad_weight")==my_opts.end())
1236  my_opts["ad_weight"] = ad_weight();
1237  if (my_opts.find("ad_weight_sp")==my_opts.end())
1238  my_opts["ad_weight_sp"] = sp_weight();
1239  if (my_opts.find("max_num_dir")==my_opts.end())
1240  my_opts["max_num_dir"] = max_num_dir_;
1241  // Wrap the function
1242  std::vector<MX> arg = mx_in();
1243  std::vector<MX> res = self()(arg);
1244  return Function(name, arg, res, name_in_, name_out_, my_opts);
1245  }
1246 
1248  return wrap("wrap_" + name_);
1249  }
1250 
1251  Function FunctionInternal::wrap(const std::string& name) const {
1252  Function f;
1253  if (!incache(name, f)) {
1254  // Options
1255  Dict opts;
1256  opts["derivative_of"] = derivative_of_;
1257  opts["ad_weight"] = ad_weight();
1258  opts["ad_weight_sp"] = sp_weight();
1259  opts["max_num_dir"] = max_num_dir_;
1260  opts["is_diff_in"] = is_diff_in_;
1261  opts["is_diff_out"] = is_diff_out_;
1262  // Wrap the function
1263  std::vector<MX> arg = mx_in();
1264  std::vector<MX> res = self()(arg);
1265  f = Function(name, arg, res, name_in_, name_out_, opts);
1266  // Save in cache
1267  tocache_if_missing(f);
1268  }
1269  return f;
1270  }
1271 
1272  std::vector<MX> FunctionInternal::symbolic_output(const std::vector<MX>& arg) const {
1273  return self()(arg);
1274  }
1275 
1277 
1278  void bvec_toggle(bvec_t* s, casadi_int begin, casadi_int end, casadi_int j) {
1279  for (casadi_int i=begin; i<end; ++i) {
1280  s[i] ^= (bvec_t(1) << j);
1281  }
1282  }
1283 
1284  void bvec_clear(bvec_t* s, casadi_int begin, casadi_int end) {
1285  for (casadi_int i=begin; i<end; ++i) {
1286  s[i] = 0;
1287  }
1288  }
1289 
1290 
1291  void bvec_or(const bvec_t* s, bvec_t & r, casadi_int begin, casadi_int end) {
1292  r = 0;
1293  for (casadi_int i=begin; i<end; ++i) r |= s[i];
1294  }
1296 
1297  // Traits
1298  template<bool fwd> struct JacSparsityTraits {};
1299  template<> struct JacSparsityTraits<true> {
1300  typedef const bvec_t* arg_t;
1301  static inline void sp(const FunctionInternal *f,
1302  const bvec_t** arg, bvec_t** res,
1303  casadi_int* iw, bvec_t* w, void* mem) {
1304  std::vector<const bvec_t*> argm(f->sz_arg(), nullptr);
1305  std::vector<bvec_t> wm(f->nnz_in(), bvec_t(0));
1306  bvec_t* wp = get_ptr(wm);
1307 
1308  for (casadi_int i=0;i<f->n_in_;++i) {
1309  if (f->is_diff_in_[i]) {
1310  argm[i] = arg[i];
1311  } else {
1312  argm[i] = arg[i] ? wp : nullptr;
1313  wp += f->nnz_in(i);
1314  }
1315  }
1316  f->sp_forward(get_ptr(argm), res, iw, w, mem);
1317  for (casadi_int i=0;i<f->n_out_;++i) {
1318  if (!f->is_diff_out_[i] && res[i]) casadi_clear(res[i], f->nnz_out(i));
1319  }
1320  }
1321  };
1322  template<> struct JacSparsityTraits<false> {
1323  typedef bvec_t* arg_t;
1324  static inline void sp(const FunctionInternal *f,
1325  bvec_t** arg, bvec_t** res,
1326  casadi_int* iw, bvec_t* w, void* mem) {
1327  for (casadi_int i=0;i<f->n_out_;++i) {
1328  if (!f->is_diff_out_[i] && res[i]) casadi_clear(res[i], f->nnz_out(i));
1329  }
1330  f->sp_reverse(arg, res, iw, w, mem);
1331  for (casadi_int i=0;i<f->n_in_;++i) {
1332  if (!f->is_diff_in_[i] && arg[i]) casadi_clear(arg[i], f->nnz_in(i));
1333  }
1334  }
1335  };
1336 
1337  template<bool fwd>
1338  Sparsity FunctionInternal::get_jac_sparsity_gen(casadi_int oind, casadi_int iind) const {
1339  // Number of nonzero inputs and outputs
1340  casadi_int nz_in = nnz_in(iind);
1341  casadi_int nz_out = nnz_out(oind);
1342 
1343  // Evaluation buffers
1344  std::vector<typename JacSparsityTraits<fwd>::arg_t> arg(sz_arg(), nullptr);
1345  std::vector<bvec_t*> res(sz_res(), nullptr);
1346  std::vector<casadi_int> iw(sz_iw());
1347  std::vector<bvec_t> w(sz_w(), 0);
1348 
1349  // Seeds and sensitivities
1350  std::vector<bvec_t> seed(nz_in, 0);
1351  arg[iind] = get_ptr(seed);
1352  std::vector<bvec_t> sens(nz_out, 0);
1353  res[oind] = get_ptr(sens);
1354  if (!fwd) std::swap(seed, sens);
1355 
1356  // Number of forward sweeps we must make
1357  casadi_int nsweep = seed.size() / bvec_size;
1358  if (seed.size() % bvec_size) nsweep++;
1359 
1360  // Print
1361  if (verbose_) {
1362  casadi_message(str(nsweep) + std::string(fwd ? " forward" : " reverse") + " sweeps "
1363  "needed for " + str(seed.size()) + " directions");
1364  }
1365 
1366  // Progress
1367  casadi_int progress = -10;
1368 
1369  // Temporary vectors
1370  std::vector<casadi_int> jcol, jrow;
1371 
1372  // Loop over the variables, bvec_size variables at a time
1373  for (casadi_int s=0; s<nsweep; ++s) {
1374 
1375  // Print progress
1376  if (verbose_) {
1377  casadi_int progress_new = (s*100)/nsweep;
1378  // Print when entering a new decade
1379  if (progress_new / 10 > progress / 10) {
1380  progress = progress_new;
1381  casadi_message(str(progress) + " %");
1382  }
1383  }
1384 
1385  // Nonzero offset
1386  casadi_int offset = s*bvec_size;
1387 
1388  // Number of local seed directions
1389  casadi_int ndir_local = seed.size()-offset;
1390  ndir_local = std::min(static_cast<casadi_int>(bvec_size), ndir_local);
1391 
1392  for (casadi_int i=0; i<ndir_local; ++i) {
1393  seed[offset+i] |= bvec_t(1)<<i;
1394  }
1395 
1396  // Propagate the dependencies
1397  JacSparsityTraits<fwd>::sp(this, get_ptr(arg), get_ptr(res),
1398  get_ptr(iw), get_ptr(w), memory(0));
1399 
1400  // Loop over the nonzeros of the output
1401  for (casadi_int el=0; el<sens.size(); ++el) {
1402 
1403  // Get the sparsity sensitivity
1404  bvec_t spsens = sens[el];
1405 
1406  if (!fwd) {
1407  // Clear the sensitivities for the next sweep
1408  sens[el] = 0;
1409  }
1410 
1411  // If there is a dependency in any of the directions
1412  if (spsens!=0) {
1413 
1414  // Loop over seed directions
1415  for (casadi_int i=0; i<ndir_local; ++i) {
1416 
1417  // If dependents on the variable
1418  if ((bvec_t(1) << i) & spsens) {
1419  // Add to pattern
1420  jcol.push_back(el);
1421  jrow.push_back(i+offset);
1422  }
1423  }
1424  }
1425  }
1426 
1427  // Remove the seeds
1428  for (casadi_int i=0; i<ndir_local; ++i) {
1429  seed[offset+i] = 0;
1430  }
1431  }
1432 
1433  // Construct sparsity pattern and return
1434  if (!fwd) swap(jrow, jcol);
1435  Sparsity ret = Sparsity::triplet(nz_out, nz_in, jcol, jrow);
1436  if (verbose_) {
1437  casadi_message("Formed Jacobian sparsity pattern (dimension " + str(ret.size()) + ", "
1438  + str(ret.nnz()) + " (" + str(ret.density()) + " %) nonzeros.");
1439  }
1440  return ret;
1441  }
1442 
1444  casadi_int iind) const {
1445  casadi_assert_dev(has_spfwd());
1446 
1447  // Number of nonzero inputs
1448  casadi_int nz = nnz_in(iind);
1449  casadi_assert_dev(nz==nnz_out(oind));
1450 
1451  // Evaluation buffers
1452  std::vector<const bvec_t*> arg(sz_arg(), nullptr);
1453  std::vector<bvec_t*> res(sz_res(), nullptr);
1454  std::vector<casadi_int> iw(sz_iw());
1455  std::vector<bvec_t> w(sz_w());
1456 
1457  // Seeds
1458  std::vector<bvec_t> seed(nz, 0);
1459  arg[iind] = get_ptr(seed);
1460 
1461  // Sensitivities
1462  std::vector<bvec_t> sens(nz, 0);
1463  res[oind] = get_ptr(sens);
1464 
1465  // Sparsity triplet accumulator
1466  std::vector<casadi_int> jcol, jrow;
1467 
1468  // Cols/rows of the coarse blocks
1469  std::vector<casadi_int> coarse(2, 0); coarse[1] = nz;
1470 
1471  // Cols/rows of the fine blocks
1472  std::vector<casadi_int> fine;
1473 
1474  // In each iteration, subdivide each coarse block in this many fine blocks
1475  casadi_int subdivision = bvec_size;
1476 
1477  Sparsity r = Sparsity::dense(1, 1);
1478 
1479  // The size of a block
1480  casadi_int granularity = nz;
1481 
1482  casadi_int nsweeps = 0;
1483 
1484  bool hasrun = false;
1485 
1486  while (!hasrun || coarse.size()!=nz+1) {
1487  if (verbose_) casadi_message("Block size: " + str(granularity));
1488 
1489  // Clear the sparsity triplet acccumulator
1490  jcol.clear();
1491  jrow.clear();
1492 
1493  // Clear the fine block structure
1494  fine.clear();
1495 
1496  Sparsity D = r.star_coloring();
1497 
1498  if (verbose_) {
1499  casadi_message("Star coloring on " + str(r.dim()) + ": "
1500  + str(D.size2()) + " <-> " + str(D.size1()));
1501  }
1502 
1503  // Clear the seeds
1504  std::fill(seed.begin(), seed.end(), 0);
1505 
1506  // Subdivide the coarse block
1507  for (casadi_int k=0; k<coarse.size()-1; ++k) {
1508  casadi_int diff = coarse[k+1]-coarse[k];
1509  casadi_int new_diff = diff/subdivision;
1510  if (diff%subdivision>0) new_diff++;
1511  std::vector<casadi_int> temp = range(coarse[k], coarse[k+1], new_diff);
1512  fine.insert(fine.end(), temp.begin(), temp.end());
1513  }
1514  if (fine.back()!=coarse.back()) fine.push_back(coarse.back());
1515 
1516  granularity = fine[1] - fine[0];
1517 
1518  // The index into the bvec bit vector
1519  casadi_int bvec_i = 0;
1520 
1521  // Create lookup tables for the fine blocks
1522  std::vector<casadi_int> fine_lookup = lookupvector(fine, nz+1);
1523 
1524  // Triplet data used as a lookup table
1525  std::vector<casadi_int> lookup_col;
1526  std::vector<casadi_int> lookup_row;
1527  std::vector<casadi_int> lookup_value;
1528 
1529  // The maximum number of fine blocks contained in one coarse block
1530  casadi_int n_fine_blocks_max = 0;
1531  for (casadi_int i=0;i<coarse.size()-1;++i) {
1532  casadi_int del = fine_lookup[coarse[i+1]]-fine_lookup[coarse[i]];
1533  n_fine_blocks_max = std::max(n_fine_blocks_max, del);
1534  }
1535 
1536  // Loop over all coarse seed directions from the coloring
1537  for (casadi_int csd=0; csd<D.size2(); ++csd) {
1538 
1539 
1540  casadi_int fci_offset = 0;
1541  casadi_int fci_cap = bvec_size-bvec_i;
1542 
1543  // Flag to indicate if all fine blocks have been handled
1544  bool f_finished = false;
1545 
1546  // Loop while not finished
1547  while (!f_finished) {
1548 
1549  // Loop over all coarse rows that are found in the coloring for this coarse seed direction
1550  for (casadi_int k=D.colind(csd); k<D.colind(csd+1); ++k) {
1551  casadi_int cci = D.row(k);
1552 
1553  // The first and last rows of the fine block
1554  casadi_int fci_start = fine_lookup[coarse[cci]];
1555  casadi_int fci_end = fine_lookup[coarse[cci+1]];
1556 
1557  // Local counter that modifies index into bvec
1558  casadi_int bvec_i_mod = 0;
1559 
1560  casadi_int value = -bvec_i + fci_offset + fci_start;
1561 
1562  //casadi_assert_dev(value>=0);
1563 
1564  // Loop over the rows of the fine block
1565  for (casadi_int fci = fci_offset; fci<std::min(fci_end-fci_start, fci_cap); ++fci) {
1566 
1567  // Loop over the coarse block cols that appear in the
1568  // coloring for the current coarse seed direction
1569  for (casadi_int cri=r.colind(cci);cri<r.colind(cci+1);++cri) {
1570  lookup_col.push_back(r.row(cri));
1571  lookup_row.push_back(bvec_i+bvec_i_mod);
1572  lookup_value.push_back(value);
1573  }
1574 
1575  // Toggle on seeds
1576  bvec_toggle(get_ptr(seed), fine[fci+fci_start], fine[fci+fci_start+1],
1577  bvec_i+bvec_i_mod);
1578  bvec_i_mod++;
1579  }
1580  }
1581 
1582  // Bump bvec_i for next major coarse direction
1583  bvec_i += std::min(n_fine_blocks_max, fci_cap);
1584 
1585  // Check if bvec buffer is full
1586  if (bvec_i==bvec_size || csd==D.size2()-1) {
1587  // Calculate sparsity for bvec_size directions at once
1588 
1589  // Statistics
1590  nsweeps+=1;
1591 
1592  // Construct lookup table
1593  IM lookup = IM::triplet(lookup_row, lookup_col, lookup_value,
1594  bvec_size, coarse.size());
1595 
1596  std::reverse(lookup_col.begin(), lookup_col.end());
1597  std::reverse(lookup_row.begin(), lookup_row.end());
1598  std::reverse(lookup_value.begin(), lookup_value.end());
1599  IM duplicates =
1600  IM::triplet(lookup_row, lookup_col, lookup_value, bvec_size, coarse.size())
1601  - lookup;
1602  duplicates = sparsify(duplicates);
1603  lookup(duplicates.sparsity()) = -bvec_size;
1604 
1605  // Propagate the dependencies
1606  JacSparsityTraits<true>::sp(this, get_ptr(arg), get_ptr(res),
1607  get_ptr(iw), get_ptr(w), nullptr);
1608 
1609  // Temporary bit work vector
1610  bvec_t spsens;
1611 
1612  // Loop over the cols of coarse blocks
1613  for (casadi_int cri=0; cri<coarse.size()-1; ++cri) {
1614 
1615  // Loop over the cols of fine blocks within the current coarse block
1616  for (casadi_int fri=fine_lookup[coarse[cri]];fri<fine_lookup[coarse[cri+1]];++fri) {
1617  // Lump individual sensitivities together into fine block
1618  bvec_or(get_ptr(sens), spsens, fine[fri], fine[fri+1]);
1619 
1620  // Loop over all bvec_bits
1621  for (casadi_int bvec_i=0;bvec_i<bvec_size;++bvec_i) {
1622  if (spsens & (bvec_t(1) << bvec_i)) {
1623  // if dependency is found, add it to the new sparsity pattern
1624  casadi_int ind = lookup.sparsity().get_nz(bvec_i, cri);
1625  if (ind==-1) continue;
1626  casadi_int lk = lookup->at(ind);
1627  if (lk>-bvec_size) {
1628  jrow.push_back(bvec_i+lk);
1629  jcol.push_back(fri);
1630  jrow.push_back(fri);
1631  jcol.push_back(bvec_i+lk);
1632  }
1633  }
1634  }
1635  }
1636  }
1637 
1638  // Clear the forward seeds/adjoint sensitivities, ready for next bvec sweep
1639  std::fill(seed.begin(), seed.end(), 0);
1640 
1641  // Clean lookup table
1642  lookup_col.clear();
1643  lookup_row.clear();
1644  lookup_value.clear();
1645  }
1646 
1647  if (n_fine_blocks_max>fci_cap) {
1648  fci_offset += std::min(n_fine_blocks_max, fci_cap);
1649  bvec_i = 0;
1650  fci_cap = bvec_size;
1651  } else {
1652  f_finished = true;
1653  }
1654  }
1655  }
1656 
1657  // Construct fine sparsity pattern
1658  r = Sparsity::triplet(fine.size()-1, fine.size()-1, jrow, jcol);
1659 
1660  // There may be false positives here that are not present
1661  // in the reverse mode that precedes it.
1662  // This can lead to an assymetrical result
1663  // cf. #1522
1664  r=r*r.T();
1665 
1666  coarse = fine;
1667  hasrun = true;
1668  }
1669  if (verbose_) {
1670  casadi_message("Number of sweeps: " + str(nsweeps));
1671  casadi_message("Formed Jacobian sparsity pattern (dimension " + str(r.size()) +
1672  ", " + str(r.nnz()) + " (" + str(r.density()) + " %) nonzeros.");
1673  }
1674 
1675  return r.T();
1676  }
1677 
1678  Sparsity FunctionInternal::get_jac_sparsity_hierarchical(casadi_int oind, casadi_int iind) const {
1679  // Number of nonzero inputs
1680  casadi_int nz_in = nnz_in(iind);
1681 
1682  // Number of nonzero outputs
1683  casadi_int nz_out = nnz_out(oind);
1684 
1685  // Seeds and sensitivities
1686  std::vector<bvec_t> s_in(nz_in, 0);
1687  std::vector<bvec_t> s_out(nz_out, 0);
1688 
1689  // Evaluation buffers
1690  std::vector<const bvec_t*> arg_fwd(sz_arg(), nullptr);
1691  std::vector<bvec_t*> arg_adj(sz_arg(), nullptr);
1692  arg_fwd[iind] = arg_adj[iind] = get_ptr(s_in);
1693  std::vector<bvec_t*> res(sz_res(), nullptr);
1694  res[oind] = get_ptr(s_out);
1695  std::vector<casadi_int> iw(sz_iw());
1696  std::vector<bvec_t> w(sz_w());
1697 
1698  // Sparsity triplet accumulator
1699  std::vector<casadi_int> jcol, jrow;
1700 
1701  // Cols of the coarse blocks
1702  std::vector<casadi_int> coarse_col(2, 0); coarse_col[1] = nz_out;
1703  // Rows of the coarse blocks
1704  std::vector<casadi_int> coarse_row(2, 0); coarse_row[1] = nz_in;
1705 
1706  // Cols of the fine blocks
1707  std::vector<casadi_int> fine_col;
1708 
1709  // Rows of the fine blocks
1710  std::vector<casadi_int> fine_row;
1711 
1712  // In each iteration, subdivide each coarse block in this many fine blocks
1713  casadi_int subdivision = bvec_size;
1714 
1715  Sparsity r = Sparsity::dense(1, 1);
1716 
1717  // The size of a block
1718  casadi_int granularity_row = nz_in;
1719  casadi_int granularity_col = nz_out;
1720 
1721  bool use_fwd = true;
1722 
1723  casadi_int nsweeps = 0;
1724 
1725  bool hasrun = false;
1726 
1727  // Get weighting factor
1728  double sp_w = sp_weight();
1729 
1730  // Lookup table for bvec_t
1731  std::vector<bvec_t> bvec_lookup;
1732  bvec_lookup.reserve(bvec_size);
1733  for (casadi_int i=0;i<bvec_size;++i) {
1734  bvec_lookup.push_back(bvec_t(1) << i);
1735  }
1736 
1737  while (!hasrun || coarse_col.size()!=nz_out+1 || coarse_row.size()!=nz_in+1) {
1738  if (verbose_) {
1739  casadi_message("Block size: " + str(granularity_col) + " x " + str(granularity_row));
1740  }
1741 
1742  // Clear the sparsity triplet acccumulator
1743  jcol.clear();
1744  jrow.clear();
1745 
1746  // Clear the fine block structure
1747  fine_row.clear();
1748  fine_col.clear();
1749 
1750  // r transpose will be needed in the algorithm
1751  Sparsity rT = r.T();
1752 
1755  // Forward mode
1756  Sparsity D1 = rT.uni_coloring(r);
1757  // Adjoint mode
1758  Sparsity D2 = r.uni_coloring(rT);
1759  if (verbose_) {
1760  casadi_message("Coloring on " + str(r.dim()) + " (fwd seeps: " + str(D1.size2()) +
1761  " , adj sweeps: " + str(D2.size1()) + ")");
1762  }
1763 
1764  // Use whatever required less colors if we tried both (with preference to forward mode)
1765  double fwd_cost = static_cast<double>(use_fwd ? granularity_row : granularity_col) *
1766  sp_w*static_cast<double>(D1.size2());
1767  double adj_cost = static_cast<double>(use_fwd ? granularity_col : granularity_row) *
1768  (1-sp_w)*static_cast<double>(D2.size2());
1769  use_fwd = fwd_cost <= adj_cost;
1770  if (verbose_) {
1771  casadi_message(std::string(use_fwd ? "Forward" : "Reverse") + " mode chosen "
1772  "(fwd cost: " + str(fwd_cost) + ", adj cost: " + str(adj_cost) + ")");
1773  }
1774 
1775  // Get seeds and sensitivities
1776  bvec_t* seed_v = use_fwd ? get_ptr(s_in) : get_ptr(s_out);
1777  bvec_t* sens_v = use_fwd ? get_ptr(s_out) : get_ptr(s_in);
1778 
1779  // The number of zeros in the seed and sensitivity directions
1780  casadi_int nz_seed = use_fwd ? nz_in : nz_out;
1781  casadi_int nz_sens = use_fwd ? nz_out : nz_in;
1782 
1783  // Clear the seeds
1784  for (casadi_int i=0; i<nz_seed; ++i) seed_v[i]=0;
1785 
1786  // Choose the active jacobian coloring scheme
1787  Sparsity D = use_fwd ? D1 : D2;
1788 
1789  // Adjoint mode amounts to swapping
1790  if (!use_fwd) {
1791  std::swap(coarse_col, coarse_row);
1792  std::swap(granularity_col, granularity_row);
1793  std::swap(r, rT);
1794  }
1795 
1796  // Subdivide the coarse block cols
1797  for (casadi_int k=0;k<coarse_col.size()-1;++k) {
1798  casadi_int diff = coarse_col[k+1]-coarse_col[k];
1799  casadi_int new_diff = diff/subdivision;
1800  if (diff%subdivision>0) new_diff++;
1801  std::vector<casadi_int> temp = range(coarse_col[k], coarse_col[k+1], new_diff);
1802  fine_col.insert(fine_col.end(), temp.begin(), temp.end());
1803  }
1804  // Subdivide the coarse block rows
1805  for (casadi_int k=0;k<coarse_row.size()-1;++k) {
1806  casadi_int diff = coarse_row[k+1]-coarse_row[k];
1807  casadi_int new_diff = diff/subdivision;
1808  if (diff%subdivision>0) new_diff++;
1809  std::vector<casadi_int> temp = range(coarse_row[k], coarse_row[k+1], new_diff);
1810  fine_row.insert(fine_row.end(), temp.begin(), temp.end());
1811  }
1812  if (fine_row.back()!=coarse_row.back()) fine_row.push_back(coarse_row.back());
1813  if (fine_col.back()!=coarse_col.back()) fine_col.push_back(coarse_col.back());
1814 
1815  granularity_col = fine_col[1] - fine_col[0];
1816  granularity_row = fine_row[1] - fine_row[0];
1817 
1818  // The index into the bvec bit vector
1819  casadi_int bvec_i = 0;
1820 
1821  // Create lookup tables for the fine blocks
1822  std::vector<casadi_int> fine_col_lookup = lookupvector(fine_col, nz_sens+1);
1823  std::vector<casadi_int> fine_row_lookup = lookupvector(fine_row, nz_seed+1);
1824 
1825  // Triplet data used as a lookup table
1826  std::vector<casadi_int> lookup_col;
1827  std::vector<casadi_int> lookup_row;
1828  std::vector<casadi_int> lookup_value;
1829 
1830 
1831  // The maximum number of fine blocks contained in one coarse block
1832  casadi_int n_fine_blocks_max = 0;
1833  for (casadi_int i=0;i<coarse_row.size()-1;++i) {
1834  casadi_int del = fine_row_lookup[coarse_row[i+1]]-fine_row_lookup[coarse_row[i]];
1835  n_fine_blocks_max = std::max(n_fine_blocks_max, del);
1836  }
1837 
1838  // Loop over all coarse seed directions from the coloring
1839  for (casadi_int csd=0; csd<D.size2(); ++csd) {
1840 
1841  casadi_int fci_offset = 0;
1842  casadi_int fci_cap = bvec_size-bvec_i;
1843 
1844  // Flag to indicate if all fine blocks have been handled
1845  bool f_finished = false;
1846 
1847  // Loop while not finished
1848  while (!f_finished) {
1849 
1850  // Loop over all coarse rows that are found in the coloring for this coarse seed direction
1851  for (casadi_int k=D.colind(csd); k<D.colind(csd+1); ++k) {
1852  casadi_int cci = D.row(k);
1853 
1854  // The first and last rows of the fine block
1855  casadi_int fci_start = fine_row_lookup[coarse_row[cci]];
1856  casadi_int fci_end = fine_row_lookup[coarse_row[cci+1]];
1857 
1858  // Local counter that modifies index into bvec
1859  casadi_int bvec_i_mod = 0;
1860 
1861  casadi_int value = -bvec_i + fci_offset + fci_start;
1862 
1863  // Loop over the rows of the fine block
1864  for (casadi_int fci = fci_offset; fci < std::min(fci_end-fci_start, fci_cap); ++fci) {
1865 
1866  // Loop over the coarse block cols that appear in the coloring
1867  // for the current coarse seed direction
1868  for (casadi_int cri=rT.colind(cci);cri<rT.colind(cci+1);++cri) {
1869  lookup_col.push_back(rT.row(cri));
1870  lookup_row.push_back(bvec_i+bvec_i_mod);
1871  lookup_value.push_back(value);
1872  }
1873 
1874  // Toggle on seeds
1875  bvec_toggle(seed_v, fine_row[fci+fci_start], fine_row[fci+fci_start+1],
1876  bvec_i+bvec_i_mod);
1877  bvec_i_mod++;
1878  }
1879  }
1880 
1881  // Bump bvec_i for next major coarse direction
1882  bvec_i+= std::min(n_fine_blocks_max, fci_cap);
1883 
1884  // Check if bvec buffer is full
1885  if (bvec_i==bvec_size || csd==D.size2()-1) {
1886  // Calculate sparsity for bvec_size directions at once
1887 
1888  // Statistics
1889  nsweeps+=1;
1890 
1891  // Construct lookup table
1892  IM lookup = IM::triplet(lookup_row, lookup_col, lookup_value, bvec_size,
1893  coarse_col.size());
1894 
1895  // Propagate the dependencies
1896  if (use_fwd) {
1897  JacSparsityTraits<true>::sp(this, get_ptr(arg_fwd), get_ptr(res),
1898  get_ptr(iw), get_ptr(w), memory(0));
1899  } else {
1900  std::fill(w.begin(), w.end(), 0);
1901  JacSparsityTraits<false>::sp(this, get_ptr(arg_adj), get_ptr(res),
1902  get_ptr(iw), get_ptr(w), memory(0));
1903  }
1904 
1905  // Temporary bit work vector
1906  bvec_t spsens;
1907 
1908  // Loop over the cols of coarse blocks
1909  for (casadi_int cri=0;cri<coarse_col.size()-1;++cri) {
1910 
1911  // Loop over the cols of fine blocks within the current coarse block
1912  for (casadi_int fri=fine_col_lookup[coarse_col[cri]];
1913  fri<fine_col_lookup[coarse_col[cri+1]];++fri) {
1914  // Lump individual sensitivities together into fine block
1915  bvec_or(sens_v, spsens, fine_col[fri], fine_col[fri+1]);
1916 
1917  // Next iteration if no sparsity
1918  if (!spsens) continue;
1919 
1920  // Loop over all bvec_bits
1921  for (casadi_int bvec_i=0;bvec_i<bvec_size;++bvec_i) {
1922  if (spsens & bvec_lookup[bvec_i]) {
1923  // if dependency is found, add it to the new sparsity pattern
1924  casadi_int ind = lookup.sparsity().get_nz(bvec_i, cri);
1925  if (ind==-1) continue;
1926  jrow.push_back(bvec_i+lookup->at(ind));
1927  jcol.push_back(fri);
1928  }
1929  }
1930  }
1931  }
1932 
1933  // Clear the forward seeds/adjoint sensitivities, ready for next bvec sweep
1934  std::fill(s_in.begin(), s_in.end(), 0);
1935 
1936  // Clear the adjoint seeds/forward sensitivities, ready for next bvec sweep
1937  std::fill(s_out.begin(), s_out.end(), 0);
1938 
1939  // Clean lookup table
1940  lookup_col.clear();
1941  lookup_row.clear();
1942  lookup_value.clear();
1943  }
1944 
1945  if (n_fine_blocks_max>fci_cap) {
1946  fci_offset += std::min(n_fine_blocks_max, fci_cap);
1947  bvec_i = 0;
1948  fci_cap = bvec_size;
1949  } else {
1950  f_finished = true;
1951  }
1952 
1953  }
1954 
1955  }
1956 
1957  // Swap results if adjoint mode was used
1958  if (use_fwd) {
1959  // Construct fine sparsity pattern
1960  r = Sparsity::triplet(fine_row.size()-1, fine_col.size()-1, jrow, jcol);
1961  coarse_col = fine_col;
1962  coarse_row = fine_row;
1963  } else {
1964  // Construct fine sparsity pattern
1965  r = Sparsity::triplet(fine_col.size()-1, fine_row.size()-1, jcol, jrow);
1966  coarse_col = fine_row;
1967  coarse_row = fine_col;
1968  }
1969  hasrun = true;
1970  }
1971  if (verbose_) {
1972  casadi_message("Number of sweeps: " + str(nsweeps));
1973  casadi_message("Formed Jacobian sparsity pattern (dimension " + str(r.size()) + ", " +
1974  str(r.nnz()) + " (" + str(r.density()) + " %) nonzeros.");
1975  }
1976 
1977  return r.T();
1978  }
1979 
1980  bool FunctionInternal::jac_is_symm(casadi_int oind, casadi_int iind) const {
1981  // If derivative expression
1982  if (!derivative_of_.is_null()) {
1983  std::string n = derivative_of_.name();
1984  // Reverse move
1985  if (name_ == "adj1_" + n) {
1986  if (iind == oind) return true;
1987  }
1988  }
1989  // Not symmetric by default
1990  return false;
1991  }
1992 
1993  Sparsity FunctionInternal::get_jac_sparsity(casadi_int oind, casadi_int iind,
1994  bool symmetric) const {
1995  if (symmetric) {
1996  casadi_assert(sparsity_out_[oind].is_dense(),
1997  "Symmetry exploitation in Jacobian assumes dense expression. "
1998  "A potential workaround is to apply densify().");
1999  }
2000  // Check if we are able to propagate dependencies through the function
2001  if (has_spfwd() || has_sprev()) {
2002  // Get weighting factor
2003  double w = sp_weight();
2004 
2005  // Skip generation, assume dense
2006  if (w == -1) return Sparsity();
2007 
2008  Sparsity sp;
2009  if (nnz_in(iind) > 3*bvec_size && nnz_out(oind) > 3*bvec_size &&
2011  if (symmetric) {
2012  sp = get_jac_sparsity_hierarchical_symm(oind, iind);
2013  } else {
2014  sp = get_jac_sparsity_hierarchical(oind, iind);
2015  }
2016  } else {
2017  // Number of nonzero inputs and outputs
2018  casadi_int nz_in = nnz_in(iind);
2019  casadi_int nz_out = nnz_out(oind);
2020 
2021  // Number of forward sweeps we must make
2022  casadi_int nsweep_fwd = nz_in/bvec_size;
2023  if (nz_in%bvec_size) nsweep_fwd++;
2024 
2025  // Number of adjoint sweeps we must make
2026  casadi_int nsweep_adj = nz_out/bvec_size;
2027  if (nz_out%bvec_size) nsweep_adj++;
2028 
2029  // Use forward mode?
2030  if (w*static_cast<double>(nsweep_fwd) <= (1-w)*static_cast<double>(nsweep_adj)) {
2031  sp = get_jac_sparsity_gen<true>(oind, iind);
2032  } else {
2033  sp = get_jac_sparsity_gen<false>(oind, iind);
2034  }
2035  }
2036  return sp;
2037  } else {
2038  // Not calculated
2039  return Sparsity();
2040  }
2041  }
2042 
2043  Sparsity FunctionInternal::to_compact(casadi_int oind, casadi_int iind,
2044  const Sparsity& sp) const {
2045  // Strip rows and columns
2046  std::vector<casadi_int> mapping;
2047  return sp.sub(sparsity_out(oind).find(), sparsity_in(iind).find(), mapping);
2048  }
2049 
2050  Sparsity FunctionInternal::from_compact(casadi_int oind, casadi_int iind,
2051  const Sparsity& sp) const {
2052  // Return value
2053  Sparsity r = sp;
2054  // Insert rows if sparse output
2055  if (numel_out(oind) != r.size1()) {
2056  casadi_assert_dev(r.size1() == nnz_out(oind));
2057  r.enlargeRows(numel_out(oind), sparsity_out(oind).find());
2058  }
2059  // Insert columns if sparse input
2060  if (numel_in(iind) != r.size2()) {
2061  casadi_assert_dev(r.size2() == nnz_in(iind));
2062  r.enlargeColumns(numel_in(iind), sparsity_in(iind).find());
2063  }
2064  // Return non-compact pattern
2065  return r;
2066  }
2067 
2068  Sparsity& FunctionInternal::jac_sparsity(casadi_int oind, casadi_int iind, bool compact,
2069  bool symmetric) const {
2070 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
2071  // Safe access to jac_sparsity_
2072  std::lock_guard<std::mutex> lock(jac_sparsity_mtx_);
2073 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
2074  // If first call, allocate cache
2075  for (bool c : {false, true}) {
2076  if (jac_sparsity_[c].empty()) jac_sparsity_[c].resize(n_in_ * n_out_);
2077  }
2078  // Flat index
2079  casadi_int ind = iind + oind * n_in_;
2080  // Reference to the block
2081  Sparsity& jsp = jac_sparsity_[compact].at(ind);
2082  // If null, generate
2083  if (jsp.is_null()) {
2084  // Use (non)-compact pattern, if given
2085  Sparsity& jsp_other = jac_sparsity_[!compact].at(ind);
2086  if (!jsp_other.is_null()) {
2087  jsp = compact ? to_compact(oind, iind, jsp_other) : from_compact(oind, iind, jsp_other);
2088  } else {
2089  // Generate pattern
2090  Sparsity sp;
2091  bool sp_is_compact;
2092  if (!is_diff_out_.at(oind) || !is_diff_in_.at(iind)) {
2093  // All-zero sparse
2094  sp = Sparsity(nnz_out(oind), nnz_in(iind));
2095  sp_is_compact = true;
2096  } else {
2097  // Use internal routine to determine sparsity
2098  if (has_spfwd() || has_sprev() || has_jac_sparsity(oind, iind)) {
2099  sp = get_jac_sparsity(oind, iind, symmetric);
2100  }
2101  // If null, dense
2102  if (sp.is_null()) sp = Sparsity::dense(nnz_out(oind), nnz_in(iind));
2103  // Is the return the compact pattern?
2104  sp_is_compact = sp.size1() == nnz_out(oind) && sp.size2() == nnz_in(iind);
2105  }
2106  // Save to cache and convert if needed
2107  if (sp_is_compact == compact) {
2108  jsp = sp;
2109  } else {
2110  jsp_other = sp;
2111  jsp = compact ? to_compact(oind, iind, sp) : from_compact(oind, iind, sp);
2112  }
2113  }
2114  }
2115 
2116  // Make sure the Jacobian is symmetric if requested, cf. #1522, #3074, #3134
2117  if (symmetric) {
2118  if (compact) {
2119  Sparsity sp = from_compact(oind, iind, jsp);
2120  if (!sp.is_symmetric()) {
2121  sp = sp * sp.T();
2122  jsp = to_compact(oind, iind, sp);
2123  }
2124  } else {
2125  if (!jsp.is_symmetric()) jsp = jsp * jsp.T();
2126  }
2127  }
2128 
2129  // Return a reference to the block
2130  return jsp;
2131  }
2132 
2133  void FunctionInternal::get_partition(casadi_int iind, casadi_int oind, Sparsity& D1, Sparsity& D2,
2134  bool compact, bool symmetric,
2135  bool allow_forward, bool allow_reverse) const {
2136  if (verbose_) casadi_message(name_ + "::get_partition");
2137  casadi_assert(allow_forward || allow_reverse, "Inconsistent options");
2138 
2139  // Sparsity pattern with transpose
2140  Sparsity &AT = jac_sparsity(oind, iind, compact, symmetric);
2141  Sparsity A = symmetric ? AT : AT.T();
2142 
2143  // Get seed matrices by graph coloring
2144  if (symmetric) {
2145  casadi_assert_dev(enable_forward_ || enable_fd_);
2146  casadi_assert_dev(allow_forward);
2147 
2148  // Star coloring if symmetric
2149  if (verbose_) casadi_message("FunctionInternal::getPartition star_coloring");
2150  D1 = A.star_coloring();
2151  if (verbose_) {
2152  casadi_message("Star coloring completed: " + str(D1.size2())
2153  + " directional derivatives needed ("
2154  + str(A.size1()) + " without coloring).");
2155  }
2156 
2157  } else {
2158  casadi_assert_dev(enable_forward_ || enable_fd_ || enable_reverse_);
2159  // Get weighting factor
2160  double w = ad_weight();
2161 
2162  // Which AD mode?
2163  if (w==1) allow_forward = false;
2164  if (w==0) allow_reverse = false;
2165  casadi_assert(allow_forward || allow_reverse, "Conflicting ad weights");
2166 
2167  // Best coloring encountered so far (relatively tight upper bound)
2168  double best_coloring = std::numeric_limits<double>::infinity();
2169 
2170  // Test forward mode first?
2171  bool test_fwd_first = allow_forward && w*static_cast<double>(A.size1()) <=
2172  (1-w)*static_cast<double>(A.size2());
2173  casadi_int mode_fwd = test_fwd_first ? 0 : 1;
2174 
2175  // Test both coloring modes
2176  for (casadi_int mode=0; mode<2; ++mode) {
2177  // Is this the forward mode?
2178  bool fwd = mode==mode_fwd;
2179 
2180  // Skip?
2181  if (!allow_forward && fwd) continue;
2182  if (!allow_reverse && !fwd) continue;
2183 
2184  // Perform the coloring
2185  if (fwd) {
2186  if (verbose_) casadi_message("Unidirectional coloring (forward mode)");
2187  bool d = best_coloring>=w*static_cast<double>(A.size1());
2188  casadi_int max_colorings_to_test =
2189  d ? A.size1() : static_cast<casadi_int>(floor(best_coloring/w));
2190  D1 = AT.uni_coloring(A, max_colorings_to_test);
2191  if (D1.is_null()) {
2192  if (verbose_) {
2193  casadi_message("Forward mode coloring interrupted (more than "
2194  + str(max_colorings_to_test) + " needed).");
2195  }
2196  } else {
2197  if (verbose_) {
2198  casadi_message("Forward mode coloring completed: "
2199  + str(D1.size2()) + " directional derivatives needed ("
2200  + str(A.size1()) + " without coloring).");
2201  }
2202  D2 = Sparsity();
2203  best_coloring = w*static_cast<double>(D1.size2());
2204  }
2205  } else {
2206  if (verbose_) casadi_message("Unidirectional coloring (adjoint mode)");
2207  bool d = best_coloring>=(1-w)*static_cast<double>(A.size2());
2208  casadi_int max_colorings_to_test =
2209  d ? A.size2() : static_cast<casadi_int>(floor(best_coloring/(1-w)));
2210 
2211  D2 = A.uni_coloring(AT, max_colorings_to_test);
2212  if (D2.is_null()) {
2213  if (verbose_) {
2214  casadi_message("Adjoint mode coloring interrupted (more than "
2215  + str(max_colorings_to_test) + " needed).");
2216  }
2217  } else {
2218  if (verbose_) {
2219  casadi_message("Adjoint mode coloring completed: "
2220  + str(D2.size2()) + " directional derivatives needed ("
2221  + str(A.size2()) + " without coloring).");
2222  }
2223  D1 = Sparsity();
2224  best_coloring = (1-w)*static_cast<double>(D2.size2());
2225  }
2226  }
2227  }
2228 
2229  }
2230  }
2231 
2232  std::vector<DM> FunctionInternal::eval_dm(const std::vector<DM>& arg) const {
2233  casadi_error("'eval_dm' not defined for " + class_name());
2234  }
2235 
2237  eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w, void* mem,
2238  bool always_inline, bool never_inline) const {
2239 
2240  always_inline = always_inline || always_inline_;
2241  never_inline = never_inline || never_inline_;
2242 
2243  casadi_assert(!always_inline, "'eval_sx' not defined for " + class_name() +
2244  " in combination with always_inline true");
2245 
2246  return CallSX::eval_sx(self(), arg, res);
2247  }
2248 
2249  std::string FunctionInternal::diff_prefix(const std::string& prefix) const {
2250  // Highest index found in current inputs and outputs
2251  casadi_int highest_index = 0;
2252  // Loop over both input names and output names
2253  for (const std::vector<std::string>& name_io : {name_in_, name_out_}) {
2254  for (const std::string& n : name_io) {
2255  // Find end of prefix, skip if no prefix
2256  size_t end = n.find('_');
2257  if (end >= n.size()) continue;
2258  // Skip if too short
2259  if (end < prefix.size()) continue;
2260  // Skip if wrong prefix
2261  if (n.compare(0, prefix.size(), prefix) != 0) continue;
2262  // Beginning of index
2263  size_t begin = prefix.size();
2264  // Check if any index
2265  casadi_int this_index;
2266  if (begin == end) {
2267  // No prefix, implicitly 1
2268  this_index = 1;
2269  } else {
2270  // Read index from string
2271  this_index = std::stoi(n.substr(begin, end - begin));
2272  }
2273  // Find the highest index
2274  if (this_index > highest_index) highest_index = this_index;
2275  }
2276  }
2277  // Return one higher index
2278  if (highest_index == 0) {
2279  return prefix + "_";
2280  } else {
2281  return prefix + std::to_string(highest_index + 1) + "_";
2282  }
2283  }
2284 
2285  Function FunctionInternal::forward(casadi_int nfwd) const {
2286  casadi_assert_dev(nfwd>=0);
2287  // Used wrapped function if forward not available
2288  if (!enable_forward_ && !enable_fd_) {
2289  // Derivative information must be available
2290  casadi_assert(has_derivative(), "Derivatives cannot be calculated for " + name_);
2291  return wrap().forward(nfwd);
2292  }
2293  // Retrieve/generate cached
2294  Function f;
2295  std::string fname = forward_name(name_, nfwd);
2296  if (!incache(fname, f)) {
2297  casadi_int i;
2298  // Prefix to be used for forward seeds, sensitivities
2299  std::string pref = diff_prefix("fwd");
2300  // Names of inputs
2301  std::vector<std::string> inames;
2302  for (i=0; i<n_in_; ++i) inames.push_back(name_in_[i]);
2303  for (i=0; i<n_out_; ++i) inames.push_back("out_" + name_out_[i]);
2304  for (i=0; i<n_in_; ++i) inames.push_back(pref + name_in_[i]);
2305  // Names of outputs
2306  std::vector<std::string> onames;
2307  for (i=0; i<n_out_; ++i) onames.push_back(pref + name_out_[i]);
2308  // Options
2310  if (enable_forward_) {
2311  opts = combine(opts, generate_options("forward"));
2312  } else {
2313  opts = combine(opts, FunctionInternal::generate_options("forward"));
2314  }
2315  opts["derivative_of"] = self();
2316  // Generate derivative function
2317  casadi_assert_dev(enable_forward_ || enable_fd_);
2318  if (enable_forward_) {
2319  f = get_forward(nfwd, fname, inames, onames, opts);
2320  } else {
2321  opts = combine(opts, fd_options_);
2322  // Get FD method
2323  if (fd_method_.empty() || fd_method_=="central") {
2324  f = Function::create(new CentralDiff(fname, nfwd), opts);
2325  } else if (fd_method_=="forward") {
2326  f = Function::create(new ForwardDiff(fname, nfwd), opts);
2327  } else if (fd_method_=="backward") {
2328  f = Function::create(new BackwardDiff(fname, nfwd), opts);
2329  } else if (fd_method_=="smoothing") {
2330  f = Function::create(new Smoothing(fname, nfwd), opts);
2331  } else {
2332  casadi_error("Unknown 'fd_method': " + fd_method_);
2333  }
2334  }
2335  // Consistency check for inputs
2336  casadi_assert_dev(f.n_in()==n_in_ + n_out_ + n_in_);
2337  casadi_int ind=0;
2338  for (i=0; i<n_in_; ++i) f.assert_size_in(ind++, size1_in(i), size2_in(i));
2339  for (i=0; i<n_out_; ++i) f.assert_size_in(ind++, size1_out(i), size2_out(i));
2340  for (i=0; i<n_in_; ++i) f.assert_size_in(ind++, size1_in(i), nfwd*size2_in(i));
2341  // Consistency check for outputs
2342  casadi_assert_dev(f.n_out()==n_out_);
2343  for (i=0; i<n_out_; ++i) f.assert_sparsity_out(i, sparsity_out(i), nfwd);
2344  // Save to cache
2345  tocache_if_missing(f);
2346  }
2347  return f;
2348  }
2349 
2350  Function FunctionInternal::reverse(casadi_int nadj) const {
2351  casadi_assert_dev(nadj>=0);
2352  // Used wrapped function if reverse not available
2353  if (!enable_reverse_) {
2354  // Derivative information must be available
2355  casadi_assert(has_derivative(), "Derivatives cannot be calculated for " + name_);
2356  return wrap().reverse(nadj);
2357  }
2358  // Retrieve/generate cached
2359  Function f;
2360  std::string fname = reverse_name(name_, nadj);
2361  if (!incache(fname, f)) {
2362  casadi_int i;
2363  // Prefix to be used for adjoint seeds, sensitivities
2364  std::string pref = diff_prefix("adj");
2365  // Names of inputs
2366  std::vector<std::string> inames;
2367  for (i=0; i<n_in_; ++i) inames.push_back(name_in_[i]);
2368  for (i=0; i<n_out_; ++i) inames.push_back("out_" + name_out_[i]);
2369  for (i=0; i<n_out_; ++i) inames.push_back(pref + name_out_[i]);
2370  // Names of outputs
2371  std::vector<std::string> onames;
2372  for (casadi_int i=0; i<n_in_; ++i) onames.push_back(pref + name_in_[i]);
2373  // Options
2375  opts = combine(opts, generate_options("reverse"));
2376  opts["derivative_of"] = self();
2377  // Generate derivative function
2378  casadi_assert_dev(enable_reverse_);
2379  f = get_reverse(nadj, fname, inames, onames, opts);
2380  // Consistency check for inputs
2381  casadi_assert_dev(f.n_in()==n_in_ + n_out_ + n_out_);
2382  casadi_int ind=0;
2383  for (i=0; i<n_in_; ++i) f.assert_size_in(ind++, size1_in(i), size2_in(i));
2384  for (i=0; i<n_out_; ++i) f.assert_size_in(ind++, size1_out(i), size2_out(i));
2385  for (i=0; i<n_out_; ++i) f.assert_size_in(ind++, size1_out(i), nadj*size2_out(i));
2386  // Consistency check for outputs
2387  casadi_assert_dev(f.n_out()==n_in_);
2388  for (i=0; i<n_in_; ++i) f.assert_sparsity_out(i, sparsity_in(i), nadj);
2389  // Save to cache
2390  tocache_if_missing(f);
2391  }
2392  return f;
2393  }
2394 
2396  get_forward(casadi_int nfwd, const std::string& name,
2397  const std::vector<std::string>& inames,
2398  const std::vector<std::string>& onames,
2399  const Dict& opts) const {
2400  casadi_error("'get_forward' not defined for " + class_name());
2401  }
2402 
2404  get_reverse(casadi_int nadj, const std::string& name,
2405  const std::vector<std::string>& inames,
2406  const std::vector<std::string>& onames,
2407  const Dict& opts) const {
2408  casadi_error("'get_reverse' not defined for " + class_name());
2409  }
2410 
2411  void FunctionInternal::export_code(const std::string& lang, std::ostream &stream,
2412  const Dict& options) const {
2413  casadi_error("'export_code' not defined for " + class_name());
2414  }
2415 
2416  void assert_read(std::istream &stream, const std::string& s) {
2417  casadi_int n = s.size();
2418  char c;
2419  std::stringstream ss;
2420  for (casadi_int i=0;i<n;++i) {
2421  stream >> c;
2422  ss << c;
2423  }
2424  casadi_assert_dev(s==ss.str());
2425  }
2426 
2427  casadi_int FunctionInternal::nnz_in() const {
2428  casadi_int ret=0;
2429  for (casadi_int iind=0; iind<n_in_; ++iind) ret += nnz_in(iind);
2430  return ret;
2431  }
2432 
2433  casadi_int FunctionInternal::nnz_out() const {
2434  casadi_int ret=0;
2435  for (casadi_int oind=0; oind<n_out_; ++oind) ret += nnz_out(oind);
2436  return ret;
2437  }
2438 
2439  casadi_int FunctionInternal::numel_in() const {
2440  casadi_int ret=0;
2441  for (casadi_int iind=0; iind<n_in_; ++iind) ret += numel_in(iind);
2442  return ret;
2443  }
2444 
2445  casadi_int FunctionInternal::numel_out() const {
2446  casadi_int ret=0;
2447  for (casadi_int oind=0; oind<n_out_; ++oind) ret += numel_out(oind);
2448  return ret;
2449  }
2450 
2452  bool always_inline, bool never_inline) const {
2453 
2454  always_inline = always_inline || always_inline_;
2455  never_inline = never_inline || never_inline_;
2456 
2457  // The code below creates a call node, to inline, wrap in an MXFunction
2458  if (always_inline) {
2459  casadi_assert(!never_inline, "Inconsistent options for " + str(name_));
2460  wrap().call(arg, res, true);
2461  return;
2462  }
2463 
2464  // Create a call-node
2465  res = Call::create(self(), arg);
2466  }
2467 
2469  // Used wrapped function if jacobian not available
2470  if (!has_jacobian()) {
2471  // Derivative information must be available
2472  casadi_assert(has_derivative(),
2473  "Derivatives cannot be calculated for " + name_);
2474  return wrap().jacobian();
2475  }
2476  // Retrieve/generate cached
2477  Function f;
2478  std::string fname = "jac_" + name_;
2479  if (!incache(fname, f)) {
2480  // Names of inputs
2481  std::vector<std::string> inames;
2482  for (casadi_int i=0; i<n_in_; ++i) inames.push_back(name_in_[i]);
2483  for (casadi_int i=0; i<n_out_; ++i) inames.push_back("out_" + name_out_[i]);
2484  // Names of outputs
2485  std::vector<std::string> onames;
2486  onames.reserve(n_in_ * n_out_);
2487  for (size_t oind = 0; oind < n_out_; ++oind) {
2488  for (size_t iind = 0; iind < n_in_; ++iind) {
2489  onames.push_back("jac_" + name_out_[oind] + "_" + name_in_[iind]);
2490  }
2491  }
2492  // Options
2494  opts["derivative_of"] = self();
2495  // Generate derivative function
2496  casadi_assert_dev(enable_jacobian_);
2497  f = get_jacobian(fname, inames, onames, opts);
2498  // Consistency checks
2499  casadi_assert(f.n_in() == inames.size(),
2500  "Mismatching input signature, expected " + str(inames));
2501  casadi_assert(f.n_out() == onames.size(),
2502  "Mismatching output signature, expected " + str(onames));
2503  // Save to cache
2504  tocache_if_missing(f);
2505  }
2506  return f;
2507  }
2508 
2510  get_jacobian(const std::string& name,
2511  const std::vector<std::string>& inames,
2512  const std::vector<std::string>& onames,
2513  const Dict& opts) const {
2514  casadi_error("'get_jacobian' not defined for " + class_name());
2515  }
2516 
2517  void FunctionInternal::codegen(CodeGenerator& g, const std::string& fname) const {
2518  // Define function
2519  g << "/* " << definition() << " */\n";
2520  g << "static " << signature(fname) << " {\n";
2521 
2522  // Reset local variables, flush buffer
2523  g.flush(g.body);
2524 
2525  g.scope_enter();
2526 
2527  if (dump_in_ || dump_out_) {
2528  Function F = shared_from_this<Function>();
2529  std::string cg_name = codegen_name(g, false);
2530  std::string dump_counter = g.shorthand(cg_name + "_dump_counter");
2531  g.auxiliaries << "static int " << dump_counter << " = 0;\n";
2532  if (g.thread_safe()) {
2533  g.define_local_mutex(F, cg_name + "_dump_mutex");
2534  std::string dump_mutex = g.local_mutex(F, cg_name + "_dump_mutex");
2535  g << "CASADI_MUTEX_LOCK(&" << dump_mutex << ");\n";
2536  g << "int dump_id_local = " << dump_counter << "++;\n";
2537  g << "CASADI_MUTEX_UNLOCK(&" << dump_mutex << ");\n";
2538  } else {
2539  g << "int dump_id_local = " << dump_counter << "++;\n";
2540  }
2541  }
2542 
2543  if (dump_in_) g.generate_dump(shared_from_this<Function>(), "arg", true);
2544  if (print_in_) g.generate_print(shared_from_this<Function>(), "arg", true);
2545 
2546  // Generate function body (to buffer)
2547  codegen_body(g);
2548 
2549  if (dump_out_) g.generate_dump(shared_from_this<Function>(), "res", false);
2550  if (print_out_) g.generate_print(shared_from_this<Function>(), "res", false);
2551 
2552  g.scope_exit();
2553 
2554  // Finalize the function
2555  g << "return 0;\n";
2556  g << "}\n\n";
2557 
2558  // Flush to function body
2559  g.flush(g.body);
2560  }
2561 
2562  std::string FunctionInternal::signature(const std::string& fname) const {
2563  return "int " + fname + "(const casadi_real** arg, casadi_real** res, "
2564  "casadi_int* iw, casadi_real* w, int mem)";
2565  }
2566 
2567  std::string FunctionInternal::signature_unrolled(const std::string& fname) const {
2568  std::vector<std::string> args;
2569  for (auto e : name_in_) {
2570  args.push_back("const casadi_real* " + str(e));
2571  }
2572  for (auto e : name_out_) {
2573  args.push_back("casadi_real* " + str(e));
2574  }
2575  args.push_back("const casadi_real** arg");
2576  args.push_back("casadi_real** res");
2577  args.push_back("casadi_int* iw");
2578  args.push_back("casadi_real* w");
2579  args.push_back("int mem");
2580  return "int " + fname + "_unrolled(" + join(args, ", ") + ")";
2581  }
2582 
2584  if (has_refcount_) {
2585  std::string name = codegen_name(g, false);
2586  std::string ref_counter = g.shorthand(name + "_ref_counter");
2587  g.auxiliaries << "static int " << ref_counter << " = 0;\n";
2588 
2589  Function F = shared_from_this<Function>();
2590  if (g.thread_safe()) {
2591  for (const auto& m : g.local_mutexes(F)) {
2592  std::string mtx = g.local_mutex(F, m);
2593  g << "#if CASADI_MUTEX_USE_STATIC_INIT == 0\n";
2594  g << "if (" << ref_counter << "==0) CASADI_MUTEX_INIT(&" << mtx << ");\n";
2595  g << "#endif\n";
2596  }
2597  }
2598  g << ref_counter << "++;\n";
2599  }
2600 
2601  // Treat dependent functions
2602  std::set<void*> added;
2603  Function F = shared_from_this<Function>();
2604  for (const Function& f : F.find_functions(0)) {
2605  if (f->has_refcount_in_deps_) {
2606  std::string cg_name = f->codegen_name(g, false);
2607  auto i = added.insert(f.get());
2608  if (i.second) { // prevent duplicate calls
2609  std::string incref = g.shorthand(cg_name + "_incref");
2610  g << incref << "();\n";
2611  }
2612  }
2613  }
2614  }
2615 
2617 
2618  // Treat dependent functions
2619  std::set<void*> added;
2620  Function F = shared_from_this<Function>();
2621  for (const Function& f : F.find_functions(0)) {
2622  if (f->has_refcount_in_deps_) {
2623  std::string cg_name = f->codegen_name(g, false);
2624  auto i = added.insert(f.get());
2625  if (i.second) { // prevent duplicate calls
2626  std::string decref = g.shorthand(cg_name + "_decref");
2627  g << decref << "();\n";
2628  }
2629  }
2630  }
2631 
2632  if (has_refcount_) {
2633  std::string name = codegen_name(g, false);
2634  std::string ref_counter = g.shorthand(name + "_ref_counter");
2635  std::string mem_counter = g.shorthand(name + "_mem_counter");
2636  std::string free_mem = g.shorthand(name + "_free_mem");
2637  g << ref_counter << "--;\n";
2638  g << "if (" << ref_counter << "==0) {\n";
2639  if (codegen_needs_mem()) {
2640  g << "while (" << mem_counter << ">0) {\n";
2641  g << free_mem << "(--" << mem_counter << ");\n";
2642  g << "}\n";
2643  }
2644  if (g.thread_safe()) {
2645  Function F = shared_from_this<Function>();
2646  for (const auto& m : g.local_mutexes(F)) {
2647  std::string mtx = g.local_mutex(F, m);
2648  g << "#if CASADI_MUTEX_USE_STATIC_INIT == 0\n";
2649  g << "CASADI_MUTEX_DESTROY(&" << mtx << ");\n";
2650  g << "#endif\n";
2651  }
2652  }
2653  g << "}\n";
2654  }
2655  }
2656 
2658  g << "return 0;\n";
2659  }
2660 
2662  bool needs_mem = codegen_needs_mem();
2663  if (needs_mem) {
2664  std::string name = codegen_name(g, false);
2665  std::string mem_counter = g.shorthand(name + "_mem_counter");
2666  g << "return " + mem_counter + "++;\n";
2667  }
2668  }
2669 
2671  std::string name = codegen_name(g, false);
2672  std::string stack_counter = g.shorthand(name + "_unused_stack_counter");
2673  std::string stack = g.shorthand(name + "_unused_stack");
2674  std::string mem_counter = g.shorthand(name + "_mem_counter");
2675  std::string mem_array = g.shorthand(name + "_mem");
2676  std::string alloc_mem = g.shorthand(name + "_alloc_mem");
2677  std::string init_mem = g.shorthand(name + "_init_mem");
2678 
2679 
2680  g.auxiliaries << "static int " << mem_counter << " = 0;\n";
2681  g.auxiliaries << "static int " << stack_counter << " = -1;\n";
2682  g.auxiliaries << "static int " << stack << "[CASADI_MAX_NUM_THREADS];\n";
2683  g.auxiliaries << "static " << codegen_mem_type() <<
2684  " " << mem_array << "[CASADI_MAX_NUM_THREADS];\n\n";
2685 
2686  if (g.thread_safe()) {
2687  Function F = shared_from_this<Function>();
2688  g.define_local_mutex(F, name + "_mem_mutex");
2689  std::string mem_mutex = g.local_mutex(F, name + "_mem_mutex");
2690  g << "CASADI_MUTEX_LOCK(&" << mem_mutex << ");\n";
2691  g.scope_add_cleanup("CASADI_MUTEX_UNLOCK(&" + mem_mutex + ");\n");
2692  }
2693 
2694  g.local("mid", "int");
2695 
2696  g << "if (" << stack_counter << ">=0) {\n";
2697  g.scope_return(stack + "[" + stack_counter + "--]");
2698  g << "} else {\n";
2699  g << "if (" << mem_counter << "==CASADI_MAX_NUM_THREADS) {\n";
2700  g.scope_return("-1");
2701  g << "}\n";
2702  g << "mid = " << alloc_mem << "();\n";
2703  g << "if (mid<0) {\n";
2704  g.scope_return("-1");
2705  g << "}\n";
2706  g << "if (" << init_mem << "(mid)) {\n";
2707  g.scope_return("-1");
2708  g << "}\n";
2709  g.scope_return("mid");
2710  g << "}\n";
2711  }
2712 
2714  std::string name = codegen_name(g, false);
2715  std::string stack_counter = g.shorthand(name + "_unused_stack_counter");
2716  std::string stack = g.shorthand(name + "_unused_stack");
2717 
2718  if (g.thread_safe()) {
2719  Function F = shared_from_this<Function>();
2720  std::string mem_mutex = g.local_mutex(F, name + "_mem_mutex");
2721  g << "CASADI_MUTEX_LOCK(&" << mem_mutex << ");\n";
2722  g.scope_add_cleanup("CASADI_MUTEX_UNLOCK(&" + mem_mutex + ");\n");
2723  }
2724 
2725  g << stack << "[++" << stack_counter << "] = mem;\n";
2726  g.scope_return();
2727  }
2728 
2731  }
2732 
2734  bool needs_mem = codegen_needs_mem();
2735  std::string name = codegen_name(g, false);
2736 
2737  // Checkout/release routines
2738  g << g.declare("int " + name_ + "_checkout(void)") << " {\n";
2739  if (needs_mem) {
2740  std::string checkout = g.shorthand(name + "_checkout");
2741  g << "return " << checkout << "();\n";
2742  } else {
2743  g << "return 0;\n";
2744  }
2745  g << "}\n\n";
2746 
2747  if (needs_mem) {
2748  g << g.declare("void " + name_ + "_release(int mem)") << " {\n";
2749  std::string release = g.shorthand(name + "_release");
2750  g << release << "(mem);\n";
2751  } else {
2752  g << g.declare("void " + name_ + "_release(int mem)") << " {\n";
2753  }
2754  g << "}\n\n";
2755 
2756  // Reference counter routines
2757  g << g.declare("void " + name_ + "_incref(void)") << " {\n";
2758  if (has_refcount_in_deps_) {
2759  std::string incref = g.shorthand(name + "_incref");
2760  g << incref << "();\n";
2761  }
2762  g << "}\n\n"
2763  << g.declare("void " + name_ + "_decref(void)") << " {\n";
2764  if (has_refcount_in_deps_) {
2765  std::string decref = g.shorthand(name + "_decref");
2766  g << decref << "();\n";
2767  }
2768  g << "}\n\n";
2769 
2770  // Number of inputs and outptus
2771  g << g.declare("casadi_int " + name_ + "_n_in(void)")
2772  << " { return " << n_in_ << ";}\n\n"
2773  << g.declare("casadi_int " + name_ + "_n_out(void)")
2774  << " { return " << n_out_ << ";}\n\n";
2775 
2776  // Default inputs
2777  g << g.declare("casadi_real " + name_ + "_default_in(casadi_int i)") << " {\n"
2778  << "switch (i) {\n";
2779  for (casadi_int i=0; i<n_in_; ++i) {
2780  double def = get_default_in(i);
2781  if (def!=0) g << "case " << i << ": return " << g.constant(def) << ";\n";
2782  }
2783  g << "default: return 0;\n}\n"
2784  << "}\n\n";
2785 
2786  // Input names
2787  g << g.declare("const char* " + name_ + "_name_in(casadi_int i)") << " {\n"
2788  << "switch (i) {\n";
2789  for (casadi_int i=0; i<n_in_; ++i) {
2790  g << "case " << i << ": return \"" << name_in_[i] << "\";\n";
2791  }
2792  g << "default: return 0;\n}\n"
2793  << "}\n\n";
2794 
2795  // Output names
2796  g << g.declare("const char* " + name_ + "_name_out(casadi_int i)") << " {\n"
2797  << "switch (i) {\n";
2798  for (casadi_int i=0; i<n_out_; ++i) {
2799  g << "case " << i << ": return \"" << name_out_[i] << "\";\n";
2800  }
2801  g << "default: return 0;\n}\n"
2802  << "}\n\n";
2803 
2804  // Codegen sparsities
2805  codegen_sparsities(g);
2806 
2807  // Function that returns work vector lengths
2808  g << g.declare(
2809  "int " + name_ + "_work(casadi_int *sz_arg, casadi_int* sz_res, "
2810  "casadi_int *sz_iw, casadi_int *sz_w)")
2811  << " {\n"
2812  << "if (sz_arg) *sz_arg = " << codegen_sz_arg(g) << ";\n"
2813  << "if (sz_res) *sz_res = " << codegen_sz_res(g) << ";\n"
2814  << "if (sz_iw) *sz_iw = " << codegen_sz_iw(g) << ";\n"
2815  << "if (sz_w) *sz_w = " << codegen_sz_w(g) << ";\n"
2816  << "return 0;\n"
2817  << "}\n\n";
2818 
2819  // Function that returns work vector lengths in bytes
2820  g << g.declare(
2821  "int " + name_ + "_work_bytes(casadi_int *sz_arg, casadi_int* sz_res, "
2822  "casadi_int *sz_iw, casadi_int *sz_w)")
2823  << " {\n"
2824  << "if (sz_arg) *sz_arg = " << codegen_sz_arg(g) << "*sizeof(const casadi_real*);\n"
2825  << "if (sz_res) *sz_res = " << codegen_sz_res(g) << "*sizeof(casadi_real*);\n"
2826  << "if (sz_iw) *sz_iw = " << codegen_sz_iw(g) << "*sizeof(casadi_int);\n"
2827  << "if (sz_w) *sz_w = " << codegen_sz_w(g) << "*sizeof(casadi_real);\n"
2828  << "return 0;\n"
2829  << "}\n\n";
2830 
2831  // Also add to header file to allow getting
2832  if (g.with_header) {
2833  g.header
2834  << "#define " << name_ << "_SZ_ARG " << codegen_sz_arg(g) << "\n"
2835  << "#define " << name_ << "_SZ_RES " << codegen_sz_res(g) << "\n"
2836  << "#define " << name_ << "_SZ_IW " << codegen_sz_iw(g) << "\n"
2837  << "#define " << name_ << "_SZ_W " << codegen_sz_w(g) << "\n";
2838  }
2839 
2840  // Which inputs are differentiable
2841  if (!all(is_diff_in_)) {
2842  g << g.declare("int " + name_ + "_diff_in(casadi_int i)") << " {\n"
2843  << "switch (i) {\n";
2844  for (casadi_int i=0; i<n_in_; ++i) {
2845  g << "case " << i << ": return " << is_diff_in_[i] << ";\n";
2846  }
2847  g << "default: return -1;\n}\n"
2848  << "}\n\n";
2849  }
2850 
2851  // Which outputs are differentiable
2852  if (!all(is_diff_out_)) {
2853  g << g.declare("int " + name_ + "_diff_out(casadi_int i)") << " {\n"
2854  << "switch (i) {\n";
2855  for (casadi_int i=0; i<n_out_; ++i) {
2856  g << "case " << i << ": return " << is_diff_out_[i] << ";\n";
2857  }
2858  g << "default: return -1;\n}\n"
2859  << "}\n\n";
2860  }
2861 
2862  // Generate mex gateway for the function
2863  if (g.mex) {
2864  // Begin conditional compilation
2865  g << "#ifdef MATLAB_MEX_FILE\n";
2866 
2867  // Declare wrapper
2868  g << "void mex_" << name_
2869  << "(int resc, mxArray *resv[], int argc, const mxArray *argv[]) {\n"
2870  << "casadi_int i;\n";
2871  g << "int mem;\n";
2872  // Work vectors, including input and output buffers
2873  casadi_int i_nnz = nnz_in(), o_nnz = nnz_out();
2874  size_t sz_w = this->sz_w();
2875  for (casadi_int i=0; i<n_in_; ++i) {
2876  const Sparsity& s = sparsity_in_[i];
2877  sz_w = std::max(sz_w, static_cast<size_t>(s.size1())); // To be able to copy a column
2878  sz_w = std::max(sz_w, static_cast<size_t>(s.size2())); // To be able to copy a row
2879  }
2880  sz_w += i_nnz + o_nnz;
2881  g << CodeGenerator::array("casadi_real", "w", sz_w);
2882  g << CodeGenerator::array("casadi_int", "iw", sz_iw());
2883  std::string fw = "w+" + str(i_nnz + o_nnz);
2884 
2885  // Copy inputs to buffers
2886  casadi_int offset=0;
2887  g << CodeGenerator::array("const casadi_real*", "arg", sz_arg(), "{0}");
2888 
2889  // Allocate output buffers
2890  g << "casadi_real* res[" << sz_res() << "] = {0};\n";
2891 
2892  // Check arguments
2893  g << "if (argc>" << n_in_ << ") mexErrMsgIdAndTxt(\"Casadi:RuntimeError\","
2894  << "\"Evaluation of \\\"" << name_ << "\\\" failed. Too many input arguments "
2895  << "(%d, max " << n_in_ << ")\", argc);\n";
2896 
2897  g << "if (resc>" << n_out_ << ") mexErrMsgIdAndTxt(\"Casadi:RuntimeError\","
2898  << "\"Evaluation of \\\"" << name_ << "\\\" failed. "
2899  << "Too many output arguments (%d, max " << n_out_ << ")\", resc);\n";
2900 
2901  for (casadi_int i=0; i<n_in_; ++i) {
2902  std::string p = "argv[" + str(i) + "]";
2903  g << "if (--argc>=0) arg[" << i << "] = "
2904  << g.from_mex(p, "w", offset, sparsity_in_[i], fw) << "\n";
2905  offset += nnz_in(i);
2906  }
2907 
2908  for (casadi_int i=0; i<n_out_; ++i) {
2909  if (i==0) {
2910  // if i==0, always store output (possibly ans output)
2911  g << "--resc;\n";
2912  } else {
2913  // Store output, if it exists
2914  g << "if (--resc>=0) ";
2915  }
2916  // Create and get pointer
2917  g << g.res(i) << " = w+" << str(offset) << ";\n";
2918  offset += nnz_out(i);
2919  }
2920  g << name_ << "_incref();\n";
2921  g << "mem = " << name_ << "_checkout();\n";
2922 
2923  // Call the function
2924  g << "i = " << name_ << "(arg, res, iw, " << fw << ", mem);\n"
2925  << "if (i) mexErrMsgIdAndTxt(\"Casadi:RuntimeError\",\"Evaluation of \\\"" << name_
2926  << "\\\" failed.\");\n";
2927  g << name_ << "_release(mem);\n";
2928  g << name_ << "_decref();\n";
2929 
2930  // Save results
2931  for (casadi_int i=0; i<n_out_; ++i) {
2932  g << "if (" << g.res(i) << ") resv[" << i << "] = "
2933  << g.to_mex(sparsity_out_[i], g.res(i)) << "\n";
2934  }
2935 
2936  // End conditional compilation and function
2937  g << "}\n"
2938  << "#endif\n\n";
2939  }
2940 
2941  if (g.main) {
2942  // Declare wrapper
2943  g << "casadi_int main_" << name_ << "(casadi_int argc, char* argv[]) {\n";
2944 
2945  g << "casadi_int j;\n";
2946  g << "casadi_real* a;\n";
2947  g << "const casadi_real* r;\n";
2948  g << "casadi_int flag;\n";
2949  if (needs_mem) g << "int mem;\n";
2950 
2951 
2952 
2953  // Work vectors and input and output buffers
2954  size_t nr = sz_w() + nnz_in() + nnz_out();
2955  g << CodeGenerator::array("casadi_int", "iw", sz_iw())
2956  << CodeGenerator::array("casadi_real", "w", nr);
2957 
2958  // Input buffers
2959  g << "const casadi_real* arg[" << sz_arg() << "];\n";
2960 
2961  // Output buffers
2962  g << "casadi_real* res[" << sz_res() << "];\n";
2963 
2964  casadi_int off=0;
2965  for (casadi_int i=0; i<n_in_; ++i) {
2966  g << "arg[" << i << "] = w+" << off << ";\n";
2967  off += nnz_in(i);
2968  }
2969  for (casadi_int i=0; i<n_out_; ++i) {
2970  g << "res[" << i << "] = w+" << off << ";\n";
2971  off += nnz_out(i);
2972  }
2973 
2974  // TODO(@jaeandersson): Read inputs from file. For now; read from stdin
2975  g << "a = w;\n"
2976  << "for (j=0; j<" << nnz_in() << "; ++j) "
2977  << "if (scanf(\"%lg\", a++)<=0) return 2;\n";
2978 
2979  if (has_refcount_in_deps_) {
2980  g << name_ << "_incref();\n";
2981  }
2982 
2983  if (needs_mem) {
2984  g << "mem = " << name_ << "_checkout();\n";
2985  }
2986 
2987  // Call the function
2988  g << "flag = " << name_ << "(arg, res, iw, w+" << off << ", ";
2989  if (needs_mem) {
2990  g << "mem";
2991  } else {
2992  g << "0";
2993  }
2994  g << ");\n";
2995  if (needs_mem) {
2996  g << name_ << "_release(mem);\n";
2997  }
2998 
2999  if (has_refcount_in_deps_) {
3000  g << name_ << "_decref();\n";
3001  }
3002 
3003  g << "if (flag) return flag;\n";
3004 
3005  // TODO(@jaeandersson): Write outputs to file. For now: print to stdout
3006  g << "r = w+" << nnz_in() << ";\n"
3007  << "for (j=0; j<" << nnz_out() << "; ++j) "
3008  << g.printf("%.16e ", "*r++") << "\n";
3009 
3010  // End with newline
3011  g << g.printf("\\n") << "\n";
3012 
3013  // Finalize function
3014  g << "return 0;\n"
3015  << "}\n\n";
3016  }
3017 
3018  if (g.with_mem) {
3019  // Allocate memory
3020  g << g.declare("casadi_functions* " + name_ + "_functions(void)") << " {\n"
3021  << "static casadi_functions fun = {\n"
3022  << name_ << "_incref,\n"
3023  << name_ << "_decref,\n"
3024  << name_ << "_checkout,\n"
3025  << name_ << "_release,\n"
3026  << name_ << "_default_in,\n"
3027  << name_ << "_n_in,\n"
3028  << name_ << "_n_out,\n"
3029  << name_ << "_name_in,\n"
3030  << name_ << "_name_out,\n"
3031  << name_ << "_sparsity_in,\n"
3032  << name_ << "_sparsity_out,\n"
3033  << name_ << "_work,\n"
3034  << name_ << "\n"
3035  << "};\n"
3036  << "return &fun;\n"
3037  << "}\n";
3038  }
3039  // Flush
3040  g.flush(g.body);
3041  }
3042 
3043  std::string FunctionInternal::codegen_name(const CodeGenerator& g, bool ns) const {
3044  if (ns) {
3045  // Get the index of the function
3046  for (auto&& e : g.added_functions_) {
3047  if (e.f.get()==this) return e.codegen_name;
3048  }
3049  } else {
3050  for (casadi_int i=0;i<g.added_functions_.size();++i) {
3051  const auto & e = g.added_functions_[i];
3052  if (e.f.get()==this) return "f" + str(i);
3053  }
3054  }
3055  casadi_error("Function '" + name_ + "' not found");
3056  }
3057 
3058  std::string FunctionInternal::codegen_mem(CodeGenerator& g, const std::string& index) const {
3059  std::string name = codegen_name(g, false);
3060  std::string mem_array = g.shorthand(name + "_mem");
3061  return mem_array+"[" + index + "]";
3062  }
3063 
3065  // Nothing to declare
3066  }
3067 
3069  casadi_warning("The function \"" + name_ + "\", which is of type \""
3070  + class_name() + "\" cannot be code generated. The generation "
3071  "will proceed, but compilation of the code will not be possible.");
3072  g << "#error Code generation not supported for " << class_name() << "\n";
3073  }
3074 
3076  generate_dependencies(const std::string& fname, const Dict& opts) const {
3077  casadi_error("'generate_dependencies' not defined for " + class_name());
3078  }
3079 
3081  eval_activity(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const {
3082  // Sound fallback: we cannot prove any output zero, so mark everything active
3083  for (casadi_int oind=0; oind<n_out_; ++oind) {
3084  if (res[oind]==nullptr) continue;
3085  std::fill_n(res[oind], nnz_out(oind), ~static_cast<bvec_t>(0));
3086  }
3087  return 0;
3088  }
3089 
3091  sp_forward(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const {
3092  // Loop over outputs
3093  for (casadi_int oind=0; oind<n_out_; ++oind) {
3094  // Skip if nothing to assign
3095  if (res[oind]==nullptr || nnz_out(oind)==0) continue;
3096  // Clear result
3097  casadi_clear(res[oind], nnz_out(oind));
3098  // Loop over inputs
3099  for (casadi_int iind=0; iind<n_in_; ++iind) {
3100  // Skip if no seeds
3101  if (arg[iind]==nullptr || nnz_in(iind)==0) continue;
3102  // Propagate sparsity for the specific block
3103  if (sp_forward_block(arg, res, iw, w, mem, oind, iind)) return 1;
3104  }
3105  }
3106  return 0;
3107  }
3108 
3110  casadi_int* iw, bvec_t* w, void* mem, casadi_int oind, casadi_int iind) const {
3111  // Get the sparsity of the Jacobian block
3112  Sparsity sp = jac_sparsity(oind, iind, true, false);
3113  if (sp.is_null() || sp.nnz() == 0) return 0; // Skip if zero
3114  // Carry out the sparse matrix-vector multiplication
3115  casadi_int d1 = sp.size2();
3116  const casadi_int *colind = sp.colind(), *row = sp.row();
3117  for (casadi_int cc=0; cc<d1; ++cc) {
3118  for (casadi_int el = colind[cc]; el < colind[cc+1]; ++el) {
3119  res[oind][row[el]] |= arg[iind][cc];
3120  }
3121  }
3122  return 0;
3123  }
3124 
3126  sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const {
3127  // Loop over outputs
3128  for (casadi_int oind=0; oind<n_out_; ++oind) {
3129  // Skip if nothing to assign
3130  if (res[oind]==nullptr || nnz_out(oind)==0) continue;
3131 
3132  // Loop over inputs
3133  for (casadi_int iind=0; iind<n_in_; ++iind) {
3134  // Skip if no seeds
3135  if (arg[iind]==nullptr || nnz_in(iind)==0) continue;
3136 
3137  // Get the sparsity of the Jacobian block
3138  Sparsity sp = jac_sparsity(oind, iind, true, false);
3139  if (sp.is_null() || sp.nnz() == 0) continue; // Skip if zero
3140 
3141  // Carry out the sparse matrix-vector multiplication
3142  casadi_int d1 = sp.size2();
3143  const casadi_int *colind = sp.colind(), *row = sp.row();
3144  for (casadi_int cc=0; cc<d1; ++cc) {
3145  for (casadi_int el = colind[cc]; el < colind[cc+1]; ++el) {
3146  arg[iind][cc] |= res[oind][row[el]];
3147  }
3148  }
3149  }
3150 
3151  // Clear seeds
3152  casadi_clear(res[oind], nnz_out(oind));
3153  }
3154  return 0;
3155  }
3156 
3157  void FunctionInternal::sz_work(size_t& sz_arg, size_t& sz_res,
3158  size_t& sz_iw, size_t& sz_w) const {
3159  sz_arg = this->sz_arg();
3160  sz_res = this->sz_res();
3161  sz_iw = this->sz_iw();
3162  sz_w = this->sz_w();
3163  }
3164 
3166  return sz_arg();
3167  }
3169  return sz_res();
3170  }
3172  return sz_iw();
3173  }
3175  return sz_w();
3176  }
3177 
3178  void FunctionInternal::alloc_arg(size_t sz_arg, bool persistent) {
3179  if (persistent) {
3180  sz_arg_per_ += sz_arg;
3181  } else {
3182  sz_arg_tmp_ = std::max(sz_arg_tmp_, sz_arg);
3183  }
3184  }
3185 
3186  void FunctionInternal::alloc_res(size_t sz_res, bool persistent) {
3187  if (persistent) {
3188  sz_res_per_ += sz_res;
3189  } else {
3190  sz_res_tmp_ = std::max(sz_res_tmp_, sz_res);
3191  }
3192  }
3193 
3194  void FunctionInternal::alloc_iw(size_t sz_iw, bool persistent) {
3195  if (persistent) {
3196  sz_iw_per_ += sz_iw;
3197  } else {
3198  sz_iw_tmp_ = std::max(sz_iw_tmp_, sz_iw);
3199  }
3200  }
3201 
3202  void FunctionInternal::alloc_w(size_t sz_w, bool persistent) {
3203  if (persistent) {
3204  sz_w_per_ += sz_w;
3205  } else {
3206  sz_w_tmp_ = std::max(sz_w_tmp_, sz_w);
3207  }
3208  }
3209 
3210  void FunctionInternal::alloc(const Function& f, bool persistent, int num_threads) {
3211  if (f.is_null()) return;
3212  size_t sz_arg, sz_res, sz_iw, sz_w;
3213  f.sz_work(sz_arg, sz_res, sz_iw, sz_w);
3214  alloc_arg(sz_arg*num_threads, persistent);
3215  alloc_res(sz_res*num_threads, persistent);
3216  alloc_iw(sz_iw*num_threads, persistent);
3217  alloc_w(sz_w*num_threads, persistent);
3218  registered_functions_.push_back(f);
3219  }
3220 
3221  Dict ProtoFunction::get_stats(void* mem) const {
3222  auto *m = static_cast<ProtoFunctionMemory*>(mem);
3223  // Add timing statistics
3224  Dict stats;
3225  for (const auto& s : m->fstats) {
3226  stats["n_call_" +s.first] = s.second.n_call;
3227  stats["t_wall_" +s.first] = s.second.t_wall;
3228  stats["t_proc_" +s.first] = s.second.t_proc;
3229  }
3230  return stats;
3231  }
3232 
3234  Dict stats = ProtoFunction::get_stats(mem);
3235  auto *m = static_cast<FunctionMemory*>(mem);
3236  casadi_assert(m->stats_available,
3237  "No stats available: Function '" + name_ + "' not set up. "
3238  "To get statistics, first evaluate it numerically.");
3239  return stats;
3240  }
3241 
3244  }
3245 
3246  bool FunctionInternal::fwdViaJac(casadi_int nfwd) const {
3247  if (!enable_forward_ && !enable_fd_) return true;
3248  if (jac_penalty_==-1) return false;
3249 
3250  // Heuristic 1: Jac calculated via forward mode likely cheaper
3251  if (jac_penalty_*static_cast<double>(nnz_in())<nfwd) return true;
3252 
3253  // Heuristic 2: Jac calculated via reverse mode likely cheaper
3254  double w = ad_weight();
3255  if (enable_reverse_ &&
3256  jac_penalty_*(1-w)*static_cast<double>(nnz_out())<w*static_cast<double>(nfwd))
3257  return true; // NOLINT
3258 
3259  return false;
3260  }
3261 
3262  bool FunctionInternal::adjViaJac(casadi_int nadj) const {
3263  if (!enable_reverse_) return true;
3264  if (jac_penalty_==-1) return false;
3265 
3266  // Heuristic 1: Jac calculated via reverse mode likely cheaper
3267  if (jac_penalty_*static_cast<double>(nnz_out())<nadj) return true;
3268 
3269  // Heuristic 2: Jac calculated via forward mode likely cheaper
3270  double w = ad_weight();
3271  if ((enable_forward_ || enable_fd_) &&
3272  jac_penalty_*w*static_cast<double>(nnz_in())<(1-w)*static_cast<double>(nadj))
3273  return true; // NOLINT
3274 
3275  return false;
3276  }
3277 
3279  return Dict();
3280  }
3281 
3283  call_forward(const std::vector<MX>& arg, const std::vector<MX>& res,
3284  const std::vector<std::vector<MX> >& fseed,
3285  std::vector<std::vector<MX> >& fsens,
3286  bool always_inline, bool never_inline) const {
3287  casadi_assert(!(always_inline && never_inline), "Inconsistent options");
3288  casadi_assert(!always_inline, "Class " + class_name() +
3289  " cannot be inlined in an MX expression");
3290 
3291  // Derivative information must be available
3292  casadi_assert(has_derivative(),
3293  "Derivatives cannot be calculated for " + name_);
3294 
3295  // Number of directional derivatives
3296  casadi_int nfwd = fseed.size();
3297  fsens.resize(nfwd);
3298 
3299  // Quick return if no seeds
3300  if (nfwd==0) return;
3301 
3302  // Check if seeds need to have dimensions corrected
3303  casadi_int npar = 1;
3304  for (auto&& r : fseed) {
3305  if (!matching_arg(r, npar)) {
3306  FunctionInternal::call_forward(arg, res, replace_fseed(fseed, npar),
3307  fsens, always_inline, never_inline);
3308  return;
3309  }
3310  }
3311 
3312  // Calculating full Jacobian and then multiplying
3313  if (fwdViaJac(nfwd)) {
3314  // Multiply the Jacobian from the right
3315  std::vector<MX> darg = arg;
3316  darg.insert(darg.end(), res.begin(), res.end());
3317  std::vector<MX> J = jacobian()(darg);
3318  // Join forward seeds
3319  std::vector<MX> v(nfwd), all_fseed(n_in_);
3320  for (size_t i = 0; i < n_in_; ++i) {
3321  for (size_t d = 0; d < nfwd; ++d) v[d] = vec(fseed.at(d).at(i));
3322  all_fseed[i] = horzcat(v);
3323  }
3324  // Calculate forward sensitivities
3325  std::vector<MX> all_fsens(n_out_);
3326  std::vector<MX>::const_iterator J_it = J.begin();
3327  for (size_t oind = 0; oind < n_out_; ++oind) {
3328  for (size_t iind = 0; iind < n_in_; ++iind) {
3329  // Add contribution
3330  MX a = mtimes(*J_it++, all_fseed[iind]);
3331  all_fsens[oind] = all_fsens[oind].is_empty(true) ? a : all_fsens[oind] + a;
3332  }
3333  }
3334  // Split forward sensitivities
3335  for (size_t d = 0; d < nfwd; ++d) fsens[d].resize(n_out_);
3336  for (size_t i = 0; i < n_out_; ++i) {
3337  v = horzsplit(all_fsens[i]);
3338  casadi_assert_dev(v.size() == nfwd);
3339  for (size_t d = 0; d < nfwd; ++d) fsens[d][i] = reshape(v[d], size_out(i));
3340  }
3341  } else {
3342  // Evaluate in batches
3343  casadi_assert_dev(enable_forward_ || enable_fd_);
3344  casadi_int max_nfwd = max_num_dir_;
3345  if (!enable_fd_) {
3346  while (!has_forward(max_nfwd)) max_nfwd/=2;
3347  }
3348  casadi_int offset = 0;
3349  while (offset<nfwd) {
3350  // Number of derivatives, in this batch
3351  casadi_int nfwd_batch = std::min(nfwd-offset, max_nfwd);
3352 
3353  // All inputs and seeds
3354  std::vector<MX> darg;
3355  darg.reserve(n_in_ + n_out_ + n_in_);
3356  darg.insert(darg.end(), arg.begin(), arg.end());
3357  darg.insert(darg.end(), res.begin(), res.end());
3358  std::vector<MX> v(nfwd_batch);
3359  for (casadi_int i=0; i<n_in_; ++i) {
3360  for (casadi_int d=0; d<nfwd_batch; ++d) v[d] = fseed[offset+d][i];
3361  darg.push_back(horzcat(v));
3362  }
3363 
3364  // Create the evaluation node
3365  Function dfcn = self().forward(nfwd_batch);
3366  std::vector<MX> x = dfcn(darg);
3367 
3368  casadi_assert_dev(x.size()==n_out_);
3369 
3370  // Retrieve sensitivities
3371  for (casadi_int d=0; d<nfwd_batch; ++d) fsens[offset+d].resize(n_out_);
3372  for (casadi_int i=0; i<n_out_; ++i) {
3373  if (size2_out(i)>0) {
3374  v = horzsplit(x[i], size2_out(i));
3375  casadi_assert_dev(v.size()==nfwd_batch);
3376  } else {
3377  v = std::vector<MX>(nfwd_batch, MX(size_out(i)));
3378  }
3379  for (casadi_int d=0; d<nfwd_batch; ++d) fsens[offset+d][i] = v[d];
3380  }
3381 
3382  // Update offset
3383  offset += nfwd_batch;
3384  }
3385  }
3386  }
3387 
3389  call_reverse(const std::vector<MX>& arg, const std::vector<MX>& res,
3390  const std::vector<std::vector<MX> >& aseed,
3391  std::vector<std::vector<MX> >& asens,
3392  bool always_inline, bool never_inline) const {
3393  casadi_assert(!(always_inline && never_inline), "Inconsistent options");
3394  casadi_assert(!always_inline, "Class " + class_name() +
3395  " cannot be inlined in an MX expression");
3396 
3397  // Derivative information must be available
3398  casadi_assert(has_derivative(),
3399  "Derivatives cannot be calculated for " + name_);
3400 
3401  // Number of directional derivatives
3402  casadi_int nadj = aseed.size();
3403  asens.resize(nadj);
3404 
3405  // Quick return if no seeds
3406  if (nadj==0) return;
3407 
3408  // Check if seeds need to have dimensions corrected
3409  casadi_int npar = 1;
3410  for (auto&& r : aseed) {
3411  if (!matching_res(r, npar)) {
3412  FunctionInternal::call_reverse(arg, res, replace_aseed(aseed, npar),
3413  asens, always_inline, never_inline);
3414  return;
3415  }
3416  }
3417 
3418  // Calculating full Jacobian and then multiplying likely cheaper
3419  if (adjViaJac(nadj)) {
3420  // Multiply the transposed Jacobian from the right
3421  std::vector<MX> darg = arg;
3422  darg.insert(darg.end(), res.begin(), res.end());
3423  std::vector<MX> J = jacobian()(darg);
3424  // Join adjoint seeds
3425  std::vector<MX> v(nadj), all_aseed(n_out_);
3426  for (size_t i = 0; i < n_out_; ++i) {
3427  for (size_t d = 0; d < nadj; ++d) v[d] = vec(aseed.at(d).at(i));
3428  all_aseed[i] = horzcat(v);
3429  }
3430  // Calculate adjoint sensitivities
3431  std::vector<MX> all_asens(n_in_);
3432  std::vector<MX>::const_iterator J_it = J.begin();
3433  for (size_t oind = 0; oind < n_out_; ++oind) {
3434  for (size_t iind = 0; iind < n_in_; ++iind) {
3435  // Add contribution
3436  MX a = mtimes((*J_it++).T(), all_aseed[oind]);
3437  all_asens[iind] = all_asens[iind].is_empty(true) ? a : all_asens[iind] + a;
3438  }
3439  }
3440  // Split adjoint sensitivities
3441  for (size_t d = 0; d < nadj; ++d) asens[d].resize(n_in_);
3442  for (size_t i = 0; i < n_in_; ++i) {
3443  v = horzsplit(all_asens[i]);
3444  casadi_assert_dev(v.size() == nadj);
3445  for (size_t d = 0; d < nadj; ++d) {
3446  if (asens[d][i].is_empty(true)) {
3447  asens[d][i] = reshape(v[d], size_in(i));
3448  } else {
3449  asens[d][i] += reshape(v[d], size_in(i));
3450  }
3451  }
3452  }
3453  } else {
3454  // Evaluate in batches
3455  casadi_assert_dev(enable_reverse_);
3456  casadi_int max_nadj = max_num_dir_;
3457 
3458  while (!has_reverse(max_nadj)) max_nadj/=2;
3459  casadi_int offset = 0;
3460  while (offset<nadj) {
3461  // Number of derivatives, in this batch
3462  casadi_int nadj_batch = std::min(nadj-offset, max_nadj);
3463 
3464  // All inputs and seeds
3465  std::vector<MX> darg;
3466  darg.reserve(n_in_ + n_out_ + n_out_);
3467  darg.insert(darg.end(), arg.begin(), arg.end());
3468  darg.insert(darg.end(), res.begin(), res.end());
3469  std::vector<MX> v(nadj_batch);
3470  for (casadi_int i=0; i<n_out_; ++i) {
3471  for (casadi_int d=0; d<nadj_batch; ++d) v[d] = aseed[offset+d][i];
3472  darg.push_back(horzcat(v));
3473  }
3474 
3475  // Create the evaluation node
3476  Function dfcn = self().reverse(nadj_batch);
3477  std::vector<MX> x = dfcn(darg);
3478  casadi_assert_dev(x.size()==n_in_);
3479 
3480  // Retrieve sensitivities
3481  for (casadi_int d=0; d<nadj_batch; ++d) asens[offset+d].resize(n_in_);
3482  for (casadi_int i=0; i<n_in_; ++i) {
3483  if (size2_in(i)>0) {
3484  v = horzsplit(x[i], size2_in(i));
3485  casadi_assert_dev(v.size()==nadj_batch);
3486  } else {
3487  v = std::vector<MX>(nadj_batch, MX(size_in(i)));
3488  }
3489  for (casadi_int d=0; d<nadj_batch; ++d) {
3490  if (asens[offset+d][i].is_empty(true)) {
3491  asens[offset+d][i] = v[d];
3492  } else {
3493  asens[offset+d][i] += v[d];
3494  }
3495  }
3496  }
3497  // Update offset
3498  offset += nadj_batch;
3499  }
3500  }
3501  }
3502 
3504  call_forward(const std::vector<SX>& arg, const std::vector<SX>& res,
3505  const std::vector<std::vector<SX> >& fseed,
3506  std::vector<std::vector<SX> >& fsens,
3507  bool always_inline, bool never_inline) const {
3508  casadi_assert(!(always_inline && never_inline), "Inconsistent options");
3509  if (fseed.empty()) { // Quick return if no seeds
3510  fsens.clear();
3511  return;
3512  }
3513  casadi_error("'forward' (SX) not defined for " + class_name());
3514  }
3515 
3517  call_reverse(const std::vector<SX>& arg, const std::vector<SX>& res,
3518  const std::vector<std::vector<SX> >& aseed,
3519  std::vector<std::vector<SX> >& asens,
3520  bool always_inline, bool never_inline) const {
3521  casadi_assert(!(always_inline && never_inline), "Inconsistent options");
3522  if (aseed.empty()) { // Quick return if no seeds
3523  asens.clear();
3524  return;
3525  }
3526  casadi_error("'reverse' (SX) not defined for " + class_name());
3527  }
3528 
3530  // If reverse mode derivatives unavailable, use forward
3531  if (!enable_reverse_) return 0;
3532 
3533  // If forward mode derivatives unavailable, use reverse
3534  if (!enable_forward_ && !enable_fd_) return 1;
3535 
3536  // Use the (potentially user set) option
3537  return ad_weight_;
3538  }
3539 
3541  // If reverse mode propagation unavailable, use forward
3542  if (!has_sprev()) return 0;
3543 
3544  // If forward mode propagation unavailable, use reverse
3545  if (!has_spfwd()) return 1;
3546 
3547  // Use the (potentially user set) option
3548  return ad_weight_sp_;
3549  }
3550 
3551  const SX FunctionInternal::sx_in(casadi_int ind) const {
3552  return SX::sym(name_in_.at(ind), sparsity_in(ind));
3553  }
3554 
3555  const SX FunctionInternal::sx_out(casadi_int ind) const {
3556  return SX::sym(name_out_.at(ind), sparsity_out(ind));
3557  }
3558 
3559  const DM FunctionInternal::dm_in(casadi_int ind) const {
3560  return DM::zeros(sparsity_in(ind));
3561  }
3562 
3563  const DM FunctionInternal::dm_out(casadi_int ind) const {
3564  return DM::zeros(sparsity_out(ind));
3565  }
3566 
3567  const std::vector<SX> FunctionInternal::sx_in() const {
3568  std::vector<SX> ret(n_in_);
3569  for (casadi_int i=0; i<ret.size(); ++i) {
3570  ret[i] = sx_in(i);
3571  }
3572  return ret;
3573  }
3574 
3575  const std::vector<SX> FunctionInternal::sx_out() const {
3576  std::vector<SX> ret(n_out_);
3577  for (casadi_int i=0; i<ret.size(); ++i) {
3578  ret[i] = sx_out(i);
3579  }
3580  return ret;
3581  }
3582 
3583  const std::vector<DM> FunctionInternal::dm_in() const {
3584  std::vector<DM> ret(n_in_);
3585  for (casadi_int i=0; i<ret.size(); ++i) {
3586  ret[i] = dm_in(i);
3587  }
3588  return ret;
3589  }
3590 
3591  const std::vector<DM> FunctionInternal::dm_out() const {
3592  std::vector<DM> ret(n_out_);
3593  for (casadi_int i=0; i<ret.size(); ++i) {
3594  ret[i] = dm_out(i);
3595  }
3596  return ret;
3597  }
3598 
3599  const MX FunctionInternal::mx_in(casadi_int ind) const {
3600  return MX::sym(name_in_.at(ind), sparsity_in(ind));
3601  }
3602 
3603  const MX FunctionInternal::mx_out(casadi_int ind) const {
3604  return MX::sym(name_out_.at(ind), sparsity_out(ind));
3605  }
3606 
3607  const std::vector<MX> FunctionInternal::mx_in() const {
3608  std::vector<MX> ret(n_in_);
3609  for (casadi_int i=0; i<ret.size(); ++i) {
3610  ret[i] = mx_in(i);
3611  }
3612  return ret;
3613  }
3614 
3615  const std::vector<MX> FunctionInternal::mx_out() const {
3616  std::vector<MX> ret(n_out_);
3617  for (casadi_int i=0; i<ret.size(); ++i) {
3618  ret[i] = mx_out(i);
3619  }
3620  return ret;
3621  }
3622 
3623  bool FunctionInternal::is_a(const std::string& type, bool recursive) const {
3624  return type == "FunctionInternal";
3625  }
3626 
3627  void FunctionInternal::merge(const std::vector<MX>& arg,
3628  std::vector<MX>& subs_from, std::vector<MX>& subs_to) const {
3629  }
3630 
3631  std::vector<MX> FunctionInternal::free_mx() const {
3632  casadi_error("'free_mx' only defined for 'MXFunction'");
3633  }
3634 
3635  std::vector<SX> FunctionInternal::free_sx() const {
3636  casadi_error("'free_sx' only defined for 'SXFunction'");
3637  }
3638 
3640  Function& vinit_fcn) const {
3641  casadi_error("'generate_lifted' only defined for 'MXFunction'");
3642  }
3643 
3645  casadi_error("'n_instructions' not defined for " + class_name());
3646  }
3647 
3648  casadi_int FunctionInternal::instruction_id(casadi_int k) const {
3649  casadi_error("'instruction_id' not defined for " + class_name());
3650  }
3651 
3652  std::vector<casadi_int> FunctionInternal::instruction_input(casadi_int k) const {
3653  casadi_error("'instruction_input' not defined for " + class_name());
3654  }
3655 
3656  double FunctionInternal::instruction_constant(casadi_int k) const {
3657  casadi_error("'instruction_constant' not defined for " + class_name());
3658  }
3659 
3660  std::vector<casadi_int> FunctionInternal::instruction_output(casadi_int k) const {
3661  casadi_error("'instruction_output' not defined for " + class_name());
3662  }
3663 
3664  MX FunctionInternal::instruction_MX(casadi_int k) const {
3665  casadi_error("'instruction_MX' not defined for " + class_name());
3666  }
3667 
3669  casadi_error("'instructions_sx' not defined for " + class_name());
3670  }
3671 
3672  casadi_int FunctionInternal::n_nodes() const {
3673  casadi_error("'n_nodes' not defined for " + class_name());
3674  }
3675 
3676  std::vector<MX>
3677  FunctionInternal::mapsum_mx(const std::vector<MX > &x,
3678  const std::string& parallelization) {
3679  if (x.empty()) return x;
3680  // Check number of arguments
3681  casadi_assert(x.size()==n_in_, "mapsum_mx: Wrong number_i of arguments");
3682  // Number of parallel calls
3683  casadi_int npar = 1;
3684  // Check/replace arguments
3685  std::vector<MX> x_mod(x.size());
3686  for (casadi_int i=0; i<n_in_; ++i) {
3687  if (check_mat(x[i].sparsity(), sparsity_in_[i], npar)) {
3688  x_mod[i] = replace_mat(x[i], sparsity_in_[i], npar);
3689  } else {
3690  // Mismatching sparsity: The following will throw an error message
3691  npar = 0;
3692  check_arg(x, npar);
3693  }
3694  }
3695 
3696  casadi_int n = 1;
3697  for (casadi_int i=0; i<x_mod.size(); ++i) {
3698  n = std::max(x_mod[i].size2() / size2_in(i), n);
3699  }
3700 
3701  std::vector<casadi_int> reduce_in;
3702  for (casadi_int i=0; i<x_mod.size(); ++i) {
3703  if (x_mod[i].size2()/size2_in(i)!=n) {
3704  reduce_in.push_back(i);
3705  }
3706  }
3707 
3708  Function ms = self().map("mapsum", parallelization, n, reduce_in, range(n_out_));
3709 
3710  // Call the internal function
3711  return ms(x_mod);
3712  }
3713 
3714  bool FunctionInternal::check_mat(const Sparsity& arg, const Sparsity& inp, casadi_int& npar) {
3715  // Matching dimensions
3716  if (arg.size()==inp.size()) return true;
3717  // Calling with a scalar - set all
3718  if (arg.is_scalar()) return true;
3719  // Vectors that are transposes of each other
3720  if (arg.is_vector() && inp.size()==std::make_pair(arg.size2(), arg.size1())) return true;
3721  // Horizontal repmat
3722  if (arg.size1()==inp.size1() && arg.size2()>0 && inp.size2()>0
3723  && inp.size2()%arg.size2()==0) return true;
3724  // Evaluate with multiple arguments
3725  if (npar!=-1 && arg.size1()==inp.size1() && arg.size2()>0 && inp.size2()>0
3726  && arg.size2()%(npar*inp.size2())==0) {
3727  npar *= arg.size2()/(npar*inp.size2());
3728  return true;
3729  }
3730  // Calling with empty matrix - set all to zero (after the structured branches above,
3731  // so that a 0-by-N argument can still be recognised as a parallel/repmat call)
3732  if (arg.is_empty()) return true;
3733  // No match
3734  return false;
3735  }
3736 
3737  std::vector<DM> FunctionInternal::nz_in(const std::vector<double>& arg) const {
3738  casadi_assert(nnz_in()==arg.size(),
3739  "Dimension mismatch. Expecting " + str(nnz_in()) +
3740  ", got " + str(arg.size()) + " instead.");
3741 
3742  std::vector<DM> ret = dm_in();
3743  casadi_int offset = 0;
3744  for (casadi_int i=0;i<n_in_;++i) {
3745  DM& r = ret.at(i);
3746  std::copy(arg.begin()+offset, arg.begin()+offset+nnz_in(i), r.ptr());
3747  offset+= nnz_in(i);
3748  }
3749  return ret;
3750  }
3751 
3752  std::vector<DM> FunctionInternal::nz_out(const std::vector<double>& res) const {
3753  casadi_assert(nnz_out()==res.size(),
3754  "Dimension mismatch. Expecting " + str(nnz_out()) +
3755  ", got " + str(res.size()) + " instead.");
3756 
3757  std::vector<DM> ret = dm_out();
3758  casadi_int offset = 0;
3759  for (casadi_int i=0;i<n_out_;++i) {
3760  DM& r = ret.at(i);
3761  std::copy(res.begin()+offset, res.begin()+offset+nnz_out(i), r.ptr());
3762  offset+= nnz_out(i);
3763  }
3764  return ret;
3765  }
3766 
3767  std::vector<double> FunctionInternal::nz_in(const std::vector<DM>& arg) const {
3768  // Disallow parallel inputs
3769  casadi_int npar = -1;
3770  if (!matching_arg(arg, npar)) {
3771  return nz_in(replace_arg(arg, npar));
3772  }
3773 
3774  std::vector<DM> arg2 = project_arg(arg, 1);
3775  std::vector<double> ret(nnz_in());
3776  casadi_int offset = 0;
3777  for (casadi_int i=0;i<n_in_;++i) {
3778  const double* e = arg2.at(i).ptr();
3779  std::copy(e, e+nnz_in(i), ret.begin()+offset);
3780  offset+= nnz_in(i);
3781  }
3782  return ret;
3783  }
3784 
3785  std::vector<double> FunctionInternal::nz_out(const std::vector<DM>& res) const {
3786  // Disallow parallel inputs
3787  casadi_int npar = -1;
3788  if (!matching_res(res, npar)) {
3789  return nz_out(replace_res(res, npar));
3790  }
3791 
3792  std::vector<DM> res2 = project_res(res, 1);
3793  std::vector<double> ret(nnz_out());
3794  casadi_int offset = 0;
3795  for (casadi_int i=0;i<n_out_;++i) {
3796  const double* e = res2.at(i).ptr();
3797  std::copy(e, e+nnz_out(i), ret.begin()+offset);
3798  offset+= nnz_out(i);
3799  }
3800  return ret;
3801  }
3802 
3803  void FunctionInternal::setup(void* mem, const double** arg, double** res,
3804  casadi_int* iw, double* w) const {
3805  set_work(mem, arg, res, iw, w);
3806  set_temp(mem, arg, res, iw, w);
3807  auto *m = static_cast<FunctionMemory*>(mem);
3808  m->stats_available = true;
3809  }
3810 
3812  for (auto&& i : mem_) {
3813  if (i!=nullptr) free_mem(i);
3814  }
3815  mem_.clear();
3816  }
3817 
3819  if (!derivative_of_.is_null()) {
3820  std::string n = derivative_of_.name();
3821  if (name_ == "jac_" + n) {
3822  return derivative_of_.n_in() + derivative_of_.n_out();
3823  } else if (name_ == "adj1_" + n) {
3825  }
3826  }
3827  // One by default
3828  return 1;
3829  }
3830 
3832  if (!derivative_of_.is_null()) {
3833  std::string n = derivative_of_.name();
3834  if (name_ == "jac_" + n) {
3835  return derivative_of_.n_in() * derivative_of_.n_out();
3836  } else if (name_ == "adj1_" + n) {
3837  return derivative_of_.n_in();
3838  }
3839  }
3840  // One by default
3841  return 1;
3842  }
3843 
3845  if (!derivative_of_.is_null()) {
3846  std::string n = derivative_of_.name();
3847  if (name_ == "jac_" + n || name_ == "adj1_" + n) {
3848  if (i < derivative_of_.n_in()) {
3849  // Input of nondifferentiated function
3850  return derivative_of_.sparsity_in(i);
3851  } else if (i < derivative_of_.n_in() + derivative_of_.n_out()) {
3852  // Output of nondifferentiated function, if needed
3855  } else {
3856  // Adjoint seeds
3858  }
3859  }
3860  }
3861  // Scalar by default
3862  return Sparsity::scalar();
3863  }
3864 
3866  if (!derivative_of_.is_null()) {
3867  std::string n = derivative_of_.name();
3868  if (name_ == "jac_" + n) {
3869  // Get Jacobian block
3870  casadi_int oind = i / derivative_of_.n_in(), iind = i % derivative_of_.n_in();
3871  const Sparsity& sp_in = derivative_of_.sparsity_in(iind);
3872  const Sparsity& sp_out = derivative_of_.sparsity_out(oind);
3873  // Handle Jacobian blocks corresponding to non-differentiable inputs or outputs
3874  if (!derivative_of_.is_diff_out(oind) || !derivative_of_.is_diff_in(iind)) {
3875  return Sparsity(sp_out.numel(), sp_in.numel());
3876  }
3877  // Is there a routine for calculating the Jacobian?
3878  if (derivative_of_->has_jac_sparsity(oind, iind)) {
3879  return derivative_of_.jac_sparsity(oind, iind);
3880  }
3881  // Construct sparsity pattern
3882  std::vector<casadi_int> row, colind;
3883  row.reserve(sp_out.nnz() * sp_in.nnz());
3884  colind.reserve(sp_in.numel() + 1);
3885  // Loop over input nonzeros
3886  for (casadi_int c1 = 0; c1 < sp_in.size2(); ++c1) {
3887  for (casadi_int k1 = sp_in.colind(c1); k1 < sp_in.colind(c1 + 1); ++k1) {
3888  casadi_int e1 = sp_in.row(k1) + sp_in.size1() * c1;
3889  // Update column offsets
3890  colind.resize(e1 + 1, row.size());
3891  // Add nonzeros corresponding to all nonzero outputs
3892  for (casadi_int c2 = 0; c2 < sp_out.size2(); ++c2) {
3893  for (casadi_int k2 = sp_out.colind(c2); k2 < sp_out.colind(c2 + 1); ++k2) {
3894  row.push_back(sp_out.row(k2) + sp_out.size1() * c2);
3895  }
3896  }
3897  }
3898  }
3899  // Finish column offsets
3900  colind.resize(sp_in.numel() + 1, row.size());
3901  // Assemble and return sparsity pattern
3902  return Sparsity(sp_out.numel(), sp_in.numel(), colind, row);
3903  } else if (name_ == "adj1_" + n) {
3904  // Adjoint sensitivity
3905  return derivative_of_.sparsity_in(i);
3906  }
3907  }
3908  // Scalar by default
3909  return Sparsity::scalar();
3910  }
3911 
3912  void* ProtoFunction::memory(int ind) const {
3913 #ifdef CASADI_WITH_THREAD
3914  std::lock_guard<std::mutex> lock(mtx_);
3915 #endif //CASADI_WITH_THREAD
3916  return mem_.at(ind);
3917  }
3918 
3919  bool ProtoFunction::has_memory(int ind) const {
3920  return ind<mem_.size();
3921  }
3922 
3924 #ifdef CASADI_WITH_THREAD
3925  std::lock_guard<std::mutex> lock(mtx_);
3926 #endif //CASADI_WITH_THREAD
3927  if (unused_.empty()) {
3928  check_mem_count(mem_.size()+1);
3929  // Allocate a new memory object
3930  void* m = alloc_mem();
3931  mem_.push_back(m);
3932  if (init_mem(m)) {
3933  casadi_error("Failed to create or initialize memory object");
3934  }
3935  return static_cast<int>(mem_.size()) - 1;
3936  } else {
3937  // Use an unused memory object
3938  int m = unused_.top();
3939  unused_.pop();
3940  return m;
3941  }
3942  }
3943 
3944  void ProtoFunction::release(int mem) const {
3945 #ifdef CASADI_WITH_THREAD
3946  std::lock_guard<std::mutex> lock(mtx_);
3947 #endif //CASADI_WITH_THREAD
3948  unused_.push(mem);
3949  }
3950 
3952  factory(const std::string& name,
3953  const std::vector<std::string>& s_in,
3954  const std::vector<std::string>& s_out,
3955  const Function::AuxOut& aux,
3956  const Dict& opts) const {
3957  return wrap().factory(name, s_in, s_out, aux, opts);
3958  }
3959 
3960  std::vector<std::string> FunctionInternal::get_function() const {
3961  // No functions
3962  return std::vector<std::string>();
3963  }
3964 
3965  bool FunctionInternal::has_function(const std::string& fname) const {
3966  std::vector<std::string> fnames = get_function();
3967  return std::find(fnames.begin(), fnames.end(), fname)!=fnames.end();
3968  }
3969 
3970  const Function& FunctionInternal::get_function(const std::string &name) const {
3971  casadi_error("'get_function' not defined for " + class_name());
3972  static Function singleton;
3973  return singleton;
3974  }
3975 
3977  std::map<FunctionInternal*, std::pair<Function, size_t> >& all_fun,
3978  const Function& dep, casadi_int max_depth) const {
3979  // Add, if not already in graph and not null
3980  if (!dep.is_null() && all_fun.find(dep.get()) == all_fun.end()) {
3981  size_t index = all_fun.size();
3982  all_fun[dep.get()] = std::make_pair(dep, index);
3983  // Also add its dependencies
3984  if (max_depth > 0) dep->find(all_fun, max_depth - 1);
3985  }
3986  }
3987 
3988  void FunctionInternal::find(std::map<FunctionInternal*, std::pair<Function, size_t> >& all_fun,
3989  casadi_int max_depth) const {
3990  for (auto&& f : registered_functions_) {
3991  add_embedded(all_fun, f, max_depth);
3992  }
3993  }
3994 
3995  std::vector<bool> FunctionInternal::
3996  which_depends(const std::string& s_in, const std::vector<std::string>& s_out,
3997  casadi_int order, bool tr) const {
3998  Function f = shared_from_this<Function>();
3999  f = f.wrap();
4000  return f.which_depends(s_in, s_out, order, tr);
4001  }
4002 
4004  const std::vector<std::pair<std::string, casadi_int> >& tasks) const {
4005  casadi_assert(tasks.empty(), "simplify passes not supported for " + class_name());
4006  return self();
4007  }
4008 
4010  casadi_error("'oracle' not defined for " + class_name());
4011  static Function singleton;
4012  return singleton;
4013  }
4014 
4015  Function FunctionInternal::slice(const std::string& name,
4016  const std::vector<casadi_int>& order_in,
4017  const std::vector<casadi_int>& order_out, const Dict& opts) const {
4018  return wrap().slice(name, order_in, order_out, opts);
4019  }
4020 
4022  // Check inputs
4023  for (casadi_int i=0; i<n_in_; ++i) {
4024  if (!sparsity_in_[i].is_scalar()) return false;
4025  }
4026  // Check outputs
4027  for (casadi_int i=0; i<n_out_; ++i) {
4028  if (!sparsity_out_[i].is_scalar()) return false;
4029  }
4030  // All are scalar
4031  return true;
4032  }
4033 
4034  void FunctionInternal::set_jac_sparsity(casadi_int oind, casadi_int iind, const Sparsity& sp) {
4035 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
4036  // Safe access to jac_sparsity_
4037  std::lock_guard<std::mutex> lock(jac_sparsity_mtx_);
4038 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
4039  casadi_int ind = iind + oind * n_in_;
4040  jac_sparsity_[false].resize(n_in_ * n_out_);
4041  jac_sparsity_[false].at(ind) = sp;
4042  jac_sparsity_[true].resize(n_in_ * n_out_);
4043  jac_sparsity_[true].at(ind) = to_compact(oind, iind, sp);
4044  }
4045 
4047  eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
4048  if (has_eval_dm()) {
4049  // Evaluate via eval_dm (less efficient)
4050  try {
4051  // Allocate input matrices
4052  std::vector<DM> argv(n_in_);
4053  for (casadi_int i=0; i<n_in_; ++i) {
4054  argv[i] = DM(sparsity_in_[i]);
4055  casadi_copy(arg[i], argv[i].nnz(), argv[i].ptr());
4056  }
4057 
4058  // Try to evaluate using eval_dm
4059  std::vector<DM> resv = eval_dm(argv);
4060 
4061  // Check number of outputs
4062  casadi_assert(resv.size()==n_out_,
4063  "Expected " + str(n_out_) + " outputs, got " + str(resv.size()) + ".");
4064 
4065  // Get outputs
4066  for (casadi_int i=0; i<n_out_; ++i) {
4067  if (resv[i].sparsity()!=sparsity_out_[i]) {
4068  if (resv[i].size()==size_out(i)) {
4069  resv[i] = project(resv[i], sparsity_out_[i]);
4070  } else {
4071  casadi_error("Shape mismatch for output " + str(i) + ": got " + resv[i].dim() + ", "
4072  "expected " + sparsity_out_[i].dim() + ".");
4073  }
4074  }
4075  if (res[i]) casadi_copy(resv[i].ptr(), resv[i].nnz(), res[i]);
4076  }
4077  } catch (KeyboardInterruptException&) {
4078  throw;
4079  } catch(std::exception& e) {
4080  casadi_error("Failed to evaluate 'eval_dm' for " + name_ + ":\n" + e.what());
4081  }
4082  // Successful return
4083  return 0;
4084  } else {
4085  casadi_error("'eval' not defined for " + class_name());
4086  }
4087  }
4088 
4089 
4090  void ProtoFunction::print_time(const std::map<std::string, FStats>& fstats) const {
4091  if (!print_time_) return;
4092  // Length of the name being printed
4093  size_t name_len=0;
4094  for (auto &&s : fstats) {
4095  name_len = std::max(s.first.size(), name_len);
4096  }
4097  name_len = std::max(name_.size(), name_len);
4098 
4099  // Print name with a given length. Format: "%NNs "
4100  char namefmt[10];
4101  sprint(namefmt, sizeof(namefmt), "%%%ds ", static_cast<casadi_int>(name_len));
4102 
4103  // Print header
4104  print(namefmt, name_.c_str());
4105 
4106  print(" : %8s %10s %8s %10s %9s\n", "t_proc", "(avg)", "t_wall", "(avg)", "n_eval");
4107 
4108 
4109  char buffer_proc[10];
4110  char buffer_wall[10];
4111  char buffer_proc_avg[10];
4112  char buffer_wall_avg[10];
4113 
4114  // Print keys
4115  for (const auto &s : fstats) {
4116  if (s.second.n_call!=0) {
4117  print(namefmt, s.first.c_str());
4118  format_time(buffer_proc, s.second.t_proc);
4119  format_time(buffer_wall, s.second.t_wall);
4120  format_time(buffer_proc_avg, s.second.t_proc/s.second.n_call);
4121  format_time(buffer_wall_avg, s.second.t_wall/s.second.n_call);
4122  print(" | %s (%s) %s (%s) %9d\n",
4123  buffer_proc, buffer_proc_avg,
4124  buffer_wall, buffer_wall_avg, s.second.n_call);
4125  }
4126  }
4127  }
4128 
4129  void ProtoFunction::format_time(char* buffer, double time) const {
4130  // Always of width 8
4131  casadi_assert_dev(time>=0);
4132  double log_time = log10(time);
4133  int magn = static_cast<int>(floor(log_time));
4134  int iprefix = static_cast<int>(floor(log_time/3));
4135  if (iprefix<-4) {
4136  sprint(buffer, 10, " 0");
4137  return;
4138  }
4139  if (iprefix>=5) {
4140  sprint(buffer, 10, " inf");
4141  return;
4142  }
4143  char prefixes[] = "TGMk munp";
4144  char prefix = prefixes[4-iprefix];
4145 
4146  int rem = magn-3*iprefix;
4147  double time_normalized = time/pow(10, 3*iprefix);
4148 
4149  if (rem==0) {
4150  sprint(buffer, 10, " %1.2f%cs", time_normalized, prefix);
4151  } else if (rem==1) {
4152  sprint(buffer, 10, " %2.2f%cs", time_normalized, prefix);
4153  } else {
4154  sprint(buffer, 10, "%3.2f%cs", time_normalized, prefix);
4155  }
4156  }
4157 
4158  void ProtoFunction::sprint(char* buf, size_t buf_sz, const char* fmt, ...) const {
4159  // Variable number of arguments
4160  va_list args;
4161  va_start(args, fmt);
4162  // Print to buffer
4163  casadi_int n = vsnprintf(buf, buf_sz, fmt, args);
4164  // Cleanup
4165  va_end(args);
4166  // Throw error if failure
4167  casadi_assert(n>=0 && n<buf_sz, "Print failure while processing '" + std::string(fmt) + "'");
4168  }
4169 
4170  void ProtoFunction::print(const char* fmt, ...) const {
4171  // Variable number of arguments
4172  va_list args;
4173  va_start(args, fmt);
4174  // Static & dynamic buffers
4175  char buf[256];
4176  size_t buf_sz = sizeof(buf);
4177  char* buf_dyn = nullptr;
4178  // Try to print with a small buffer
4179  casadi_int n = vsnprintf(buf, buf_sz, fmt, args);
4180  // Need a larger buffer?
4181  if (n>static_cast<casadi_int>(buf_sz)) {
4182  buf_sz = static_cast<size_t>(n+1);
4183  buf_dyn = new char[buf_sz];
4184  n = vsnprintf(buf_dyn, buf_sz, fmt, args);
4185  }
4186  // Print buffer content
4187  if (n>=0) uout() << (buf_dyn ? buf_dyn : buf) << std::flush;
4188  // Cleanup
4189  delete[] buf_dyn;
4190  va_end(args);
4191  // Throw error if failure
4192  casadi_assert(n>=0, "Print failure while processing '" + std::string(fmt) + "'");
4193  }
4194 
4196  call_gen(const MXVector& arg, MXVector& res, casadi_int npar,
4197  bool always_inline, bool never_inline) const {
4198  if (npar==1) {
4199  eval_mx(arg, res, always_inline, never_inline);
4200  } else {
4201  // Split it up arguments
4202  std::vector<std::vector<MX>> v(npar, arg);
4203  std::vector<MX> t;
4204  for (int i=0; i<n_in_; ++i) {
4205  if (arg[i].size2()!=size2_in(i)) {
4206  t = horzsplit(arg[i], size2_in(i));
4207  casadi_assert_dev(t.size()==npar);
4208  for (int p=0; p<npar; ++p) v[p][i] = t[p];
4209  }
4210  }
4211  // Unroll the loop
4212  for (int p=0; p<npar; ++p) {
4213  eval_mx(v[p], t, always_inline, never_inline);
4214  v[p] = t;
4215  }
4216  // Concatenate results
4217  t.resize(npar);
4218  res.resize(n_out_);
4219  for (int i=0; i<n_out_; ++i) {
4220  for (int p=0; p<npar; ++p) t[p] = v[p][i];
4221  res[i] = horzcat(t);
4222  }
4223  }
4224  }
4225 
4227  switch (status) {
4228  case SOLVER_RET_LIMITED: return "SOLVER_RET_LIMITED";
4229  case SOLVER_RET_NAN: return "SOLVER_RET_NAN";
4230  case SOLVER_RET_SUCCESS: return "SOLVER_RET_SUCCESS";
4231  default: return "SOLVER_RET_UNKNOWN";
4232  }
4233  }
4234 
4236  s.version("ProtoFunction", 2);
4237  s.pack("ProtoFunction::name", name_);
4238  s.pack("ProtoFunction::verbose", verbose_);
4239  s.pack("ProtoFunction::print_time", print_time_);
4240  s.pack("ProtoFunction::record_time", record_time_);
4241  s.pack("ProtoFunction::regularity_check", regularity_check_);
4242  s.pack("ProtoFunction::error_on_fail", error_on_fail_);
4243  }
4244 
4246  int version = s.version("ProtoFunction", 1, 2);
4247  s.unpack("ProtoFunction::name", name_);
4248  s.unpack("ProtoFunction::verbose", verbose_);
4249  s.unpack("ProtoFunction::print_time", print_time_);
4250  s.unpack("ProtoFunction::record_time", record_time_);
4251  if (version >= 2) s.unpack("ProtoFunction::regularity_check", regularity_check_);
4252  if (version >= 2) s.unpack("ProtoFunction::error_on_fail", error_on_fail_);
4253  }
4254 
4256  s.pack("FunctionInternal::base_function", serialize_base_function());
4257  }
4258 
4261  s.version("FunctionInternal", 9);
4262  s.pack("FunctionInternal::is_diff_in", is_diff_in_);
4263  s.pack("FunctionInternal::is_diff_out", is_diff_out_);
4264  s.pack("FunctionInternal::sp_in", sparsity_in_);
4265  s.pack("FunctionInternal::sp_out", sparsity_out_);
4266  s.pack("FunctionInternal::name_in", name_in_);
4267  s.pack("FunctionInternal::name_out", name_out_);
4268 
4269  s.pack("FunctionInternal::jit", jit_);
4270  s.pack("FunctionInternal::jit_cleanup", jit_cleanup_);
4271  s.pack("FunctionInternal::jit_serialize", jit_serialize_);
4272  if (jit_serialize_=="link" || jit_serialize_=="embed") {
4273  s.pack("FunctionInternal::jit_library", compiler_.library());
4274  if (jit_serialize_=="embed") {
4275  auto binary_ptr =
4276  Filesystem::ifstream_ptr(compiler_.library(), std::ios_base::binary, true);
4277  casadi_assert(binary_ptr, "Could not open library '" + compiler_.library() + "'.");
4278  s.pack("FunctionInternal::jit_binary", *binary_ptr);
4279  }
4280  }
4281  s.pack("FunctionInternal::jit_temp_suffix", jit_temp_suffix_);
4282  s.pack("FunctionInternal::jit_base_name", jit_base_name_);
4283  s.pack("FunctionInternal::jit_options", jit_options_);
4284  s.pack("FunctionInternal::codegen_options", codegen_options_);
4285  s.pack("FunctionInternal::compiler_plugin", compiler_plugin_);
4286  s.pack("FunctionInternal::has_refcount", has_refcount_);
4287 
4288  s.pack("FunctionInternal::cache_init", cache_init_);
4289 
4290  s.pack("FunctionInternal::derivative_of", derivative_of_);
4291 
4292  s.pack("FunctionInternal::jac_penalty", jac_penalty_);
4293 
4294  s.pack("FunctionInternal::enable_forward", enable_forward_);
4295  s.pack("FunctionInternal::enable_reverse", enable_reverse_);
4296  s.pack("FunctionInternal::enable_jacobian", enable_jacobian_);
4297  s.pack("FunctionInternal::enable_fd", enable_fd_);
4298  s.pack("FunctionInternal::enable_forward_op", enable_forward_op_);
4299  s.pack("FunctionInternal::enable_reverse_op", enable_reverse_op_);
4300  s.pack("FunctionInternal::enable_jacobian_op", enable_jacobian_op_);
4301  s.pack("FunctionInternal::enable_fd_op", enable_fd_op_);
4302 
4303  s.pack("FunctionInternal::ad_weight", ad_weight_);
4304  s.pack("FunctionInternal::ad_weight_sp", ad_weight_sp_);
4305  s.pack("FunctionInternal::always_inline", always_inline_);
4306  s.pack("FunctionInternal::never_inline", never_inline_);
4307 
4308  s.pack("FunctionInternal::max_num_dir", max_num_dir_);
4309 
4310  s.pack("FunctionInternal::inputs_check", inputs_check_);
4311 
4312  s.pack("FunctionInternal::fd_step", fd_step_);
4313 
4314  s.pack("FunctionInternal::fd_method", fd_method_);
4315  s.pack("FunctionInternal::print_in", print_in_);
4316  s.pack("FunctionInternal::print_out", print_out_);
4317  s.pack("FunctionInternal::print_canonical", print_canonical_);
4318  s.pack("FunctionInternal::max_io", max_io_);
4319  s.pack("FunctionInternal::dump_in", dump_in_);
4320  s.pack("FunctionInternal::dump_out", dump_out_);
4321  s.pack("FunctionInternal::dump_dir", dump_dir_);
4322  s.pack("FunctionInternal::dump_format", dump_format_);
4323  s.pack("FunctionInternal::forward_options", forward_options_);
4324  s.pack("FunctionInternal::reverse_options", reverse_options_);
4325  s.pack("FunctionInternal::jacobian_options", jacobian_options_);
4326  s.pack("FunctionInternal::der_options", der_options_);
4327  s.pack("FunctionInternal::custom_jacobian", custom_jacobian_);
4328  s.pack("FunctionInternal::registered_functions", registered_functions_);
4329 
4330  s.pack("FunctionInternal::sz_arg_per", sz_arg_per_);
4331  s.pack("FunctionInternal::sz_res_per", sz_res_per_);
4332  s.pack("FunctionInternal::sz_iw_per", sz_iw_per_);
4333  s.pack("FunctionInternal::sz_w_per", sz_w_per_);
4334  s.pack("FunctionInternal::sz_arg_tmp", sz_arg_tmp_);
4335  s.pack("FunctionInternal::sz_res_tmp", sz_res_tmp_);
4336  s.pack("FunctionInternal::sz_iw_tmp", sz_iw_tmp_);
4337  s.pack("FunctionInternal::sz_w_tmp", sz_w_tmp_);
4338  }
4339 
4341  eval_ = nullptr;
4342  checkout_ = nullptr;
4343  release_ = nullptr;
4344  incref_ = nullptr;
4345  decref_ = nullptr;
4346  int version = s.version("FunctionInternal", 1, 9);
4347  s.unpack("FunctionInternal::is_diff_in", is_diff_in_);
4348  s.unpack("FunctionInternal::is_diff_out", is_diff_out_);
4349  s.unpack("FunctionInternal::sp_in", sparsity_in_);
4350  s.unpack("FunctionInternal::sp_out", sparsity_out_);
4351  s.unpack("FunctionInternal::name_in", name_in_);
4352  s.unpack("FunctionInternal::name_out", name_out_);
4353 
4354  s.unpack("FunctionInternal::jit", jit_);
4355  s.unpack("FunctionInternal::jit_cleanup", jit_cleanup_);
4356  if (version < 2) {
4357  jit_serialize_ = "source";
4358  } else {
4359  s.unpack("FunctionInternal::jit_serialize", jit_serialize_);
4360  }
4361  if (jit_serialize_=="link" || jit_serialize_=="embed") {
4362  std::string library;
4363  s.unpack("FunctionInternal::jit_library", library);
4364  if (jit_serialize_=="embed") {
4365  // If file already exist
4366  auto binary_ptr = Filesystem::ifstream_ptr(library, std::ios_base::binary, false);
4367  if (binary_ptr) { // library exists
4368  // Ignore packed contents
4369  std::stringstream ss;
4370  s.unpack("FunctionInternal::jit_binary", ss);
4371  } else { // library does not exist
4372  auto binary_ptr = Filesystem::ofstream_ptr(library, std::ios_base::binary);
4373  s.unpack("FunctionInternal::jit_binary", *binary_ptr);
4374  }
4375  }
4376  compiler_ = Importer(library, "dll");
4377  }
4378  s.unpack("FunctionInternal::jit_temp_suffix", jit_temp_suffix_);
4379  s.unpack("FunctionInternal::jit_base_name", jit_base_name_);
4380  s.unpack("FunctionInternal::jit_options", jit_options_);
4381  if (version >= 9) {
4382  s.unpack("FunctionInternal::codegen_options", codegen_options_);
4383  }
4384  s.unpack("FunctionInternal::compiler_plugin", compiler_plugin_);
4385  s.unpack("FunctionInternal::has_refcount", has_refcount_);
4386 
4387  if (version >= 6) {
4388  s.unpack("FunctionInternal::cache_init", cache_init_);
4389  }
4390 
4391  s.unpack("FunctionInternal::derivative_of", derivative_of_);
4392 
4393  s.unpack("FunctionInternal::jac_penalty", jac_penalty_);
4394 
4395  s.unpack("FunctionInternal::enable_forward", enable_forward_);
4396  s.unpack("FunctionInternal::enable_reverse", enable_reverse_);
4397  s.unpack("FunctionInternal::enable_jacobian", enable_jacobian_);
4398  s.unpack("FunctionInternal::enable_fd", enable_fd_);
4399  s.unpack("FunctionInternal::enable_forward_op", enable_forward_op_);
4400  s.unpack("FunctionInternal::enable_reverse_op", enable_reverse_op_);
4401  s.unpack("FunctionInternal::enable_jacobian_op", enable_jacobian_op_);
4402  s.unpack("FunctionInternal::enable_fd_op", enable_fd_op_);
4403 
4404  s.unpack("FunctionInternal::ad_weight", ad_weight_);
4405  s.unpack("FunctionInternal::ad_weight_sp", ad_weight_sp_);
4406  s.unpack("FunctionInternal::always_inline", always_inline_);
4407  s.unpack("FunctionInternal::never_inline", never_inline_);
4408 
4409  s.unpack("FunctionInternal::max_num_dir", max_num_dir_);
4410 
4411  if (version < 3) s.unpack("FunctionInternal::regularity_check", regularity_check_);
4412 
4413  s.unpack("FunctionInternal::inputs_check", inputs_check_);
4414 
4415  s.unpack("FunctionInternal::fd_step", fd_step_);
4416 
4417  s.unpack("FunctionInternal::fd_method", fd_method_);
4418  s.unpack("FunctionInternal::print_in", print_in_);
4419  s.unpack("FunctionInternal::print_out", print_out_);
4420  if (version >= 7) {
4421  s.unpack("FunctionInternal::print_canonical", print_canonical_);
4422  } else {
4423  print_canonical_ = false;
4424  }
4425  if (version >= 4) {
4426  s.unpack("FunctionInternal::max_io", max_io_);
4427  } else {
4428  max_io_ = 10000;
4429  }
4430  s.unpack("FunctionInternal::dump_in", dump_in_);
4431  s.unpack("FunctionInternal::dump_out", dump_out_);
4432  s.unpack("FunctionInternal::dump_dir", dump_dir_);
4433  s.unpack("FunctionInternal::dump_format", dump_format_);
4434  // Makes no sense to dump a Function that is being deserialized
4435  dump_ = false;
4436  s.unpack("FunctionInternal::forward_options", forward_options_);
4437  s.unpack("FunctionInternal::reverse_options", reverse_options_);
4438  if (version>=5) {
4439  s.unpack("FunctionInternal::jacobian_options", jacobian_options_);
4440  s.unpack("FunctionInternal::der_options", der_options_);
4441  }
4442  s.unpack("FunctionInternal::custom_jacobian", custom_jacobian_);
4443  if (version >= 8) {
4444  s.unpack("FunctionInternal::registered_functions", registered_functions_);
4445  }
4446  if (!custom_jacobian_.is_null()) {
4447  casadi_assert_dev(custom_jacobian_.name() == "jac_" + name_);
4449  }
4450  s.unpack("FunctionInternal::sz_arg_per", sz_arg_per_);
4451  s.unpack("FunctionInternal::sz_res_per", sz_res_per_);
4452  s.unpack("FunctionInternal::sz_iw_per", sz_iw_per_);
4453  s.unpack("FunctionInternal::sz_w_per", sz_w_per_);
4454  s.unpack("FunctionInternal::sz_arg_tmp", sz_arg_tmp_);
4455  s.unpack("FunctionInternal::sz_res_tmp", sz_res_tmp_);
4456  s.unpack("FunctionInternal::sz_iw_tmp", sz_iw_tmp_);
4457  s.unpack("FunctionInternal::sz_w_tmp", sz_w_tmp_);
4458 
4459  n_in_ = sparsity_in_.size();
4460  n_out_ = sparsity_out_.size();
4461  eval_ = nullptr;
4462  checkout_ = nullptr;
4463  release_ = nullptr;
4464  dump_count_ = 0;
4465  }
4466 
4468  serialize_type(s);
4469  serialize_body(s);
4470  }
4471 
4473  std::string base_function;
4474  s.unpack("FunctionInternal::base_function", base_function);
4475  auto it = FunctionInternal::deserialize_map.find(base_function);
4476  casadi_assert(it!=FunctionInternal::deserialize_map.end(),
4477  "FunctionInternal::deserialize: not found '" + base_function + "'");
4478 
4479  Function ret;
4480  ret.own(it->second(s));
4481  ret->finalize();
4482  return ret;
4483  }
4484 
4485  /*
4486  * Keys are given by serialize_base_function()
4487  */
4488  std::map<std::string, ProtoFunction* (*)(DeserializingStream&)>
4490  {"MXFunction", MXFunction::deserialize},
4491  {"SXFunction", SXFunction::deserialize},
4492  {"Interpolant", Interpolant::deserialize},
4493  {"Switch", Switch::deserialize},
4494  {"ForwardDiff", ForwardDiff::deserialize},
4495  {"BackwardDiff", BackwardDiff::deserialize},
4496  {"CentralDiff", CentralDiff::deserialize},
4497  {"Smoothing", Smoothing::deserialize},
4498 
4499  {"Map", Map::deserialize},
4500  {"MapSum", MapSum::deserialize},
4501  {"Nlpsol", Nlpsol::deserialize},
4502  {"Rootfinder", Rootfinder::deserialize},
4503  {"Integrator", Integrator::deserialize},
4504  {"External", External::deserialize},
4505  {"Conic", Conic::deserialize},
4506  {"FmuFunction", FmuFunction::deserialize},
4507  {"BlazingSplineFunction", BlazingSplineFunction::deserialize},
4508  {"Onnx", OnnxFunction::deserialize}
4509  };
4510 
4511 } // namespace casadi
static ProtoFunction * deserialize(DeserializingStream &s)
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
static int eval_sx(const Function &f, const SXElem **arg, SXElem **res)
Definition: call_sx.hpp:63
static std::vector< MX > create(const Function &fcn, const std::vector< MX > &arg)
Create function call node.
static ProtoFunction * deserialize(DeserializingStream &s)
Helper class for C code generation.
void scope_add_cleanup(const std::string &code)
Add cleanup code to be executed upon scope exit.
const std::set< std::string > & local_mutexes(const Function &f) const
Get all mutex names associated with a function.
void add_io_sparsities(const std::string &name, const std::vector< Sparsity > &sp_in, const std::vector< Sparsity > &sp_out)
Add io sparsity patterns of a function.
void scope_enter()
Enter a local scope.
std::string constant(const std::vector< casadi_int > &v)
Represent an array constant; adding it when new.
void add(const Function &f, bool with_jac_sparsity=false)
Add a function (name generated)
void flush(std::ostream &s)
Flush the buffer to a stream of choice.
std::string to_mex(const Sparsity &sp, const std::string &arg)
Create matrix in MATLAB's MEX format.
std::string printf(const std::string &str, const std::vector< std::string > &arg=std::vector< std::string >())
Printf.
bool thread_safe() const
Emit thead safe code chekout/release?
static std::string array(const std::string &type, const std::string &name, casadi_int len, const std::string &def=std::string())
void generate_dump(const Function &f, const std::string &arr, bool is_input)
Generate dump_in or dump_out code for a function call.
std::string generate(const std::string &prefix="")
Generate file(s)
void generate_print(const Function &f, const std::string &arr, bool is_input)
Generate print_in or print_out code for a function call.
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
std::stringstream header
std::string from_mex(std::string &arg, const std::string &res, std::size_t res_off, const Sparsity &sp_res, const std::string &w)
Get matrix from MATLAB's MEX format.
std::string res(casadi_int i) const
Refer to resuly.
std::string declare(std::string s)
Declare a function.
void scope_exit()
Exit a local scope.
std::string local_mutex(const Function &f, const std::string &name) const
Access a static mutex associated with a function.
std::vector< FunctionMeta > added_functions_
std::string shorthand(const std::string &name) const
Get a shorthand.
std::stringstream body
void scope_return(const std::string &value)
Return from a scope with a value.
std::stringstream auxiliaries
void define_local_mutex(const Function &f, const std::string &name)
Declare a static mutex associated with a function.
void deserialize(DeserializingStream &s, SDPToSOCPMem &m)
Definition: conic.cpp:958
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
Definition: external.cpp:508
static std::string absolute(const std::string &path)
Definition: filesystem.cpp:78
static bool is_absolute(const std::string &path)
Definition: filesystem.cpp:162
static std::string ensure_trailing_slash(const std::string &path)
Definition: filesystem.cpp:155
static bool is_enabled()
Definition: filesystem.cpp:83
static std::unique_ptr< std::ostream > ofstream_ptr(const std::string &path, std::ios_base::openmode mode=std::ios_base::out)
Definition: filesystem.cpp:115
static std::unique_ptr< std::istream > ifstream_ptr(const std::string &path, std::ios_base::openmode mode=std::ios_base::in, bool fail=true)
Definition: filesystem.cpp:135
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize without type information.
static ProtoFunction * deserialize(DeserializingStream &s)
Internal class for Function.
bool has_refcount_
Reference counting in codegen?
casadi_int size1_in(casadi_int ind) const
Input/output dimensions.
virtual std::string codegen_mem_type() const
Thread-local memory object type.
std::string jit_serialize_
Serialize behaviour.
void finish_trace(std::ostream &trace, double **res, int ret) const
std::string diff_prefix(const std::string &prefix) const
Determine prefix for differentiated functions.
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
Dict get_stats(void *mem) const override
Get all statistics.
void init(const Dict &opts) override
Initialize.
virtual void call_forward(const std::vector< MX > &arg, const std::vector< MX > &res, const std::vector< std::vector< MX > > &fseed, std::vector< std::vector< MX > > &fsens, bool always_inline, bool never_inline) const
Forward mode AD, virtual functions overloaded in derived classes.
void finalize() override
Finalize the object creation.
std::vector< M > project_arg(const std::vector< M > &arg, casadi_int npar) const
Project sparsities.
Function forward(casadi_int nfwd) const
Return function that calculates forward derivatives.
virtual bool has_sprev() const
Is the class able to propagate seeds through the algorithm?
virtual size_t codegen_sz_res(const CodeGenerator &g) const
Get required lengths, for codegen.
const std::vector< DM > dm_in() const
Get function input(s) and output(s)
virtual Function slice(const std::string &name, const std::vector< casadi_int > &order_in, const std::vector< casadi_int > &order_out, const Dict &opts) const
returns a new function with a selection of inputs/outputs of the original
void tocache_if_missing(Function &f, const std::string &suffix="") const
Save function to cache, only if missing.
Function map(casadi_int n, const std::string &parallelization) const
Generate/retrieve cached serial map.
double jac_penalty_
Penalty factor for using a complete Jacobian to calculate directional derivatives.
void call_gen(const MXVector &arg, MXVector &res, casadi_int npar, bool always_inline, bool never_inline) const
Call a function, overloaded.
virtual casadi_int n_nodes() const
Number of nodes in the algorithm.
std::vector< Sparsity > sparsity_in_
Input and output sparsity.
std::vector< Sparsity > jac_sparsity_[2]
Cache for sparsities of the Jacobian blocks.
virtual double ad_weight() const
Weighting factor for chosing forward/reverse mode.
virtual const std::vector< SX > sx_in() const
Get function input(s) and output(s)
static Function deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
virtual void codegen_decref(CodeGenerator &g) const
Codegen decref for dependencies.
virtual void export_code(const std::string &lang, std::ostream &stream, const Dict &options) const
Export function in a specific language.
virtual bool has_forward(casadi_int nfwd) const
Return function that calculates forward derivatives.
void print_in(std::ostream &stream, const double **arg, bool truncate) const
Print inputs.
void generate_in(const std::string &fname, const double **arg) const
Export an input file that can be passed to generate C code with a main.
static std::string forward_name(const std::string &fcn, casadi_int nfwd)
Helper function: Get name of forward derivative function.
virtual void jit_dependencies(const std::string &fname)
Jit dependencies.
virtual size_t codegen_sz_arg(const CodeGenerator &g) const
Get required lengths, for codegen.
void check_arg(const std::vector< M > &arg, casadi_int &npar) const
Check if input arguments have correct length and dimensions.
std::vector< std::vector< M > > replace_fseed(const std::vector< std::vector< M >> &fseed, casadi_int npar) const
Replace 0-by-0 forward seeds.
std::vector< bool > is_diff_out_
virtual bool adjViaJac(casadi_int nadj) const
Calculate derivatives by multiplying the full Jacobian and multiplying.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
virtual MX instruction_MX(casadi_int k) const
get MX expression associated with instruction
void alloc_res(size_t sz_res, bool persistent=false)
Ensure required length of res field.
std::string jit_name_
Name if jit source file.
std::string compiler_plugin_
Just-in-time compiler.
virtual Function factory(const std::string &name, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const Function::AuxOut &aux, const Dict &opts) const
virtual size_t codegen_sz_iw(const CodeGenerator &g) const
Get required lengths, for codegen.
casadi_release_t release_
Release redirected to a C function.
std::pair< casadi_int, casadi_int > size_in(casadi_int ind) const
Input/output dimensions.
virtual bool has_eval_dm() const
Evaluate with DM matrices.
virtual int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const
Evaluate numerically.
casadi_int numel_out() const
Number of input/output elements.
std::string definition() const
Get function signature: name:(inputs)->(outputs)
const Sparsity & sparsity_in(casadi_int ind) const
Input/output sparsity.
static std::string get_jit_directory(const Dict &jit_options)
Get JIT directory from options.
Sparsity to_compact(casadi_int oind, casadi_int iind, const Sparsity &sp) const
Convert to compact Jacobian sparsity pattern.
Sparsity get_jac_sparsity_hierarchical_symm(casadi_int oind, casadi_int iind) const
void * user_data_
User-set field.
std::vector< M > replace_arg(const std::vector< M > &arg, casadi_int npar) const
Replace 0-by-0 inputs.
virtual const std::vector< MX > mx_in() const
Get function input(s) and output(s)
virtual void call_reverse(const std::vector< MX > &arg, const std::vector< MX > &res, const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens, bool always_inline, bool never_inline) const
Reverse mode, virtual functions overloaded in derived classes.
virtual bool has_jac_sparsity(casadi_int oind, casadi_int iind) const
Get Jacobian sparsity.
void alloc_arg(size_t sz_arg, bool persistent=false)
Ensure required length of arg field.
void print_dimensions(std::ostream &stream) const
Print dimensions of inputs and outputs.
virtual void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const
Set the (persistent) work vectors.
std::string signature_unrolled(const std::string &fname) const
Code generate the function.
virtual size_t codegen_sz_w(const CodeGenerator &g) const
Get required lengths, for codegen.
virtual bool is_a(const std::string &type, bool recursive) const
Check if the function is of a particular type.
Dict codegen_options_
Options of the code generator of jit.
const std::vector< DM > dm_out() const
Get function input(s) and output(s)
Sparsity & jac_sparsity(casadi_int oind, casadi_int iind, bool compact, bool symmetric) const
Get Jacobian sparsity.
static std::map< std::string, ProtoFunction *(*)(DeserializingStream &)> deserialize_map
double ad_weight_
Weighting factor for derivative calculation and sparsity pattern calculation.
casadi_int numel_in() const
Number of input/output elements.
virtual bool has_jacobian() const
Return Jacobian of all input elements with respect to all output elements.
Sparsity from_compact(casadi_int oind, casadi_int iind, const Sparsity &sp) const
Convert from compact Jacobian sparsity pattern.
~FunctionInternal() override=0
Destructor.
std::vector< Function > registered_functions_
void set_jac_sparsity(casadi_int oind, casadi_int iind, const Sparsity &sp)
Populate jac_sparsity_ and jac_sparsity_compact_ during initialization.
bool inputs_check_
Errors are thrown if numerical values of inputs look bad.
virtual std::vector< SX > free_sx() const
Get free variables (SX)
static void print_canonical(std::ostream &stream, const Sparsity &sp, const double *nz)
Print canonical representation of a numeric matrix.
bool jit_
Use just-in-time compiler.
void add_embedded(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, const Function &dep, casadi_int max_depth) const
eval_t eval_
Numerical evaluation redirected to a C function.
bool has_refcount_in_deps_
Reference counting in dependent functions.
bool has_derivative() const
Can derivatives be calculated in any way?
virtual std::vector< std::string > get_free() const
Print free variables.
Function wrap() const
Wrap in an Function instance consisting of only one MX call.
virtual std::vector< MX > free_mx() const
Get free variables (MX)
void * alloc_mem() const override
Create memory block.
virtual bool uses_output() const
Do the derivative functions need nondifferentiated outputs?
virtual void find(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, casadi_int max_depth) const
virtual double sp_weight() const
Weighting factor for chosing forward/reverse mode,.
std::string codegen_mem(CodeGenerator &g, const std::string &index="mem") const
Get thread-local memory object.
virtual SX instructions_sx() const
get SX expression associated with instructions
Sparsity get_jac_sparsity_hierarchical(casadi_int oind, casadi_int iind) const
A flavor of get_jac_sparsity_gen that does hierarchical block structure recognition.
virtual void generate_lifted(Function &vdef_fcn, Function &vinit_fcn) const
Extract the functions needed for the Lifted Newton method.
bool incache(const std::string &fname, Function &f, const std::string &suffix="") const
Get function in cache.
virtual Function simplify_passes(const std::vector< std::pair< std::string, casadi_int > > &tasks) const
Apply an ordered list of simplify passes (used by transform)
virtual std::string codegen_name(const CodeGenerator &g, bool ns=true) const
Get name in codegen.
size_t n_in_
Number of inputs and outputs.
void codegen(CodeGenerator &g, const std::string &fname) const
Generate code the function.
virtual casadi_int instruction_id(casadi_int k) const
Get an atomic operation operator index.
size_t sz_res() const
Get required length of res field.
virtual void eval_mx(const MXVector &arg, MXVector &res, bool always_inline, bool never_inline) const
Evaluate with symbolic matrices.
virtual void codegen_release(CodeGenerator &g) const
Codegen for release.
virtual std::vector< casadi_int > instruction_input(casadi_int k) const
Get the (integer) input arguments of an atomic operation.
virtual size_t get_n_out()
Are all inputs and outputs scalar.
virtual void codegen_body(CodeGenerator &g) const
Generate code for the function body.
virtual int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w, void *mem, bool always_inline, bool never_inline) const
Evaluate with symbolic scalars.
casadi_int size2_out(casadi_int ind) const
Input/output dimensions.
virtual void codegen_alloc_mem(CodeGenerator &g) const
Codegen decref for alloc_mem.
virtual void set_temp(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const
Set the (temporary) work vectors.
bool matching_arg(const std::vector< M > &arg, casadi_int &npar) const
Check if input arguments that needs to be replaced.
std::vector< M > project_res(const std::vector< M > &arg, casadi_int npar) const
Project sparsities.
casadi_int size1_out(casadi_int ind) const
Input/output dimensions.
virtual void codegen_checkout(CodeGenerator &g) const
Codegen for checkout.
void get_partition(casadi_int iind, casadi_int oind, Sparsity &D1, Sparsity &D2, bool compact, bool symmetric, bool allow_forward, bool allow_reverse) const
Get the unidirectional or bidirectional partition.
std::pair< casadi_int, casadi_int > size_out(casadi_int ind) const
Input/output dimensions.
WeakCache< std::string, Function > cache_
Function cache.
virtual int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const
Propagate sparsity forward.
casadi_checkout_t checkout_
Checkout redirected to a C function.
virtual int eval_activity(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const
Propagate signal activity forward.
std::vector< double > nz_in(const std::vector< DM > &arg) const
Convert from/to flat vector of input/output nonzeros.
casadi_int nnz_in() const
Number of input/output nonzeros.
virtual void disp_more(std::ostream &stream) const
Print more.
static const Options options_
Options.
virtual std::vector< DM > eval_dm(const std::vector< DM > &arg) const
Evaluate with DM matrices.
FunctionInternal(const std::string &name)
Constructor.
Function wrap_as_needed(const std::string &name, const Dict &opts) const
Wrap in an Function instance consisting of only one MX call.
std::vector< MX > mapsum_mx(const std::vector< MX > &arg, const std::string &parallelization)
Parallel evaluation.
virtual Function get_reverse(casadi_int nadj, const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const
Return function that calculates adjoint derivatives.
void sz_work(size_t &sz_arg, size_t &sz_res, size_t &sz_iw, size_t &sz_w) const
Get number of temporary variables needed.
std::vector< Sparsity > sparsity_out_
Function reverse(casadi_int nadj) const
Return function that calculates adjoint derivatives.
std::vector< M > replace_res(const std::vector< M > &res, casadi_int npar) const
Replace 0-by-0 outputs.
virtual const Function & oracle() const
Get oracle.
virtual bool get_diff_in(casadi_int i)
Which inputs are differentiable.
bool jit_temp_suffix_
Use a temporary name.
virtual std::vector< std::string > get_function() const
signal_t incref_
Incref/decref redirected to C functions.
void serialize_type(SerializingStream &s) const override
Serialize type information.
virtual std::string get_name_out(casadi_int i)
Names of function input and outputs.
casadi_int max_num_dir_
Maximum number of sensitivity directions.
virtual double instruction_constant(casadi_int k) const
Get the floating point output argument of an atomic operation.
virtual bool fwdViaJac(casadi_int nfwd) const
Calculate derivatives by multiplying the full Jacobian and multiplying.
virtual Sparsity get_sparsity_out(casadi_int i)
Get sparsity of a given output.
const Sparsity & sparsity_out(casadi_int ind) const
Input/output sparsity.
bool matching_res(const std::vector< M > &arg, casadi_int &npar) const
Check if output arguments that needs to be replaced.
void disp(std::ostream &stream, bool more) const override
Display object.
size_t sz_w() const
Get required length of w field.
virtual int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const
Propagate sparsity backwards.
virtual Sparsity get_jac_sparsity(casadi_int oind, casadi_int iind, bool symmetric) const
Get Jacobian sparsity.
virtual void merge(const std::vector< MX > &arg, std::vector< MX > &subs_from, std::vector< MX > &subs_to) const
List merge opportunitities.
bool jit_cleanup_
Cleanup jit source file.
virtual bool codegen_needs_mem() const
Is thread-local memory object needed?
virtual bool has_function(const std::string &fname) const
Sparsity get_jac_sparsity_gen(casadi_int oind, casadi_int iind) const
Get the sparsity pattern via sparsity seed propagation.
std::unique_ptr< std::ostream > open_trace(const double **arg, casadi_int dump_id) const
void print_out(std::ostream &stream, double **res, bool truncate) const
Print outputs.
virtual void codegen_declarations(CodeGenerator &g) const
Generate code for the declarations of the C function.
int eval_gen(const double **arg, double **res, casadi_int *iw, double *w, void *mem, bool always_inline, bool never_inline) const
Evaluate numerically.
virtual bool jac_is_symm(casadi_int oind, casadi_int iind) const
Is a Jacobian block known to be symmetric a priori?
virtual const std::vector< MX > mx_out() const
Get function input(s) and output(s)
virtual std::vector< casadi_int > instruction_output(casadi_int k) const
Get the (integer) output argument of an atomic operation.
virtual int sp_forward_block(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem, casadi_int oind, casadi_int iind) const
Propagate sparsity forward, specific block.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
std::string signature(const std::string &fname) const
Code generate the function.
void reset_dump_count()
Reset the counter used to name dump files.
virtual const std::vector< SX > sx_out() const
Get function input(s) and output(s)
bool all_scalar() const
Are all inputs and outputs scalar.
virtual Function get_jacobian(const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const
Return Jacobian of all input elements with respect to all output elements.
std::vector< double > nz_out(const std::vector< DM > &res) const
Convert from/to flat vector of input/output nonzeros.
casadi_int nnz_out() const
Number of input/output nonzeros.
void tocache(const Function &f, const std::string &suffix="") const
Save function to cache.
size_t sz_arg() const
Get required length of arg field.
void setup(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const
Set the (persistent and temporary) work vectors.
void generate_out(const std::string &fname, double **res) const
virtual bool has_codegen() const
Is codegen supported?
static bool check_mat(const Sparsity &arg, const Sparsity &inp, casadi_int &npar)
void codegen_meta(CodeGenerator &g) const
Generate meta-information allowing a user to evaluate a generated function.
Function jacobian() const
Return Jacobian of all input elements with respect to all output elements.
virtual void codegen_init_mem(CodeGenerator &g) const
Codegen decref for init_mem.
virtual bool has_free() const
Does the function have free variables.
void alloc(const Function &f, bool persistent=false, int num_threads=1)
Ensure work vectors long enough to evaluate function.
static void trace_values(std::ostream &trace, const double *values, casadi_int nnz)
virtual bool has_reverse(casadi_int nadj) const
Return function that calculates adjoint derivatives.
virtual std::string generate_dependencies(const std::string &fname, const Dict &opts) const
Export / Generate C code for the dependency function.
virtual std::vector< MX > symbolic_output(const std::vector< MX > &arg) const
Get a vector of symbolic variables corresponding to the outputs.
std::vector< bool > is_diff_in_
Are inputs and outputs differentiable?
size_t sz_iw() const
Get required length of iw field.
void change_option(const std::string &option_name, const GenericType &option_value) override
Change option after object creation for debugging.
static std::string string_from_UnifiedReturnStatus(UnifiedReturnStatus status)
virtual casadi_int n_instructions() const
Get the number of atomic operations.
Dict cache_init_
Values to prepopulate the function cache with.
void free_mem(void *mem) const override
Free memory block.
std::vector< std::string > name_out_
virtual bool get_diff_out(casadi_int i)
Which outputs are differentiable.
Function derivative_of_
If the function is the derivative of another function.
Dict generate_options(const std::string &target) const override
Reconstruct options dict.
virtual bool has_spfwd() const
Is the class able to propagate seeds through the algorithm?
static std::string reverse_name(const std::string &fcn, casadi_int nadj)
Helper function: Get name of adjoint derivative function.
std::vector< std::vector< M > > replace_aseed(const std::vector< std::vector< M >> &aseed, casadi_int npar) const
Replace 0-by-0 reverse seeds.
Dict cache() const
Get all functions in the cache.
virtual std::string get_name_in(casadi_int i)
Names of function input and outputs.
casadi_int size2_in(casadi_int ind) const
Input/output dimensions.
virtual size_t get_n_in()
Number of function inputs and outputs.
virtual Function get_forward(casadi_int nfwd, const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const
Return function that calculates forward derivatives.
void codegen_sparsities(CodeGenerator &g) const
Codegen sparsities.
virtual double get_default_in(casadi_int ind) const
Get default input value.
std::vector< std::string > name_in_
Input and output scheme.
virtual void codegen_incref(CodeGenerator &g) const
Codegen incref for dependencies.
virtual std::vector< bool > which_depends(const std::string &s_in, const std::vector< std::string > &s_out, casadi_int order, bool tr=false) const
Which variables enter with some order.
virtual Sparsity get_sparsity_in(casadi_int i)
Get sparsity of a given input.
Function object.
Definition: function.hpp:126
Function forward(casadi_int nfwd) const
Get a function computing nfwd forward directional derivatives.
Definition: function.cpp:1324
void sz_work(size_t &sz_arg, size_t &sz_res, size_t &sz_iw, size_t &sz_w) const
Get number of temporary variables needed.
Definition: function.cpp:1231
std::vector< bool > which_depends(const std::string &s_in, const std::vector< std::string > &s_out, casadi_int order=1, bool tr=false) const
Find which entries of an input the outputs depend on, linearly or not.
Definition: function.cpp:2023
void assert_size_in(casadi_int i, casadi_int nrow, casadi_int ncol) const
Raise an error unless input i is nrow-by-ncol.
Definition: function.cpp:1982
const Sparsity & sparsity_out(casadi_int ind) const
Get the sparsity pattern of an output, by index or name.
Definition: function.cpp:1183
FunctionInternal * get() const
Definition: function.cpp:505
const std::vector< std::string > & name_in() const
Get the names of all inputs, in order.
Definition: function.cpp:1113
const std::string & name() const
Get the name given at construction ("null" for a null object)
Definition: function.cpp:1504
Function wrap() const
Wrap in an MXFunction whose graph is a single call to this function.
Definition: function.cpp:2112
std::vector< Function > find_functions(casadi_int max_depth=-1) const
Get all functions embedded in this function, recursively.
Definition: function.cpp:2067
Function reverse(casadi_int nadj) const
Get a function computing nadj reverse (adjoint) directional derivatives.
Definition: function.cpp:1332
Function jacobian() const
Get a function computing all Jacobian blocks at once.
Definition: function.cpp:1068
static Function create(FunctionInternal *node)
Create from node.
Definition: function.cpp:488
static bool check_name(const std::string &name)
Check whether a string is a valid function name.
Definition: function.cpp:1513
bool is_diff_out(casadi_int ind) const
Check which inputs or outputs are marked differentiable.
Definition: function.cpp:1207
std::pair< casadi_int, casadi_int > size_out(casadi_int ind) const
Get the shape of an output: rows, columns or both.
Definition: function.cpp:999
const Sparsity & sparsity_in(casadi_int ind) const
Get the sparsity pattern of an input, by index or name.
Definition: function.cpp:1167
void assert_sparsity_out(casadi_int i, const Sparsity &sp, casadi_int n=1, bool allow_all_zero_sparse=true) const
Raise an error unless output i has the sparsity sp repeated n.
Definition: function.cpp:1997
casadi_int n_out() const
Get the number of function outputs.
Definition: function.cpp:975
casadi_int n_in() const
Get the number of function inputs.
Definition: function.cpp:971
bool is_diff_in(casadi_int ind) const
Check which inputs or outputs are marked differentiable.
Definition: function.cpp:1199
Function slice(const std::string &name, const std::vector< casadi_int > &order_in, const std::vector< casadi_int > &order_out, const Dict &opts=Dict()) const
Create a function with a subset or reordering of the inputs and outputs.
Definition: function.cpp:899
void call(const std::vector< DM > &arg, std::vector< DM > &res, bool always_inline=false, bool never_inline=false) const
Evaluate with a list or a dict of arguments; the result has the same form.
Definition: function.cpp:509
const std::vector< Sparsity > & jac_sparsity(bool compact=false) const
Get the sparsity patterns of all Jacobian blocks.
Definition: function.cpp:1092
std::map< std::string, std::vector< std::string > > AuxOut
Definition: function.hpp:1546
Function factory(const std::string &name, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const AuxOut &aux=AuxOut(), const Dict &opts=Dict()) const
Build a function computing derivatives by naming inputs and outputs.
Definition: function.cpp:2009
const std::vector< std::string > & name_out() const
Get the names of all outputs, in order.
Definition: function.cpp:1117
static Matrix< Scalar > sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
static MatType zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
bool is_null() const
Is a null pointer?
void own(Internal *node)
Generic data type, can hold different types such as bool, casadi_int, std::string etc.
std::string to_string() const
Convert to a type.
static std::string getTempWorkDir()
static casadi_int getMaxNumDir()
static bool hierarchical_sparsity
Importer.
Definition: importer.hpp:86
std::string library() const
Get library name.
Definition: importer.cpp:104
signal_t get_function(const std::string &symname)
Get a function pointer for numerical evaluation.
Definition: importer.cpp:84
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
MX - Matrix expression.
Definition: mx.hpp:145
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: mapsum.cpp:85
static Function create(const std::string &parallelization, const Function &f, casadi_int n)
Definition: map.cpp:43
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: map.cpp:114
static void print_default(std::ostream &stream, const Sparsity &sp, const double *nonzeros, bool truncate=true)
Print default style.
const Sparsity & sparsity() const
Const access the sparsity - reference to data member.
void to_file(const std::string &filename, const std::string &format="") const
Write a numerical matrix to a text file (DM only)
static Matrix< casadi_int > triplet(const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, const Matrix< casadi_int > &d)
Construct a sparse matrix from triplet form (row indices, column indices, values)
Scalar * ptr()
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
Definition: nlpsol.cpp:1435
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into a plugin instance (dispatches on the plugin name)
Base class for FunctionInternal and LinsolInternal.
void print_option(const std::string &name, std::ostream &stream) const
Print all information there is to know about a certain option.
bool error_on_fail_
Throw an exception on failure?
void construct(const Dict &opts)
Construct.
virtual int init_mem(void *mem) const
Initalize memory block.
virtual void serialize_type(SerializingStream &s) const
Serialize type information.
virtual void * alloc_mem() const
Create memory block.
virtual const Options & get_options() const
Options.
bool regularity_check_
Errors are thrown when NaN is produced.
virtual Dict generate_options(const std::string &target) const
Reconstruct options dict.
void serialize(SerializingStream &s) const
Serialize an object.
ProtoFunction(const std::string &name)
Constructor.
void print(const char *fmt,...) const
C-style formatted printing during evaluation.
virtual void free_mem(void *mem) const
Free memory block.
virtual void serialize_body(SerializingStream &s) const
Serialize an object without type information.
void print_time(const std::map< std::string, FStats > &fstats) const
Print timing statistics.
int checkout() const
Checkout a memory object.
virtual void init(const Dict &opts)
Initialize.
void format_time(char *buffer, double time) const
Format time in a fixed width 8 format.
virtual Dict get_stats(void *mem) const
Get all statistics.
void * memory(int ind) const
Memory objects.
void print_options(std::ostream &stream) const
Print list of options.
bool has_memory(int ind) const
Check for existance of memory object.
bool verbose_
Verbose printout.
virtual void finalize()
Finalize the object creation.
virtual std::string serialize_base_function() const
String used to identify the immediate FunctionInternal subclass.
virtual void check_mem_count(casadi_int n) const
Check for validatity of memory object count.
void sprint(char *buf, size_t buf_sz, const char *fmt,...) const
C-style formatted printing to string.
void release(int mem) const
Release a memory object.
bool has_option(const std::string &option_name) const
Does a particular option exist.
static const Options options_
Options.
void clear_mem()
Clear all memory (called from destructor)
~ProtoFunction() override=0
Destructor.
virtual void change_option(const std::string &option_name, const GenericType &option_value)
Change option after object creation for debugging.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
Definition: rootfinder.cpp:595
The basic scalar symbolic class of CasADi.
Definition: sx_elem.hpp:75
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize without type information.
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
virtual std::string class_name() const =0
Readable name of the internal class.
static ProtoFunction * deserialize(DeserializingStream &s)
General sparsity class.
Definition: sparsity.hpp:200
casadi_int get_nz(casadi_int rr, casadi_int cc) const
Nonzero index of entry (rr, cc), or -1 if it is a structural zero.
Definition: sparsity.cpp:248
bool is_vector() const
Check whether the pattern is a row or a column vector.
Definition: sparsity.cpp:291
Sparsity sub(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, std::vector< casadi_int > &mapping, bool ind1=false) const
Pattern of the submatrix with rows rr and columns cc.
Definition: sparsity.cpp:336
casadi_int numel() const
Total number of entries, structural zeros included, i.e. size1()*size2()
Definition: sparsity.cpp:132
casadi_int size1() const
Number of rows.
Definition: sparsity.cpp:124
Sparsity star_coloring(casadi_int ordering=1, casadi_int cutoff=std::numeric_limits< casadi_int >::max()) const
Star coloring of a symmetric pattern (greedy distance-2 coloring)
Definition: sparsity.cpp:781
std::string dim(bool with_nz=false) const
Dimensions as a string "nrow x ncol", optionally with the number of nonzeros.
Definition: sparsity.cpp:595
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern.
Definition: sparsity.cpp:1041
Sparsity T() const
Transposed pattern.
Definition: sparsity.cpp:396
bool is_scalar(bool scalar_and_dense=false) const
Check whether the pattern is 1-by-1.
Definition: sparsity.cpp:271
void enlargeColumns(casadi_int ncol, const std::vector< casadi_int > &cc, bool ind1=false)
Enlarge the pattern in place by inserting empty columns.
Definition: sparsity.cpp:553
void enlargeRows(casadi_int nrow, const std::vector< casadi_int > &rr, bool ind1=false)
Enlarge the pattern in place by inserting empty rows.
Definition: sparsity.cpp:563
casadi_int nnz() const
Number of structural nonzeros.
Definition: sparsity.cpp:150
casadi_int size2() const
Number of columns.
Definition: sparsity.cpp:128
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:166
std::pair< casadi_int, casadi_int > size() const
Shape as a pair (number of rows, number of columns)
Definition: sparsity.cpp:154
static Sparsity scalar(bool dense_scalar=true)
Create a 1-by-1 sparsity pattern.
Definition: sparsity.hpp:454
bool is_empty(bool both=false) const
Check whether the pattern has a zero dimension.
Definition: sparsity.cpp:146
double density() const
Percentage of nonzeros: 100*nnz()/numel()
Definition: sparsity.cpp:136
Sparsity uni_coloring(const Sparsity &AT=Sparsity(), casadi_int cutoff=std::numeric_limits< casadi_int >::max()) const
Unidirectional (column) coloring for compressed Jacobian evaluation.
Definition: sparsity.cpp:764
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:170
bool is_dense() const
Check whether every entry is a structural nonzero, i.e. nnz() == numel()
Definition: sparsity.cpp:275
static Sparsity triplet(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, std::vector< casadi_int > &mapping, bool invert_mapping)
Create a sparsity pattern from the (row, col) index of every nonzero.
Definition: sparsity.cpp:1157
bool is_symmetric() const
Check whether the pattern equals its transpose.
Definition: sparsity.cpp:319
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize without type information.
Definition: switch.hpp:150
The casadi namespace.
Definition: archiver.cpp:28
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
T get_from_dict(const std::map< std::string, T > &d, const std::string &key, const T &default_value)
std::string join(const std::vector< std::string > &l, const std::string &delim)
unsigned long long bvec_t
int(* casadi_checkout_t)(void)
Function pointer types for the C API.
Dict combine(const Dict &first, const Dict &second, bool recurse)
Combine two dicts. First has priority.
std::string filesep()
Definition: casadi_os.cpp:71
M replace_mat(const M &arg, const Sparsity &inp, casadi_int npar)
void bvec_clear(bvec_t *s, casadi_int begin, casadi_int end)
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
int(* eval_t)(const double **arg, double **res, casadi_int *iw, double *w, int)
Function pointer types for the C API.
std::vector< MX > MXVector
Definition: mx.hpp:5148
@ OT_BOOLVECTOR
@ OT_VECTORVECTOR
void assert_read(std::istream &stream, const std::string &s)
std::string str(const T &v)
String representation, any type.
std::vector< casadi_int > lookupvector(const std::vector< casadi_int > &v, casadi_int size)
Returns a vector for quickly looking up entries of supplied list.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void(* casadi_release_t)(int)
Function pointer types for the C API.
void normalized_setup(std::istream &stream)
void(* signal_t)(void)
Function pointer types for the C API.
bool all(const std::vector< bool > &v)
Check if all arguments are true.
Definition: casadi_misc.cpp:81
const int bvec_size
std::vector< T > diff(const std::vector< T > &values)
diff
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
bool remove(const std::string &path)
Definition: ghc.cpp:47
Matrix< double > DM
Definition: dm_fwd.hpp:33
void casadi_clear(T1 *x, casadi_int n)
CLEAR: x <- 0.
bvec_t bvec_or(const bvec_t *arg, casadi_int n)
Bit-wise or operation on bvec_t array.
std::ostream & uout()
std::string filename(const std::string &path)
Definition: ghc.cpp:55
UnifiedReturnStatus
@ SOLVER_RET_NAN
@ SOLVER_RET_LIMITED
@ SOLVER_RET_SUCCESS
std::string temporary_file(const std::string &prefix, const std::string &suffix, const std::string &directory)
void normalized_out(std::ostream &stream, double val)
void bvec_toggle(bvec_t *s, casadi_int begin, casadi_int end, casadi_int j)
Function memory with temporary work vectors.
Options metadata for a class.
Definition: options.hpp:40
static bool is_sane(const Dict &opts)
Is the dictionary sane.
Definition: options.cpp:169
void print_all(std::ostream &stream) const
Print list of options.
Definition: options.cpp:268
static Dict sanitize(const Dict &opts, bool top_level=true)
Sanitize a options dictionary.
Definition: options.cpp:173
const Options::Entry * find(const std::string &name) const
Definition: options.cpp:32
void check(const Dict &opts) const
Check if options exist.
Definition: options.cpp:240
void print_one(const std::string &name, std::ostream &stream) const
Print all information there is to know about a certain option.
Definition: options.cpp:274
Function memory with temporary work vectors.
void add_stat(const std::string &s)