map.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
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 "map.hpp"
27 #include "serializing_stream.hpp"
28 
29 #ifdef CASADI_WITH_THREAD
30 #ifdef CASADI_WITH_THREAD_MINGW
31 #include <mingw.thread.h>
32 #else // CASADI_WITH_THREAD_MINGW
33 #include <thread>
34 #endif // CASADI_WITH_THREAD_MINGW
35 #endif // CASADI_WITH_THREAD
36 
37 namespace casadi {
38 
39  Function Map::create(const std::string& parallelization, const Function& f, casadi_int n) {
40  // Create instance of the right class
41  std::string suffix = str(n) + "_" + f.name();
42  if (parallelization == "serial") {
43  return Function::create(new Map("map" + suffix, f, n), Dict());
44  } else if (parallelization== "openmp") {
45  return Function::create(new OmpMap("ompmap" + suffix, f, n), Dict());
46  } else if (parallelization== "thread") {
47  return Function::create(new ThreadMap("threadmap" + suffix, f, n), Dict());
48  } else {
49  casadi_error("Unknown parallelization: " + parallelization);
50  }
51  }
52 
53  Map::Map(const std::string& name, const Function& f, casadi_int n)
54  : FunctionInternal(name), f_(f), n_(n) {
55  }
56 
57  bool Map::is_a(const std::string& type, bool recursive) const {
58  return type=="Map"
59  || (recursive && FunctionInternal::is_a(type, recursive));
60  }
61 
62  bool OmpMap::is_a(const std::string& type, bool recursive) const {
63  return type=="OmpMap"
64  || (recursive && Map::is_a(type, recursive));
65  }
66 
67  bool ThreadMap::is_a(const std::string& type, bool recursive) const {
68  return type=="ThreadMap"
69  || (recursive && Map::is_a(type, recursive));
70  }
71 
72  std::vector<std::string> Map::get_function() const {
73  return {"f"};
74  }
75 
76  const Function& Map::get_function(const std::string &name) const {
77  casadi_assert(has_function(name),
78  "No function \"" + name + "\" in " + name_ + ". " +
79  "Available functions: " + join(get_function()) + ".");
80  return f_;
81  }
82 
83  void Map::find(std::map<FunctionInternal*, std::pair<Function, size_t>> & all_fun,
84  casadi_int max_depth) const {
85  // Call to base class
86  FunctionInternal::find(all_fun, max_depth);
87  add_embedded(all_fun, f_, max_depth);
88  }
89 
90  bool Map::has_function(const std::string& fname) const {
91  return fname=="f";
92  }
93 
96  s.pack("Map::f", f_);
97  s.pack("Map::n", n_);
98  }
99 
102  s.pack("Map::class_name", class_name());
103  }
104 
106  s.unpack("Map::f", f_);
107  s.unpack("Map::n", n_);
108  }
109 
111  std::string class_name;
112  s.unpack("Map::class_name", class_name);
113  if (class_name=="Map") {
114  return new Map(s);
115  } else if (class_name=="OmpMap") {
116  return new OmpMap(s);
117  } else if (class_name=="ThreadMap") {
118  return new ThreadMap(s);
119  } else {
120  casadi_error("class name '" + class_name + "' unknown.");
121  }
122  }
123 
125  clear_mem();
126  }
127 
128  void Map::init(const Dict& opts) {
131  // Call the initialization method of the base class
133 
134  // Allocate sufficient memory for serial evaluation
135  alloc_arg(f_.sz_arg());
136  alloc_res(f_.sz_res());
137  alloc_w(f_.sz_w());
138  alloc_iw(f_.sz_iw());
139  }
140 
141  template<typename T>
142  int Map::eval_gen(const T** arg, T** res, casadi_int* iw, T* w, int mem) const {
143  const T** arg1 = arg+n_in_;
144  std::copy_n(arg, n_in_, arg1);
145  T** res1 = res+n_out_;
146  std::copy_n(res, n_out_, res1);
147  for (casadi_int i=0; i<n_; ++i) {
148  if (f_(arg1, res1, iw, w, mem)) return 1;
149  for (casadi_int j=0; j<n_in_; ++j) {
150  if (arg1[j]) arg1[j] += f_.nnz_in(j);
151  }
152  for (casadi_int j=0; j<n_out_; ++j) {
153  if (res1[j]) res1[j] += f_.nnz_out(j);
154  }
155  }
156  return 0;
157  }
158 
159  int Map::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w, void* mem,
160  bool always_inline, bool never_inline) const {
161  return eval_gen(arg, res, iw, w);
162  }
163 
164  int Map::sp_forward(const bvec_t** arg, bvec_t** res,
165  casadi_int* iw, bvec_t* w, void* mem) const {
166  return eval_gen(arg, res, iw, w);
167  }
168 
169  int Map::sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const {
170  bvec_t** arg1 = arg+n_in_;
171  std::copy_n(arg, n_in_, arg1);
172  bvec_t** res1 = res+n_out_;
173  std::copy_n(res, n_out_, res1);
174  for (casadi_int i=0; i<n_; ++i) {
175  if (f_.rev(arg1, res1, iw, w)) return 1;
176  for (casadi_int j=0; j<n_in_; ++j) {
177  if (arg1[j]) arg1[j] += f_.nnz_in(j);
178  }
179  for (casadi_int j=0; j<n_out_; ++j) {
180  if (res1[j]) res1[j] += f_.nnz_out(j);
181  }
182  }
183  return 0;
184  }
185 
187  g.add_dependency(f_);
188  }
189 
191  g.local("i", "casadi_int");
192  g.local("arg1", "const casadi_real*", "*");
193  g.local("res1", "casadi_real*", "*");
194 
195  // Input buffer
196  g << "arg1 = arg+" << n_in_ << ";\n"
197  << "for (i=0; i<" << n_in_ << "; ++i) arg1[i]=arg[i];\n";
198  // Output buffer
199  g << "res1 = res+" << n_out_ << ";\n"
200  << "for (i=0; i<" << n_out_ << "; ++i) res1[i]=res[i];\n"
201  << "for (i=0; i<" << n_ << "; ++i) {\n";
202 
203  std::string flag = g(f_, "arg1", "res1", "iw", "w");
204  // Evaluate
205  g << "if (" << flag << ") return 1;\n";
206  // Update input buffers
207  for (casadi_int j=0; j<n_in_; ++j) {
208  if (f_.nnz_in(j))
209  g << "if (arg1[" << j << "]) arg1[" << j << "]+=" << f_.nnz_in(j) << ";\n";
210  }
211  // Update output buffers
212  for (casadi_int j=0; j<n_out_; ++j) {
213  if (f_.nnz_out(j))
214  g << "if (res1[" << j << "]) res1[" << j << "]+=" << f_.nnz_out(j) << ";\n";
215  }
216  g << "}\n";
217  }
218 
220  ::get_forward(casadi_int nfwd, const std::string& name,
221  const std::vector<std::string>& inames,
222  const std::vector<std::string>& onames,
223  const Dict& opts) const {
224  // Generate map of derivative
225  Function df = f_.forward(nfwd);
226  Function dm = df.map(n_, parallelization());
227 
228  // Input expressions
229  std::vector<MX> arg = dm.mx_in();
230 
231  // Need to reorder sensitivity inputs
232  std::vector<MX> res = arg;
233  std::vector<MX>::iterator it=res.begin()+n_in_+n_out_;
234  std::vector<casadi_int> ind;
235  for (casadi_int i=0; i<n_in_; ++i, ++it) {
236  casadi_int sz = f_.size2_in(i);
237  ind.clear();
238  for (casadi_int k=0; k<n_; ++k) {
239  for (casadi_int d=0; d<nfwd; ++d) {
240  for (casadi_int j=0; j<sz; ++j) {
241  ind.push_back((d*n_ + k)*sz + j);
242  }
243  }
244  }
245  *it = (*it)(Slice(), ind); // NOLINT
246  }
247 
248  // Get output expressions
249  res = dm(res);
250 
251  // Reorder sensitivity outputs
252  it = res.begin();
253  for (casadi_int i=0; i<n_out_; ++i, ++it) {
254  casadi_int sz = f_.size2_out(i);
255  ind.clear();
256  for (casadi_int d=0; d<nfwd; ++d) {
257  for (casadi_int k=0; k<n_; ++k) {
258  for (casadi_int j=0; j<sz; ++j) {
259  ind.push_back((k*nfwd + d)*sz + j);
260  }
261  }
262  }
263  *it = (*it)(Slice(), ind); // NOLINT
264  }
265 
266  Dict options = opts;
267  options["allow_duplicate_io_names"] = true;
268 
269  // Construct return function
270  return Function(name, arg, res, inames, onames, options);
271  }
272 
274  ::get_reverse(casadi_int nadj, const std::string& name,
275  const std::vector<std::string>& inames,
276  const std::vector<std::string>& onames,
277  const Dict& opts) const {
278  // Generate map of derivative
279  Function df = f_.reverse(nadj);
280  Function dm = df.map(n_, parallelization());
281 
282  // Input expressions
283  std::vector<MX> arg = dm.mx_in();
284 
285  // Need to reorder sensitivity inputs
286  std::vector<MX> res = arg;
287  std::vector<MX>::iterator it=res.begin()+n_in_+n_out_;
288  std::vector<casadi_int> ind;
289  for (casadi_int i=0; i<n_out_; ++i, ++it) {
290  casadi_int sz = f_.size2_out(i);
291  ind.clear();
292  for (casadi_int k=0; k<n_; ++k) {
293  for (casadi_int d=0; d<nadj; ++d) {
294  for (casadi_int j=0; j<sz; ++j) {
295  ind.push_back((d*n_ + k)*sz + j);
296  }
297  }
298  }
299  *it = (*it)(Slice(), ind); // NOLINT
300  }
301 
302  // Get output expressions
303  res = dm(res);
304 
305  // Reorder sensitivity outputs
306  it = res.begin();
307  for (casadi_int i=0; i<n_in_; ++i, ++it) {
308  casadi_int sz = f_.size2_in(i);
309  ind.clear();
310  for (casadi_int d=0; d<nadj; ++d) {
311  for (casadi_int k=0; k<n_; ++k) {
312  for (casadi_int j=0; j<sz; ++j) {
313  ind.push_back((k*nadj + d)*sz + j);
314  }
315  }
316  }
317  *it = (*it)(Slice(), ind); // NOLINT
318  }
319 
320  Dict options = opts;
321  options["allow_duplicate_io_names"] = true;
322 
323  // Construct return function
324  return Function(name, arg, res, inames, onames, options);
325  }
326 
327  int Map::eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
328  // This checkout/release dance is an optimization.
329  // Could also use the thread-safe variant f_(arg1, res1, iw, w)
330  // in Map::eval_gen
331  setup(mem, arg, res, iw, w);
333  return eval_gen(arg, res, iw, w, m);
334  }
335 
337  clear_mem();
338  }
339 
340  int OmpMap::eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
341 #ifndef WITH_OPENMP
342  return Map::eval(arg, res, iw, w, mem);
343 #else // WITH_OPENMP
344  setup(mem, arg, res, iw, w);
345  size_t sz_arg, sz_res, sz_iw, sz_w;
347 
348  // Error flag
349  casadi_int flag = 0;
350 
351  // Checkout memory objects
352  std::vector< scoped_checkout<Function> > ind; ind.reserve(n_);
353  for (casadi_int i=0; i<n_; ++i) ind.emplace_back(f_);
354 
355  // Evaluate in parallel
356 #pragma omp parallel for reduction(||:flag)
357  for (casadi_int i=0; i<n_; ++i) {
358  // Input buffers
359  const double** arg1 = arg + n_in_ + i*sz_arg;
360  for (casadi_int j=0; j<n_in_; ++j) {
361  arg1[j] = arg[j] ? arg[j] + i*f_.nnz_in(j) : 0;
362  }
363 
364  // Output buffers
365  double** res1 = res + n_out_ + i*sz_res;
366  for (casadi_int j=0; j<n_out_; ++j) {
367  res1[j] = res[j] ? res[j] + i*f_.nnz_out(j) : 0;
368  }
369 
370  // Evaluation
371  try {
372  flag = f_(arg1, res1, iw + i*sz_iw, w + i*sz_w, ind[i]) || flag;
373  } catch (std::exception& e) {
374  flag = 1;
375  casadi_warning("Exception raised: " + std::string(e.what()));
376  } catch (...) {
377  flag = 1;
378  casadi_warning("Uncaught exception.");
379  }
380 
381  }
382 
383  // Return error flag
384  return flag;
385 #endif // WITH_OPENMP
386  }
387 
389  size_t sz_arg, sz_res, sz_iw, sz_w;
391 
392  std::string priv_vars = "";
393 
394  if (f_->codegen_needs_mem()) {
395  g.local("flag", "int");
396  g.local("mid", "int");
397  priv_vars = ",mid,flag";
398  }
399 
400  g.local("i", "casadi_int");
401  g.local("arg1", "const double*", "*");
402  g.local("res1", "double*", "*");
403  g.local("cflag", "casadi_int");
404  g.init_local("cflag", "0");
405 
406  g << "#pragma omp parallel for private(i,arg1,res1" << priv_vars << ") reduction(||:cflag)\n"
407  << "for (i=0; i<" << n_ << "; ++i) {\n"
408  << "arg1 = arg + " << n_in_ << "+i*" << sz_arg << ";\n";
409  for (casadi_int j=0; j<n_in_; ++j) {
410  g << "arg1[" << j << "] = arg[" << j << "] ? "
411  << g.arg(j) << "+i*" << f_.nnz_in(j) << ": 0;\n";
412  }
413  g << "res1 = res + " << n_out_ << "+i*" << sz_res << ";\n";
414  for (casadi_int j=0; j<n_out_; ++j) {
415  g << "res1[" << j << "] = res[" << j << "] ?"
416  << g.res(j) << "+i*" << f_.nnz_out(j) << ": 0;\n";
417  }
418 
419  std::string flag = g(f_, "arg1", "res1", "iw+i*" + str(sz_iw), "w+i*" + str(sz_w), "");
420 
421  g << "cflag = "
422  << flag << " || cflag;\n"
423  << "}\n";
424  g << "if (cflag) return 1;\n";
425  }
426 
427  void OmpMap::init(const Dict& opts) {
428 #ifndef WITH_OPENMP
429  casadi_warning("CasADi was not compiled with WITH_OPENMP=ON. "
430  "Falling back to serial evaluation.");
431 #endif // WITH_OPENMP
432  // Call the initialization method of the base class
433  Map::init(opts);
434 
435  // Allocate memory for holding memory object references
436  alloc_iw(n_, true);
437 
438  // Allocate sufficient memory for parallel evaluation
439  alloc_arg(f_.sz_arg() * n_);
440  alloc_res(f_.sz_res() * n_);
441  alloc_w(f_.sz_w() * n_);
442  alloc_iw(f_.sz_iw() * n_);
443  }
444 
445 
447  clear_mem();
448  }
449 
450  void ThreadsWork(const Function& f, casadi_int i,
451  const double** arg, double** res,
452  casadi_int* iw, double* w,
453  casadi_int ind, int& ret) {
454 
455  // Function dimensions
456  casadi_int n_in = f.n_in();
457  casadi_int n_out = f.n_out();
458 
459  // Function work sizes
460  size_t sz_arg, sz_res, sz_iw, sz_w;
461  f.sz_work(sz_arg, sz_res, sz_iw, sz_w);
462 
463  // Input buffers
464  const double** arg1 = arg + n_in + i*sz_arg;
465  for (casadi_int j=0; j<n_in; ++j) {
466  arg1[j] = arg[j] ? arg[j] + i*f.nnz_in(j) : nullptr;
467  }
468 
469  // Output buffers
470  double** res1 = res + n_out + i*sz_res;
471  for (casadi_int j=0; j<n_out; ++j) {
472  res1[j] = res[j] ? res[j] + i*f.nnz_out(j) : nullptr;
473  }
474 
475  try {
476  ret = f(arg1, res1, iw + i*sz_iw, w + i*sz_w, ind);
477  } catch (std::exception& e) {
478  ret = 1;
479  casadi_warning("Exception raised: " + std::string(e.what()));
480  } catch (...) {
481  ret = 1;
482  casadi_warning("Uncaught exception.");
483  }
484  }
485 
486  int ThreadMap::eval(const double** arg, double** res, casadi_int* iw, double* w,
487  void* mem) const {
488 #ifndef CASADI_WITH_THREAD
489  return Map::eval(arg, res, iw, w, mem);
490 #else // CASADI_WITH_THREAD
491  setup(mem, arg, res, iw, w);
492  // Checkout memory objects
493  std::vector< scoped_checkout<Function> > ind; ind.reserve(n_);
494  for (casadi_int i=0; i<n_; ++i) ind.emplace_back(f_);
495 
496  // Allocate space for return values
497  std::vector<int> ret_values(n_);
498 
499  // Spawn threads
500  std::vector<std::thread> threads;
501  for (casadi_int i=0; i<n_; ++i) {
502  // Why the lambda function?
503  // Because it was the first iteration to pass tests on MingGW
504  // using mingw-std-threads.
505  threads.emplace_back(
506  [i](const Function& f, const double** arg, double** res,
507  casadi_int* iw, double* w, casadi_int ind, int& ret) {
508  ThreadsWork(f, i, arg, res, iw, w, ind, ret);
509  },
510  std::ref(f_), arg, res, iw, w, casadi_int(ind[i]), std::ref(ret_values[i]));
511  }
512 
513  // Join threads
514  for (auto && th : threads) th.join();
515 
516  // Anticipate success
517  int ret = 0;
518 
519  // Compute aggregate return value
520  for (int e : ret_values) ret = ret || e;
521 
522  return ret;
523 #endif // CASADI_WITH_THREAD
524  }
525 
528  // Call base class
530 
531  size_t sz_arg, sz_res, sz_iw, sz_w;
533 
534  // Create wrapper name
535  std::string worker_name = g.shorthand(g.wrapper(f_, "thread_worker"));
536 
537  // Generate struct definition for thread arguments
538  g << "struct " << worker_name << "_args_t {\n";
539  g << " casadi_int i;\n";
540  g << " casadi_int n_in;\n";
541  g << " casadi_int n_out;\n";
542  g << " const casadi_real** arg;\n";
543  g << " casadi_real** res;\n";
544  g << " casadi_int* iw;\n";
545  g << " casadi_real* w;\n";
546  g << " casadi_int sz_arg;\n";
547  g << " casadi_int sz_res;\n";
548  g << " casadi_int sz_iw;\n";
549  g << " casadi_int sz_w;\n";
550 
551  for (casadi_int j=0; j<n_in_; ++j) {
552  g << " casadi_int nnz_in_" << j << ";\n";
553  }
554  for (casadi_int j=0; j<n_out_; ++j) {
555  g << " casadi_int nnz_out_" << j << ";\n";
556  }
557  g << " int ret;\n";
558  g << "};\n\n";
559 
560  // Generate wrapper function using portable thread macros
561  g << "CASADI_THREAD_WORKER_RETURN " << worker_name << "(CASADI_THREAD_WORKER_ARG arg) {\n";
562  g.flush(g.body);
563  g.scope_enter();
564  g << " struct " << worker_name << "_args_t* data = (struct "
565  << worker_name << "_args_t*)arg;\n";
566  g << " casadi_int i = data->i;\n";
567  g << " const casadi_real** arg1;\n";
568  g << " casadi_real** res1;\n\n";
569 
570  // Setup input buffers
571  g << " arg1 = data->arg + data->n_in + i * data->sz_arg;\n";
572  for (casadi_int j=0; j<n_in_; ++j) {
573  g << " arg1[" << j << "] = data->arg[" << j << "] ? "
574  << "data->arg[" << j << "] + i * data->nnz_in_" << j << " : 0;\n";
575  }
576 
577  // Setup output buffers
578  g << " res1 = data->res + data->n_out + i * data->sz_res;\n";
579  for (casadi_int j=0; j<n_out_; ++j) {
580  g << " res1[" << j << "] = data->res[" << j << "] ? "
581  << "data->res[" << j << "] + i * data->nnz_out_" << j << " : 0;\n";
582  }
583 
584  // Call the function
585  std::string flag = g(f_, "arg1", "res1",
586  "data->iw + i * data->sz_iw",
587  "data->w + i * data->sz_w", "");
588  g << " data->ret = " << flag << ";\n";
589  g << " return CASADI_THREAD_RETURN_VALUE;\n";
590  g.scope_exit();
591  g << "}\n\n";
592  }
593 
595  size_t sz_arg, sz_res, sz_iw, sz_w;
597 
598  // Create wrapper function for thread worker
599  std::string worker_name = g.shorthand(g.wrapper(f_, "thread_worker"));
600 
601  g.local("i", "casadi_int");
602  g.local("threads[" + str(n_) + "]", "CASADI_THREAD_HANDLE");
603  g.local("thread_args[" + str(n_) + "]", "struct " + worker_name + "_args_t");
604  g.local("cflag", "casadi_int");
605  g.init_local("cflag", "0");
606 
607  // Create threads
608  g << "for (i=0; i<" << n_ << "; ++i) {\n";
609  g << " thread_args[i].i = i;\n";
610  g << " thread_args[i].n_in = " << n_in_ << ";\n";
611  g << " thread_args[i].n_out = " << n_out_ << ";\n";
612  g << " thread_args[i].arg = arg;\n";
613  g << " thread_args[i].res = res;\n";
614  g << " thread_args[i].iw = iw;\n";
615  g << " thread_args[i].w = w;\n";
616  g << " thread_args[i].sz_arg = " << sz_arg << ";\n";
617  g << " thread_args[i].sz_res = " << sz_res << ";\n";
618  g << " thread_args[i].sz_iw = " << sz_iw << ";\n";
619  g << " thread_args[i].sz_w = " << sz_w << ";\n";
620 
621  // Add function-specific nnz info
622  for (casadi_int j=0; j<n_in_; ++j) {
623  g << " thread_args[i].nnz_in_" << j << " = " << f_.nnz_in(j) << ";\n";
624  }
625  for (casadi_int j=0; j<n_out_; ++j) {
626  g << " thread_args[i].nnz_out_" << j << " = " << f_.nnz_out(j) << ";\n";
627  }
628 
629  g << " CASADI_THREAD_CREATE(threads[i], " << worker_name << ", &thread_args[i]);\n";
630  g << "}\n\n";
631 
632  // Join threads
633  g << "for (i=0; i<" << n_ << "; ++i) {\n";
634  g << " CASADI_THREAD_JOIN(threads[i]);\n";
635  g << " cflag = cflag || thread_args[i].ret;\n";
636  g << "}\n\n";
637 
638  g << "if (cflag) return 1;\n";
639  }
640 
641  void ThreadMap::init(const Dict& opts) {
642 #ifndef CASADI_WITH_THREAD
643  casadi_warning("CasADi was not compiled with WITH_THREAD=ON. "
644  "Falling back to serial evaluation.");
645 #endif // CASADI_WITH_THREAD
646  // Call the initialization method of the base class
647  Map::init(opts);
648 
649  // Allocate memory for holding memory object references
650  alloc_iw(n_, true);
651 
652  // Allocate sufficient memory for parallel evaluation
653  alloc_arg(f_.sz_arg() * n_);
654  alloc_res(f_.sz_res() * n_);
655  alloc_w(f_.sz_w() * n_);
656  alloc_iw(f_.sz_iw() * n_);
657  }
658 
659 } // namespace casadi
Helper class for C code generation.
std::string add_dependency(const Function &f)
Add a function dependency.
std::string arg(casadi_int i) const
Refer to argument.
std::string wrapper(const Function &base, const std::string &name)
void scope_enter()
Enter a local scope.
void flush(std::ostream &s)
Flush the buffer to a stream of choice.
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
std::string res(casadi_int i) const
Refer to resuly.
void scope_exit()
Exit a local scope.
void init_local(const std::string &name, const std::string &def)
Specify the default value for a local variable.
std::string shorthand(const std::string &name) const
Get a shorthand.
std::stringstream body
void add_auxiliary(Auxiliary f, const std::vector< std::string > &inst={"casadi_real"})
Add a built-in auxiliary function.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
Internal class for Function.
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
void init(const Dict &opts) override
Initialize.
std::vector< bool > is_diff_out_
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void alloc_res(size_t sz_res, bool persistent=false)
Ensure required length of res field.
void alloc_arg(size_t sz_arg, bool persistent=false)
Ensure required length of arg field.
virtual bool is_a(const std::string &type, bool recursive) const
Check if the function is of a particular type.
void add_embedded(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, const Function &dep, casadi_int max_depth) const
virtual void find(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, casadi_int max_depth) const
size_t n_in_
Number of inputs and outputs.
size_t sz_res() const
Get required length of res field.
void serialize_type(SerializingStream &s) const override
Serialize type information.
size_t sz_w() const
Get required length of w field.
virtual bool codegen_needs_mem() const
Is thread-local memory object needed?
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
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.
std::vector< bool > is_diff_in_
Are inputs and outputs differentiable?
size_t sz_iw() const
Get required length of iw field.
Function object.
Definition: function.hpp:60
Function forward(casadi_int nfwd) const
Get a function that calculates nfwd forward derivatives.
Definition: function.cpp:1324
casadi_int nnz_out() const
Get number of output nonzeros.
Definition: function.cpp:1007
void sz_work(size_t &sz_arg, size_t &sz_res, size_t &sz_iw, size_t &sz_w) const
Get number of temporary variables needed.
Definition: function.cpp:1231
size_t sz_res() const
Get required length of res field.
Definition: function.cpp:1237
const MX mx_in(casadi_int ind) const
Get symbolic primitives equivalent to the input expressions.
Definition: function.cpp:1781
const std::string & name() const
Name of the function.
Definition: function.cpp:1504
Function reverse(casadi_int nadj) const
Get a function that calculates nadj adjoint derivatives.
Definition: function.cpp:1332
static Function create(FunctionInternal *node)
Create from node.
Definition: function.cpp:488
bool is_diff_out(casadi_int ind) const
Get differentiability of inputs/output.
Definition: function.cpp:1207
int rev(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, int mem=0) const
Propagate sparsity backward.
Definition: function.cpp:1252
size_t sz_iw() const
Get required length of iw field.
Definition: function.cpp:1239
casadi_int n_out() const
Get the number of function outputs.
Definition: function.cpp:975
casadi_int n_in() const
Get the number of function inputs.
Definition: function.cpp:971
bool is_diff_in(casadi_int ind) const
Get differentiability of inputs/output.
Definition: function.cpp:1199
Function map(casadi_int n, const std::string &parallelization="serial") const
Create a mapped version of this function.
Definition: function.cpp:861
size_t sz_w() const
Get required length of w field.
Definition: function.cpp:1241
size_t sz_arg() const
Get required length of arg field.
Definition: function.cpp:1235
casadi_int nnz_in() const
Get number of input nonzeros.
Definition: function.cpp:1003
int eval_gen(const T **arg, T **res, casadi_int *iw, T *w, int mem=0) const
Evaluate or propagate sparsities.
Definition: map.cpp:142
void serialize_type(SerializingStream &s) const override
Serialize type information.
Definition: map.cpp:100
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 override
Generate a function that calculates nadj adjoint derivatives.
Definition: map.cpp:274
int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity forward.
Definition: map.cpp:164
void init(const Dict &opts) override
Initialize.
Definition: map.cpp:128
~Map() override
Destructor.
Definition: map.cpp:124
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
Definition: map.cpp:57
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate the function numerically.
Definition: map.cpp:327
Function f_
Definition: map.hpp:216
casadi_int n_
Definition: map.hpp:219
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
Definition: map.cpp:190
bool has_function(const std::string &fname) const override
Definition: map.cpp:90
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
Definition: map.cpp:186
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity backwards.
Definition: map.cpp:169
std::string class_name() const override
Get type name.
Definition: map.hpp:53
void find(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, casadi_int max_depth) const override
Definition: map.cpp:83
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w, void *mem, bool always_inline, bool never_inline) const override
evaluate symbolically while also propagating directional derivatives
Definition: map.cpp:159
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: map.cpp:94
virtual std::vector< std::string > get_function() const override
Definition: map.cpp:72
static Function create(const std::string &parallelization, const Function &f, casadi_int n)
Definition: map.cpp:39
Map(DeserializingStream &s)
Deserializing constructor.
Definition: map.cpp:105
virtual std::string parallelization() const
Type of parallellization.
Definition: map.hpp:116
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: map.cpp:110
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 override
Generate a function that calculates nfwd forward derivatives.
Definition: map.cpp:220
void init(const Dict &opts) override
Initialize.
Definition: map.cpp:427
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
Definition: map.cpp:62
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate the function numerically.
Definition: map.cpp:340
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
Definition: map.cpp:388
~OmpMap() override
Destructor.
Definition: map.cpp:336
Base class for FunctionInternal and LinsolInternal.
void clear_mem()
Clear all memory (called from destructor)
The basic scalar symbolic class of CasADi.
Definition: sx_elem.hpp:75
Helper class for Serialization.
void pack(const Sparsity &e)
Serializes an object to the output stream.
Class representing a Slice.
Definition: slice.hpp:48
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
Definition: map.cpp:594
~ThreadMap() override
Destructor.
Definition: map.cpp:446
void init(const Dict &opts) override
Initialize.
Definition: map.cpp:641
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
Definition: map.cpp:526
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate the function numerically.
Definition: map.cpp:486
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
Definition: map.cpp:67
The casadi namespace.
Definition: archiver.cpp:28
void ThreadsWork(const Function &f, casadi_int i, const double **arg, double **res, casadi_int *iw, double *w, casadi_int ind, int &ret)
Definition: map.cpp:450
std::string join(const std::vector< std::string > &l, const std::string &delim)
unsigned long long bvec_t
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.