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