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