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