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