27 #include "serializing_stream.hpp"
29 #ifdef CASADI_WITH_THREAD
30 #ifdef CASADI_WITH_THREAD_MINGW
31 #include <mingw.thread.h>
41 std::string suffix =
str(n) +
"_" + f.
name();
57 bool Map::is_a(
const std::string& type,
bool recursive)
const {
64 || (recursive &&
Map::is_a(type, recursive));
68 return type==
"ThreadMap"
69 || (recursive &&
Map::is_a(type, recursive));
78 "No function \"" + name +
"\" in " +
name_ +
". " +
84 casadi_int max_depth)
const {
120 casadi_error(
"class name '" +
class_name +
"' unknown.");
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);
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);
152 for (casadi_int j=0; j<
n_out_; ++j) {
160 bool always_inline,
bool never_inline)
const {
165 casadi_int* iw,
bvec_t* w,
void* mem)
const {
171 std::copy_n(arg,
n_in_, arg1);
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);
179 for (casadi_int j=0; j<
n_out_; ++j) {
191 g.
local(
"i",
"casadi_int");
192 g.
local(
"arg1",
"const casadi_real*",
"*");
193 g.
local(
"res1",
"casadi_real*",
"*");
196 g <<
"arg1 = arg+" <<
n_in_ <<
";\n"
197 <<
"for (i=0; i<" <<
n_in_ <<
"; ++i) arg1[i]=arg[i];\n";
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";
203 std::string flag = g(
f_,
"arg1",
"res1",
"iw",
"w");
205 g <<
"if (" << flag <<
") return 1;\n";
207 for (casadi_int j=0; j<
n_in_; ++j) {
209 g <<
"if (arg1[" << j <<
"]) arg1[" << j <<
"]+=" <<
f_.
nnz_in(j) <<
";\n";
212 for (casadi_int j=0; j<
n_out_; ++j) {
214 g <<
"if (res1[" << j <<
"]) res1[" << j <<
"]+=" <<
f_.
nnz_out(j) <<
";\n";
221 const std::vector<std::string>& inames,
222 const std::vector<std::string>& onames,
223 const Dict& opts)
const {
229 std::vector<MX> arg = dm.
mx_in();
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);
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);
245 *it = (*it)(
Slice(), ind);
253 for (casadi_int i=0; i<n_out_; ++i, ++it) {
254 casadi_int sz = f_.size2_out(i);
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);
263 *it = (*it)(
Slice(), ind);
267 options[
"allow_duplicate_io_names"] =
true;
270 return Function(name, arg, res, inames, onames, options);
275 const std::vector<std::string>& inames,
276 const std::vector<std::string>& onames,
277 const Dict& opts)
const {
283 std::vector<MX> arg = dm.
mx_in();
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);
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);
299 *it = (*it)(
Slice(), ind);
307 for (casadi_int i=0; i<n_in_; ++i, ++it) {
308 casadi_int sz = f_.size2_in(i);
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);
317 *it = (*it)(
Slice(), ind);
321 options[
"allow_duplicate_io_names"] =
true;
324 return Function(name, arg, res, inames, onames, options);
327 int Map::eval(
const double** arg,
double** res, casadi_int* iw,
double* w,
void* mem)
const {
331 setup(mem, arg, res, iw, w);
333 return eval_gen(arg, res, iw, w, m);
340 int OmpMap::eval(
const double** arg,
double** res, casadi_int* iw,
double* w,
void* mem)
const {
344 setup(mem, arg, res, iw, w);
352 std::vector< scoped_checkout<Function> > ind; ind.reserve(
n_);
353 for (casadi_int i=0; i<
n_; ++i) ind.emplace_back(
f_);
356 #pragma omp parallel for reduction(||:flag)
357 for (casadi_int i=0; i<
n_; ++i) {
360 for (casadi_int j=0; j<
n_in_; ++j) {
361 arg1[j] = arg[j] ? arg[j] + i*
f_.
nnz_in(j) : 0;
366 for (casadi_int j=0; j<
n_out_; ++j) {
367 res1[j] = res[j] ? res[j] + i*
f_.
nnz_out(j) : 0;
372 flag =
f_(arg1, res1, iw + i*
sz_iw, w + i*
sz_w, ind[i]) || flag;
373 }
catch (std::exception& e) {
375 casadi_warning(
"Exception raised: " + std::string(e.what()));
378 casadi_warning(
"Uncaught exception.");
392 std::string priv_vars =
"";
395 g.
local(
"flag",
"int");
396 g.
local(
"mid",
"int");
397 priv_vars =
",mid,flag";
400 g.
local(
"i",
"casadi_int");
401 g.
local(
"arg1",
"const double*",
"*");
402 g.
local(
"res1",
"double*",
"*");
403 g.
local(
"cflag",
"casadi_int");
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 <<
"] ? "
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 <<
"] ?"
419 std::string flag = g(
f_,
"arg1",
"res1",
"iw+i*" +
str(
sz_iw),
"w+i*" +
str(
sz_w),
"");
422 << flag <<
" || cflag;\n"
424 g <<
"if (cflag) return 1;\n";
429 casadi_warning(
"CasADi was not compiled with WITH_OPENMP=ON. "
430 "Falling back to serial evaluation.");
451 const double** arg,
double** res,
452 casadi_int* iw,
double* w,
453 casadi_int ind,
int& ret) {
456 casadi_int n_in = f.
n_in();
457 casadi_int n_out = f.
n_out();
460 size_t sz_arg, sz_res, sz_iw, sz_w;
461 f.
sz_work(sz_arg, sz_res, sz_iw, sz_w);
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;
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;
476 ret = f(arg1, res1, iw + i*sz_iw, w + i*sz_w, ind);
477 }
catch (std::exception& e) {
479 casadi_warning(
"Exception raised: " + std::string(e.what()));
482 casadi_warning(
"Uncaught exception.");
488 #ifndef CASADI_WITH_THREAD
491 setup(mem, arg, res, iw, w);
493 std::vector< scoped_checkout<Function> > ind; ind.reserve(
n_);
494 for (casadi_int i=0; i<
n_; ++i) ind.emplace_back(
f_);
497 std::vector<int> ret_values(
n_);
500 std::vector<std::thread> threads;
501 for (casadi_int i=0; i<
n_; ++i) {
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) {
510 std::ref(
f_), arg, res, iw, w, casadi_int(ind[i]), std::ref(ret_values[i]));
514 for (
auto && th : threads) th.join();
520 for (
int e : ret_values) ret = ret || e;
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";
551 for (casadi_int j=0; j<
n_in_; ++j) {
552 g <<
" casadi_int nnz_in_" << j <<
";\n";
554 for (casadi_int j=0; j<
n_out_; ++j) {
555 g <<
" casadi_int nnz_out_" << j <<
";\n";
561 g <<
"CASADI_THREAD_WORKER_RETURN " << worker_name <<
"(CASADI_THREAD_WORKER_ARG arg) {\n";
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";
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";
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";
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";
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");
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";
622 for (casadi_int j=0; j<
n_in_; ++j) {
623 g <<
" thread_args[i].nnz_in_" << j <<
" = " <<
f_.
nnz_in(j) <<
";\n";
625 for (casadi_int j=0; j<
n_out_; ++j) {
626 g <<
" thread_args[i].nnz_out_" << j <<
" = " <<
f_.
nnz_out(j) <<
";\n";
629 g <<
" CASADI_THREAD_CREATE(threads[i], " << worker_name <<
", &thread_args[i]);\n";
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";
638 g <<
"if (cflag) return 1;\n";
642 #ifndef CASADI_WITH_THREAD
643 casadi_warning(
"CasADi was not compiled with WITH_THREAD=ON. "
644 "Falling back to serial evaluation.");
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.
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 forward(casadi_int nfwd) const
Get a function that calculates nfwd forward derivatives.
casadi_int nnz_out() const
Get number of output nonzeros.
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.
size_t sz_res() const
Get required length of res field.
const MX mx_in(casadi_int ind) const
Get symbolic primitives equivalent to the input expressions.
const std::string & name() const
Name of the function.
Function reverse(casadi_int nadj) const
Get a function that calculates nadj adjoint derivatives.
static Function create(FunctionInternal *node)
Create from node.
bool is_diff_out(casadi_int ind) const
Get differentiability of inputs/output.
int rev(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, int mem=0) const
Propagate sparsity backward.
size_t sz_iw() const
Get required length of iw field.
casadi_int n_out() const
Get the number of function outputs.
casadi_int n_in() const
Get the number of function inputs.
bool is_diff_in(casadi_int ind) const
Get differentiability of inputs/output.
Function map(casadi_int n, const std::string ¶llelization="serial") const
Create a mapped version of this function.
size_t sz_w() const
Get required length of w field.
size_t sz_arg() const
Get required length of arg field.
casadi_int nnz_in() const
Get number of input nonzeros.
int eval_gen(const T **arg, T **res, casadi_int *iw, T *w, int mem=0) const
Evaluate or propagate sparsities.
void serialize_type(SerializingStream &s) const override
Serialize type information.
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.
int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity forward.
void init(const Dict &opts) override
Initialize.
~Map() override
Destructor.
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate the function numerically.
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
bool has_function(const std::string &fname) const override
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity backwards.
std::string class_name() const override
Get type name.
void find(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, casadi_int max_depth) const override
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
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
virtual std::vector< std::string > get_function() const override
static Function create(const std::string ¶llelization, const Function &f, casadi_int n)
Map(DeserializingStream &s)
Deserializing constructor.
virtual std::string parallelization() const
Type of parallellization.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
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.
void init(const Dict &opts) override
Initialize.
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate the function numerically.
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
~OmpMap() override
Destructor.
Base class for FunctionInternal and LinsolInternal.
void clear_mem()
Clear all memory (called from destructor)
The basic scalar symbolic class of CasADi.
Helper class for Serialization.
void pack(const Sparsity &e)
Serializes an object to the output stream.
Class representing a Slice.
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
~ThreadMap() override
Destructor.
void init(const Dict &opts) override
Initialize.
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate the function numerically.
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
void ThreadsWork(const Function &f, casadi_int i, const double **arg, double **res, casadi_int *iw, double *w, casadi_int ind, int &ret)
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.