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