26 #include "sx_function.hpp"
33 #include "sx_node.hpp"
34 #include "output_sx.hpp"
35 #include "call_sx.hpp"
36 #include "casadi_common.hpp"
37 #include "sparsity_internal.hpp"
38 #include "casadi_interrupt.hpp"
39 #include "serializing_stream.hpp"
40 #include "global_options.hpp"
56 const std::vector<SX >& inputv,
57 const std::vector<SX >& outputv,
58 const std::vector<std::string>& name_in,
59 const std::vector<std::string>& name_out)
73 casadi_int* iw,
double* w,
void* mem)
const {
78 setup(mem, arg, res, iw, w);
84 casadi_error(
"Cannot evaluate \"" + ss.str() +
"\" since variables "
99 CASADI_MATH_FUN_BUILTIN(w[e.i1], w[e.i2], w[e.i0])
101 case OP_CONST: w[e.i0] = e.d;
break;
102 case OP_INPUT: w[e.i0] = arg[e.i1]==
nullptr ? 0 : arg[e.i1][e.i2];
break;
103 case OP_OUTPUT:
if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
break;
108 casadi_error(
"Unknown operation" +
str(e.op));
118 CASADI_MATH_FUN_BUILTIN(w[e.i1], w[e.i2], w[e.i0])
120 case OP_CONST: w[e.i0] = e.d;
break;
121 case OP_INPUT: w[e.i0] = arg[e.i1]==
nullptr ? 0 : arg[e.i1][e.i2];
break;
122 case OP_OUTPUT:
if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
break;
127 casadi_error(
"Unknown operation" +
str(e.op));
132 if (trace) *trace <<
"{\"event\":\"error\"}\n";
140 const double* w,
bool output)
const {
142 const int* slots = output ? &e.i0 : &e.i1;
147 n = output ?
call.n_res :
call.n_dep;
153 trace <<
"{\"instruction\":" << k <<
",\"op\":" << e.op
154 <<
",\"phase\":\"" << (output ?
"outputs" :
"inputs") <<
"\",\"values\":[";
155 for (casadi_int i = 0; i < n; ++i) {
157 trace_values(trace, slots[i] < 0 ?
nullptr : w + slots[i], 1);
165 if (!operation_checker<SmoothChecker>(a.op)) {
172 std::stringstream stream;
174 stream <<
"output[" << a.
i0 <<
"][" << a.
i2 <<
"] = @" << a.
i1;
179 for (casadi_int i=0; i<m.
f.
n_out(); ++i) {
180 if (m.
f.
nnz_out(i)>1) stream <<
"[";
181 for (casadi_int j=0; j<m.
f.
nnz_out(i); ++j) {
188 if (j<m.
f.
nnz_out(i)-1) stream <<
",";
190 if (m.
f.
nnz_out(i)>1) stream <<
"]";
191 if (i<m.
f.
n_out()-1) stream <<
",";
194 stream << m.
f.
name() <<
"(";
196 for (casadi_int i=0; i<m.
f.
n_in(); ++i) {
197 if (m.
f.
nnz_in(i)==0) stream <<
"0x0";
198 if (m.
f.
nnz_in(i)>1) stream <<
"[";
199 for (casadi_int j=0; j<m.
f.
nnz_in(i); ++j) {
200 stream <<
"@" << m.
dep[k++];
201 if (j<m.
f.
nnz_in(i)-1) stream <<
",";
203 if (m.
f.
nnz_in(i)>1) stream <<
"]";
204 if (i<m.
f.
n_in()-1) stream <<
",";
208 stream <<
"@" << a.
i0 <<
" = ";
210 stream <<
"input[" << a.
i1 <<
"][" << a.
i2 <<
"]";
218 stream << casadi_math<double>::pre(a.
op);
219 for (casadi_int c=0; c<ndep; ++c) {
221 stream <<
"@" << a.
i1;
223 stream << casadi_math<double>::sep(a.
op);
224 stream <<
"@" << a.
i2;
228 stream << casadi_math<double>::post(a.
op);
236 stream <<
"Algorithm:";
256 casadi_error(
"Code generation of '" +
name_ +
"' is not possible since variables "
268 const double* w)
const {
270 stream <<
name_ <<
":" << k <<
": " <<
print(el) <<
" inputs:" << std::endl;
273 const int* dep = &el.
i1;
282 for (
size_t i = 0; i < ndeps; ++i) {
283 if (i>0) stream <<
", ";
295 for (
size_t i = 0; i < ndeps; ++i) {
317 }
else if (ndeps==2) {
338 const double* w)
const {
340 stream <<
name_ <<
":" << k <<
": " <<
print(el) <<
" outputs:" << std::endl;
343 const int* res = &el.
i0;
352 for (
size_t i = 0; i < nres; ++i) {
353 if (i>0) stream <<
", ";
365 for (
size_t i = 0; i < nres; ++i) {
384 g <<
"if (res[" << a.i0 <<
"]!=0) "
385 << g.
res(a.i0) <<
"[" << a.i2 <<
"]=" << g.
sx_work(a.i1) <<
";\n";
392 casadi_int offset = worksize;
393 for (casadi_int i=0; i<m.
f_n_in; ++i) {
395 g <<
"arg[" <<
n_in_+i <<
"] = "
401 g <<
"arg[" <<
n_in_+i <<
"]=" << 0 <<
";\n";
403 g <<
"arg[" <<
n_in_+i <<
"]=" <<
"w+" +
str(offset) <<
";\n";
410 casadi_int out_offset = offset;
413 for (casadi_int i=0; i<m.
f_n_out; ++i) {
414 g <<
"res[" <<
n_out_+i <<
"]=" <<
"w+" +
str(offset) <<
";\n";
418 for (casadi_int i=0; i<m.
f_n_in; ++i) {
420 for (casadi_int j=0; j<m.
f_nnz_in[i]; ++j) {
421 g <<
"w["+
str(k+worksize) +
"] = " << g.
sx_work(m.
dep[k]) <<
";\n";
432 g <<
"if (" << flag <<
") return 1;\n";
434 for (casadi_int i=0;i<m.
n_res;++i) {
437 g <<
"w[" +
str(i+out_offset) +
"];\n";
443 << g.
arg(a.i1) <<
"? " << g.
arg(a.i1) <<
"[" << a.i2 <<
"] : 0;\n";
456 casadi_assert_dev(ndep>0);
473 "Default input values"}},
474 {
"just_in_time_sparsity",
476 "Propagate sparsity patterns using just-in-time "
477 "compilation to a CPU or GPU using OpenCL"}},
478 {
"just_in_time_opencl",
480 "Just-in-time compilation for numeric evaluation using OpenCL (experimental)"}},
483 "Reuse variables in the work vector"}},
486 "Perform common subexpression elimination (complexity is N*log(N) in graph size)"}},
489 "Allow construction with free variables (Default: false)"}},
490 {
"allow_duplicate_io_names",
492 "Allow construction with duplicate io names (Default: false)"}},
495 "Dump interpreted instruction values to name.NNNNNN.trace.jsonl in dump_dir, "
496 "using the dump_in/dump_out counter. [false]"}},
497 {
"print_instructions",
499 "Print each operation during evaluation. Influenced by print_canonical."}}
506 if (target==
"clone") opts[
"default_in"] =
default_in_;
522 bool cse_opt =
false;
523 bool allow_free =
false;
526 for (
auto&& op : opts) {
527 if (op.first==
"default_in") {
529 }
else if (op.first==
"live_variables") {
531 }
else if (op.first==
"just_in_time_opencl") {
533 }
else if (op.first==
"just_in_time_sparsity") {
535 }
else if (op.first==
"cse") {
537 }
else if (op.first==
"allow_free") {
538 allow_free = op.second;
539 }
else if (op.first==
"dump_trace") {
541 }
else if (op.first==
"print_instructions") {
550 casadi_assert(!
dump_trace_ || !
jit_,
"dump_trace is not supported for JIT evaluation");
557 "Option 'default_in' has incorrect length");
560 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
561 std::lock_guard<std::mutex> lock(SX::get_mutex_temp());
565 std::stack<SXNode*> s;
568 std::vector<SXNode*> nodes;
572 for (
auto it =
out_.begin(); it !=
out_.end(); ++it, ++ind) {
574 for (
auto itc = (*it)->begin(); itc != (*it)->end(); ++itc, ++nz) {
580 nodes.push_back(
static_cast<SXNode*
>(
nullptr));
584 casadi_assert(nodes.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
586 for (casadi_int i=0; i<nodes.size(); ++i) {
588 nodes[i]->temp =
static_cast<int>(i);
595 for (std::vector<SXNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
606 std::vector<std::pair<int, SXNode*> > symb_loc;
609 int curr_oind, curr_nz=0;
610 casadi_assert(
out_.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
611 for (curr_oind=0; curr_oind<
out_.size(); ++curr_oind) {
612 if (
out_[curr_oind].nnz()!=0) {
618 std::vector<casadi_int> refcount(nodes.size(), 0);
625 std::vector<int> alg_index;
626 alg_index.reserve(nodes.size());
628 for (std::vector<SXNode*>::iterator it=nodes.begin(); it!=nodes.end(); ++it) {
636 ae.
op = n==
nullptr ?
static_cast<int>(
OP_OUTPUT) :
static_cast<int>(n->
op());
649 symb_loc.push_back(std::make_pair(
algorithm_.size(), n));
655 ae.
i1 =
out_[curr_oind]->at(curr_nz)->temp;
659 casadi_assert(curr_nz < std::numeric_limits<int>::max(),
"Integer overflow");
661 if (curr_nz>=
out_[curr_oind].nnz()) {
663 casadi_assert(curr_oind < std::numeric_limits<int>::max(),
"Integer overflow");
665 for (; curr_oind<
out_.size(); ++curr_oind) {
666 if (
out_[curr_oind].nnz()!=0) {
699 for (casadi_int i=0; i<ndeps; ++i) {
707 int oind =
static_cast<OutputSX*
>(n)->oind_;
708 casadi_assert(
call_.
el.at(dep[0]).res.at(oind)==-1,
"Duplicate");
719 for (casadi_int c=0; c<ndeps; ++c) {
720 refcount.at(dep[c])++;
732 std::vector<int> place(nodes.size());
735 std::stack<int> unused;
762 for (casadi_int c=ndeps-1; c>=0; --c) {
763 casadi_int ch_ind = dep[c];
764 casadi_int remaining = --refcount.at(ch_ind);
765 if (remaining==0) unused.push(place[ch_ind]);
770 for (casadi_int c=0; c<nres; ++c) {
771 if (res[c]<0)
continue;
774 res[c] = place[res[c]] = unused.top();
778 res[c] = place[res[c]] = worksize++;
784 for (casadi_int c=0; c<ndeps; ++c) {
785 dep[c] = place[dep[c]];
799 casadi_message(
"Using live variables: work array is " +
str(
worksize_)
800 +
" instead of " +
str(nodes.size()));
802 casadi_message(
"Live variables disabled.");
815 for (casadi_int i=0; i<nodes.size(); ++i) {
822 for (
auto it=symb_loc.begin(); it!=symb_loc.end(); ++it) {
823 it->second->temp = it->first+1;
827 casadi_assert(
in_.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
828 for (
int ind=0; ind<
in_.size(); ++ind) {
830 for (
auto itc =
in_[ind]->begin(); itc !=
in_[ind]->end(); ++itc, ++nz) {
831 int i = itc->get_temp()-1;
848 for (std::vector<std::pair<int, SXNode*> >::const_iterator it=symb_loc.begin();
849 it!=symb_loc.end(); ++it) {
850 if (it->second->temp!=0) {
863 casadi_error(
name_ +
"::init: Initialization failed since variables [" +
864 join(
get_free(),
", ") +
"] are free. These symbols occur in the output expressions "
865 "but you forgot to declare these as inputs. "
866 "Set option 'allow_free' to allow free variables.");
873 casadi_error(
"OpenCL is not supported in this version of CasADi");
878 casadi_error(
"OpenCL is not supported in this version of CasADi");
898 std::vector<casadi_int> alg_i(
worksize_, -1);
914 if (arg_i[e.i1]>=0) {
923 casadi_int offset_input = 0;
924 for (casadi_int i=0; i<m.f_n_in; ++i) {
927 casadi_int offset = -1;
928 for (casadi_int j=0; j<m.f_nnz_in[i]; ++j) {
929 casadi_int k = offset_input+j;
931 arg = arg_i[m.dep[k]];
932 offset = nz_i[m.dep[k]];
934 if (arg_i[m.dep[k]]==-1) {
939 if (nz_i[m.dep[k]]!=offset+j) {
949 for (casadi_int j=0; j<m.f_nnz_in[i]; ++j) {
950 casadi_int k = offset_input+j;
951 if (arg_i[m.dep[k]]>=0) {
957 m.copy_elision_arg[i] = arg;
958 m.copy_elision_offset[i] = offset;
960 offset += m.f_nnz_in[i];
961 offset_input += m.f_nnz_in[i];
965 for (casadi_int i=0; i<m.n_res; ++i) {
967 arg_i[m.res[i]] = -1;
978 if (arg_i[e.i1]>=0) {
982 if (arg_i[e.i2]>=0) {
996 std::vector<SXElem>::iterator it=ret.begin();
999 std::vector<SXElem>::const_iterator b_it =
operations_.begin();
1002 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
1005 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
1008 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1025 casadi_assert(it==ret.end(),
"Dimension mismatch");
1031 bool always_inline,
bool never_inline)
const {
1044 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1047 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
1050 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
1053 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1057 w[a.i0] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
1060 if (res[a.i0]!=
nullptr) res[a.i0][a.i2] = w[a.i1];
1066 w[a.i0] = *p_it++;
break;
1070 const SXElem& orig = *b_it++;
1071 std::vector<SXElem> deps(m.
n_dep);
1072 bool identical =
true;
1074 std::vector<SXElem> ret;
1075 for (casadi_int i=0;i<m.
n_dep;++i) {
1081 for (casadi_int i=0;i<m.
n_dep;++i) deps[i] = w[m.
dep[i]];
1084 for (casadi_int i=0;i<m.
n_res;++i) {
1085 if (m.
res[i]>=0) w[m.
res[i]] = ret[i];
1095 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1100 const casadi_int depth = 2;
1112 bool always_inline,
bool never_inline)
const {
1117 if (!always_inline) {
1125 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
1128 "Free variables not supported in inlining call to SXFunction::eval_mx");
1131 casadi_assert(arg.size()==
n_in_,
"Wrong number of input arguments");
1132 res.resize(
out_.size());
1135 std::vector<MX> w(
sz_w());
1136 if (
verbose_) casadi_message(
"Allocated work vector");
1139 std::vector<std::vector<MX> > arg_split(
in_.size());
1140 for (casadi_int i=0; i<
in_.size(); ++i) {
1142 std::vector<MX> orig = arg[i].get_nonzeros();
1146 std::vector<MX> w(arg[i].size1());
1151 arg_split[i] = target;
1155 std::vector<std::vector<MX> > res_split(
out_.size());
1156 for (casadi_int i=0; i<
out_.size(); ++i) res_split[i].resize(
nnz_out(i));
1159 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1163 w[a.i0] = arg_split[a.i1][a.i2];
1166 res_split[a.i0][a.i2] = w[a.i1];
1169 w[a.i0] =
static_cast<double>(*c_it++);
1174 std::vector<MX> deps(m.
n_dep);
1175 std::vector<MX> args;
1179 for (casadi_int i=0;i<m.
f_n_in;++i) {
1180 std::vector<MX> arg;
1181 for (casadi_int j=0;j<m.
f_nnz_in[i];++j) {
1182 arg.push_back(w[m.
dep[k++]]);
1184 args.push_back(sparsity_cast(vertcat(arg), m.
f.
sparsity_in(i)));
1188 std::vector<MX> ret = m.
f(args);
1189 std::vector<MX> res;
1192 for (casadi_int i=0;i<m.
f_n_out;++i) {
1193 std::vector<MX> nz = ret[i].get_nonzeros();
1194 res.insert(res.end(), nz.begin(), nz.end());
1198 for (casadi_int i=0;i<m.
n_res;++i) {
1199 if (m.
res[i]>=0) w[m.
res[i]] = res[i];
1208 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1217 for (casadi_int i=0; i<res.size(); ++i) {
1218 res[i] = sparsity_cast(vertcat(res_split[i]),
sparsity_out_[i]);
1224 casadi_assert(!(always_inline && never_inline),
1226 casadi_assert(!(never_inline &&
has_free()),
1228 if (always_inline)
return true;
1229 if (never_inline)
return false;
1237 std::vector<std::vector<SX> >& fsens)
const {
1241 casadi_int nfwd = fseed.size();
1245 if (nfwd==0)
return;
1248 casadi_int npar = 1;
1249 for (
auto&& r : fseed) {
1251 casadi_assert_dev(npar==1);
1258 for (
auto it=fseed.begin(); it!=fseed.end(); ++it) {
1259 casadi_assert_dev(it->size()==
n_in_);
1260 for (casadi_int i=0; i<
n_in_; ++i) {
1263 std::vector<std::vector<SX> > fseed2(fseed);
1264 for (
auto&& r : fseed2) {
1274 for (casadi_int d=0; d<nfwd; ++d) {
1276 for (casadi_int i=0; i<fsens[d].size(); ++i)
1282 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1285 std::vector<TapeEl<SXElem> > s_pdwork(
operations_.size());
1286 std::vector<TapeEl<SXElem> >::iterator it1 = s_pdwork.begin();
1289 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1301 CASADI_MATH_DER_BUILTIN(f->
dep(0), f->
dep(1), f, it1++->d)
1313 if (
verbose_) casadi_message(
"Calculating forward derivatives");
1314 for (casadi_int dir=0; dir<nfwd; ++dir) {
1315 std::vector<TapeEl<SXElem> >::const_iterator it2 = s_pdwork.begin();
1319 w[a.i0] = fseed[dir][a.i1].nonzeros()[a.i2];
break;
1321 fsens[dir][a.i0].nonzeros()[a.i2] = w[a.i1];
break;
1331 const auto& m =
call_.
el.at(a.i1);
1332 CallSX* call_node =
static_cast<CallSX*
>(it2->d[0].get());
1338 std::vector<SXElem> deps;
1339 deps.reserve(2*m.n_dep);
1342 casadi_int offset = 0;
1343 for (casadi_int i=0;i<m.f_n_in;++i) {
1344 casadi_int nnz = ff.
nnz_in(i);
1345 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1346 for (casadi_int j=0;j<nnz;++j) {
1347 deps.push_back(call_node->
dep(offset+j));
1349 offset += m.f_nnz_in[i];
1353 std::vector<casadi_int> oind;
1355 for (casadi_int i=0;i<m.f_n_out;++i) {
1356 casadi_int nnz = ff.
nnz_in(i+m.f_n_in);
1357 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1358 for (casadi_int j=0;j<nnz;++j) {
1359 oind.push_back(offset+j);
1361 offset += m.f_nnz_out[i];
1364 auto nominal_outputs = call_node->
get_output(oind);
1365 deps.insert(deps.end(), nominal_outputs.begin(), nominal_outputs.end());
1369 for (casadi_int i=0;i<m.f_n_in;++i) {
1370 casadi_int nnz = ff.
nnz_in(i+m.f_n_in+m.f_n_out);
1372 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1374 for (casadi_int j=0;j<nnz;++j) {
1375 deps.push_back(w[m.dep[offset+j]]);
1378 offset += m.f_nnz_in[i];
1387 for (casadi_int i=0;i<m.f_n_out;++i) {
1388 casadi_int nnz = ff.
nnz_out(i);
1390 casadi_assert(nnz==0 || nnz==m.f_nnz_out[i],
"Not implemented");
1392 for (casadi_int j=0;j<nnz;++j) {
1393 if (m.res[offset+j]>=0) w[m.res[offset+j]] = ret[k];
1397 offset += m.f_nnz_out[i];
1402 CASADI_MATH_BINARY_BUILTIN
1403 w[a.i0] = it2->d[0] * w[a.i1] + it2->d[1] * w[a.i2];
1407 w[a.i0] = it2->d[0] * w[a.i1];
1415 std::vector<std::vector<SX> >& asens)
const {
1419 casadi_int nadj = aseed.size();
1423 if (nadj==0)
return;
1426 casadi_int npar = 1;
1427 for (
auto&& r : aseed) {
1429 casadi_assert_dev(npar==1);
1436 bool matching_sparsity =
true;
1437 for (casadi_int d=0; d<nadj; ++d) {
1438 casadi_assert_dev(aseed[d].size()==
n_out_);
1439 for (casadi_int i=0; matching_sparsity && i<
n_out_; ++i)
1440 matching_sparsity = aseed[d][i].sparsity()==
sparsity_out_[i];
1444 if (!matching_sparsity) {
1445 std::vector<std::vector<SX> > aseed2(aseed);
1446 for (casadi_int d=0; d<nadj; ++d)
1447 for (casadi_int i=0; i<
n_out_; ++i)
1455 for (casadi_int d=0; d<nadj; ++d) {
1456 asens[d].resize(
n_in_);
1457 for (casadi_int i=0; i<asens[d].size(); ++i) {
1461 std::fill(asens[d][i]->begin(), asens[d][i]->end(), 0);
1467 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1470 std::vector<TapeEl<SXElem> > s_pdwork(
operations_.size());
1471 std::vector<TapeEl<SXElem> >::iterator it1 = s_pdwork.begin();
1474 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1486 CASADI_MATH_DER_BUILTIN(f->
dep(0), f->
dep(1), f, it1++->d)
1495 if (
verbose_) casadi_message(
"Calculating adjoint derivatives");
1500 for (casadi_int dir=0; dir<nadj; ++dir) {
1501 auto it2 = s_pdwork.rbegin();
1506 asens[dir][it->i1].nonzeros()[it->i2] = w[it->i0];
1510 w[it->i1] += aseed[dir][it->i0].nonzeros()[it->i2];
1523 const auto& m =
call_.
el.at(it->i1);
1524 CallSX* call_node =
static_cast<CallSX*
>(it2->d[0].get());
1530 std::vector<SXElem> deps;
1531 deps.reserve(m.n_dep+m.n_res);
1534 casadi_int offset = 0;
1535 for (casadi_int i=0;i<m.f_n_in;++i) {
1536 casadi_int nnz = fr.
nnz_in(i);
1537 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1538 for (casadi_int j=0;j<nnz;++j) {
1539 deps.push_back(call_node->
dep(offset+j));
1541 offset += m.f_nnz_in[i];
1545 std::vector<casadi_int> oind;
1547 for (casadi_int i=0;i<m.f_n_out;++i) {
1548 casadi_int nnz = fr.
nnz_in(i+m.f_n_in);
1549 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1550 for (casadi_int j=0;j<nnz;++j) {
1551 oind.push_back(offset+j);
1553 offset += m.f_nnz_out[i];
1556 auto nominal_outputs = call_node->
get_output(oind);
1557 deps.insert(deps.end(), nominal_outputs.begin(), nominal_outputs.end());
1561 for (casadi_int i=0;i<m.f_n_out;++i) {
1562 casadi_int nnz = fr.
nnz_in(i+m.f_n_in+m.f_n_out);
1564 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1566 for (casadi_int j=0;j<nnz;++j) {
1567 deps.push_back((m.res[offset+j]>=0) ? w[m.res[offset+j]] : 0);
1570 offset += m.f.nnz_out(i);
1577 for (casadi_int i=0;i<m.n_res;++i) {
1578 if (m.res[i]>=0) w[m.res[i]] = 0;
1584 for (casadi_int i=0;i<m.f_n_in;++i) {
1585 casadi_int nnz = fr.
nnz_out(i);
1587 casadi_assert(nnz==0 || nnz==m.f_nnz_in[i],
"Not implemented");
1589 for (casadi_int j=0;j<nnz;++j) {
1590 w[m.dep[offset+j]] += ret[k++];
1593 offset += m.f_nnz_in[i];
1598 CASADI_MATH_BINARY_BUILTIN
1601 w[it->i1] += it2->d[0] * seed;
1602 w[it->i2] += it2++->d[1] * seed;
1607 w[it->i1] += it2++->d[0] * seed;
1613 for (casadi_int d=0; d<nadj; ++d) {
1614 for (casadi_int i=0; i<
n_in_; ++i) {
1615 SX& a = asens[d][i];
1621 template<
typename T,
typename CT>
1623 CT*** call_arg, T*** call_res, casadi_int** call_iw, T** call_w, T**
nz_in, T**
nz_out)
const {
1632 for (casadi_int i=0;i<m.
f_n_in;++i) {
1633 (*call_arg)[i] = ptr_w;
1639 for (casadi_int i=0;i<m.
f_n_out;++i) {
1640 (*call_res)[i] = ptr_w;
1645 template<
typename T>
1648 const T** call_arg = arg;
1650 casadi_int* call_iw = iw;
1658 for (casadi_int i=0;i<m.n_dep;++i) {
1659 nz_in[i] = w[m.dep[i]];
1662 m.f(call_arg, call_res, call_iw, call_w);
1665 for (casadi_int i=0;i<m.n_res;++i) {
1674 template<
typename T>
1679 casadi_int* call_iw = iw;
1686 std::fill_n(
nz_in, m.n_dep, 0);
1689 for (casadi_int i=0;i<m.n_res;++i) {
1690 nz_out[i] = (m.res[i]>=0) ? w[m.res[i]] : 0;
1694 m.f.rev(call_arg, call_res, call_iw, call_w);
1697 for (casadi_int i=0;i<m.n_res;++i) {
1698 if (m.res[i]>=0) w[m.res[i]] = 0;
1702 for (casadi_int i=0;i<m.n_dep;++i) {
1703 w[m.dep[i]] |=
nz_in[i];
1719 w[e.i0] = (arg[e.i1]!=
nullptr &&
is_diff_in_[e.i1]) ? arg[e.i1][e.i2] : 0;
1722 if (res[e.i0]!=
nullptr) res[e.i0][e.i2] =
is_diff_out_[e.i0] ? w[e.i1] : 0;
1728 w[e.i0] = w[e.i1] | w[e.i2];
break;
1736 const bvec_t nz = ~static_cast<bvec_t>(0);
1741 w[e.i0] = (e.d!=0) ? nz : 0;
break;
1743 w[e.i0] = nz;
break;
1745 w[e.i0] = (arg[e.i1]!=
nullptr) ? arg[e.i1][e.i2] : 0;
1748 if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
1756 w[e.i0] = w[e.i1] ? nz : (operation_checker<F0XChecker>(e.op) ? 0 : nz);
1758 const bool z0 = w[e.i1]!=0, z1 = w[e.i2]!=0;
1759 if (!z0 && !z1) w[e.i0] = operation_checker<F00Checker>(e.op) ? 0 : nz;
1760 else if (!z0 && z1) w[e.i0] = operation_checker<F0XChecker>(e.op) ? 0 : nz;
1761 else if ( z0 && !z1) w[e.i0] = operation_checker<FX0Checker>(e.op) ? 0 : nz;
1771 casadi_int* iw,
bvec_t* w)
const {
1773 const bvec_t** call_arg = arg;
1775 casadi_int* call_iw = iw;
1783 for (casadi_int i=0; i<m.n_dep; ++i)
nz_in[i] = w[m.dep[i]];
1785 m.f.eval_activity(call_arg, call_res, call_iw, call_w);
1787 for (casadi_int i=0; i<m.n_res; ++i) {
1788 if (m.res[i]>=0) w[m.res[i]] =
nz_out[i];
1793 casadi_int* iw,
bvec_t* w,
void* mem)
const {
1797 std::fill_n(w,
sz_w(), 0);
1812 arg[it->i1][it->i2] |= w[it->i0];
1817 w[it->i1] |= res[it->i0][it->i2];
1818 res[it->i0][it->i2] = 0;
1843 std::map<std::string, bool> flagged;
1846 const auto& m =
call_.
el.at(a.i1);
1848 if (flagged.find(f.
name())==flagged.end()) {
1849 flagged[f.
name()] =
true;
1853 std::vector<std::string> ret;
1854 for (
auto it : flagged) {
1855 ret.push_back(it.first);
1863 const auto& m =
call_.
el.at(a.i1);
1865 if (name==f.
name())
return f;
1868 casadi_error(
"No such function '" + name +
"'.");
1877 std::ostream &ss,
const Dict& options)
const {
1880 casadi_int indent_level = 0;
1883 for (
auto&& op : options) {
1884 if (op.first==
"indent_level") {
1885 indent_level = op.second;
1887 casadi_error(
"Unknown option '" + op.first +
"'.");
1893 for (casadi_int i=0;i<indent_level;++i) {
1898 for (casadi_int i=0;i<
n_in_;++i) {
1899 ss << indent <<
"argin_" << i <<
" = nonzeros_gen(varargin{" << i+1 <<
"});" << std::endl;
1902 Function f = shared_from_this<Function>();
1914 ss << indent <<
"w" << o[0] <<
" = " <<
"argin_" << i[0] <<
"(" << i[1]+1 <<
");";
1920 ss << indent <<
"argout_" << o[0] <<
"{" << o[1]+1 <<
"} = w" << i[0] <<
";";
1926 std::ios_base::fmtflags fmtfl = ss.flags();
1927 ss << indent <<
"w" << o[0] <<
" = ";
1928 ss << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1);
1935 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
"^2;" << std::endl;
1940 ss << indent <<
"w" << o[0] <<
" = abs(" <<
"w" << i[0] <<
");" << std::endl;
1945 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".^w" << i[1] <<
";" << std::endl;
1948 ss << indent <<
"w" << o[0] <<
" = ~" <<
"w" << i[0] <<
";" << std::endl;
1951 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" | w" << i[1] <<
";" << std::endl;
1954 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" & w" << i[1] <<
";" << std::endl;
1957 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" ~= w" << i[1] <<
";" << std::endl;
1960 ss << indent <<
"w" << o[0] <<
" = ";
1961 ss <<
"if_else_zero_gen(w" << i[0] <<
", w" << i[1] <<
");" << std::endl;
1966 "w"+std::to_string(i[0]),
"w"+std::to_string(i[1])) <<
";" << std::endl;
1969 "w"+std::to_string(i[0])) <<
";" << std::endl;
1978 int version = s.
version(
"SXFunction", 1, 4);
1998 s.
unpack(
"SXFunction::call_el_size", el_size);
2002 for (casadi_int k=0;k<el_size;++k) {
2004 s.
unpack(
"SXFunction::call_el_f", f);
2007 s.
unpack(
"SXFunction::call_el_dep", e.dep);
2008 s.
unpack(
"SXFunction::call_el_res", e.res);
2009 s.
unpack(
"SXFunction::call_el_copy_elision_arg", e.copy_elision_arg);
2010 s.
unpack(
"SXFunction::call_el_copy_elision_offset", e.copy_elision_offset);
2029 s.
unpack(
"SXFunction::ScalarAtomic::op", e.
op);
2030 s.
unpack(
"SXFunction::ScalarAtomic::i0", e.
i0);
2031 s.
unpack(
"SXFunction::ScalarAtomic::i1", e.
i1);
2032 s.
unpack(
"SXFunction::ScalarAtomic::i2", e.
i2);
2069 s.
pack(
"SXFunction::call_el_size",
call_.
el.size());
2071 for (
const auto& n :
call_.
el) {
2072 s.
pack(
"SXFunction::call_el_f", n.f);
2073 s.
pack(
"SXFunction::call_el_dep", n.dep);
2074 s.
pack(
"SXFunction::call_el_res", n.res);
2075 s.
pack(
"SXFunction::call_el_copy_elision_arg", n.copy_elision_arg);
2076 s.
pack(
"SXFunction::call_el_copy_elision_offset", n.copy_elision_offset);
2083 s.
pack(
"SXFunction::ScalarAtomic::op", e.op);
2084 s.
pack(
"SXFunction::ScalarAtomic::i0", e.i0);
2085 s.
pack(
"SXFunction::ScalarAtomic::i1", e.i1);
2086 s.
pack(
"SXFunction::ScalarAtomic::i2", e.i2);
2101 casadi_int max_depth)
const {
2114 if (option_name ==
"print_instructions") {
2116 }
else if (option_name ==
"dump_trace") {
2117 bool value = option_value;
2118 casadi_assert(!value || !
jit_,
"dump_trace is not supported for JIT evaluation");
2127 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
2128 std::lock_guard<std::mutex> lock(SX::get_mutex_temp());
2131 std::stack<SXNode*> s;
2134 std::vector<SXNode*> nodes;
2138 for (
auto it = expr.begin(); it != expr.end(); ++it, ++ind) {
2140 for (
auto itc = (*it)->begin(); itc != (*it)->end(); ++itc, ++nz) {
2148 for (casadi_int i=0; i<nodes.size(); ++i) {
2152 std::vector<SX> ret(nodes.size());
2153 for (casadi_int i=0; i<nodes.size(); ++i) {
SXElem get_output(casadi_int oind) const override
Get an output.
const SXElem & dep(casadi_int i) const override
get the reference of a dependency
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.
void reserve_work(casadi_int n)
Reserve a maximum size of work elements, used for padding of index.
std::string constant(const std::vector< casadi_int > &v)
Represent an array constant; adding it when new.
std::string printf(const std::string &str, const std::vector< std::string > &arg=std::vector< std::string >())
Printf.
std::string print_op(casadi_int op, const std::string &a0)
Print an operation to a c file.
void print_vector(std::ostream &s, const std::string &name, const std::vector< casadi_int > &v)
Print casadi_int vector to a c file.
std::string res(casadi_int i) const
Refer to resuly.
bool avoid_stack() const
Avoid stack?
std::string sx_work(casadi_int i)
Declare a work vector element.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
Internal class for Function.
void finish_trace(std::ostream &trace, double **res, int ret) const
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
std::vector< Sparsity > sparsity_in_
Input and output sparsity.
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_
void alloc_res(size_t sz_res, bool persistent=false)
Ensure required length of res field.
std::string definition() const
Get function signature: name:(inputs)->(outputs)
void alloc_arg(size_t sz_arg, bool persistent=false)
Ensure required length of arg field.
static void print_canonical(std::ostream &stream, const Sparsity &sp, const double *nz)
Print canonical representation of a numeric matrix.
bool jit_
Use just-in-time compiler.
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
virtual double sp_weight() const
Weighting factor for chosing forward/reverse mode,.
size_t n_in_
Number of inputs and outputs.
virtual void eval_mx(const MXVector &arg, MXVector &res, bool always_inline, bool never_inline) const
Evaluate with symbolic matrices.
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.
bool matching_arg(const std::vector< M > &arg, casadi_int &npar) const
Check if input arguments that needs to be replaced.
virtual int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const
Propagate sparsity forward.
std::vector< double > nz_in(const std::vector< DM > &arg) const
Convert from/to flat vector of input/output nonzeros.
static const Options options_
Options.
std::vector< Sparsity > sparsity_out_
void call(const std::vector< M > &arg, std::vector< M > &res, bool always_inline, bool never_inline) const
Call a function, templated.
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.
std::unique_ptr< std::ostream > open_trace(const double **arg, casadi_int dump_id) const
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
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 setup(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const
Set the (persistent and temporary) work vectors.
static void trace_values(std::ostream &trace, const double *values, casadi_int nnz)
std::vector< bool > is_diff_in_
Are inputs and outputs differentiable?
void change_option(const std::string &option_name, const GenericType &option_value) override
Change option after object creation for debugging.
Dict generate_options(const std::string &target) const override
Reconstruct options dict.
std::vector< std::vector< M > > replace_aseed(const std::vector< std::vector< M >> &aseed, casadi_int npar) const
Replace 0-by-0 reverse seeds.
Function forward(casadi_int nfwd) const
Get a function that calculates nfwd forward derivatives.
casadi_int nnz_out() const
Get number of output nonzeros.
casadi_int n_instructions() const
Number of instruction in the algorithm (SXFunction/MXFunction)
size_t sz_res() const
Get required length of res field.
const std::string & name() const
Name of the function.
Function reverse(casadi_int nadj) const
Get a function that calculates nadj adjoint derivatives.
std::vector< casadi_int > instruction_input(casadi_int k) const
Locations in the work vector for the inputs of the instruction.
const Sparsity & sparsity_in(casadi_int ind) const
Get sparsity of a given input.
std::vector< casadi_int > instruction_output(casadi_int k) const
Location in the work vector for the output of the instruction.
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.
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.
double instruction_constant(casadi_int k) const
Get the floating point output argument of an instruction (SXFunction)
casadi_int instruction_id(casadi_int k) const
Identifier index of the instruction (SXFunction/MXFunction)
casadi_int size2() const
Get the second dimension (i.e. number of columns)
casadi_int size1() const
Get the first dimension (i.e. number of rows)
static Matrix< Scalar > zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
Generic data type, can hold different types such as bool, casadi_int, std::string etc.
static casadi_int copy_elision_min_size
static void check()
Raises an error if an interrupt was captured.
Sparse matrix class. SX and DM are specializations.
bool is_zero() const
check if the matrix is 0 (note that false negative answers are possible)
void print_scalar(std::ostream &stream) const
Print scalar.
static std::vector< SXElem > split(const SXElem &e, casadi_int n)
Base class for FunctionInternal and LinsolInternal.
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
The basic scalar symbolic class of CasADi.
void assignIfDuplicate(const SXElem &scalar, casadi_int depth=1)
Assign to another expression, if a duplicate.
static std::vector< SXElem > call(const Function &f, const std::vector< SXElem > &deps)
static SXElem create(SXNode *node)
SXNode * get() const
Get a pointer to the node.
static bool is_equal(const SXElem &x, const SXElem &y, casadi_int depth=0)
Check equality up to a given depth.
Internal node class for SXFunction.
std::vector< SXElem > operations_
The expressions corresponding to each binary operation.
SXFunction(const std::string &name, const std::vector< Matrix< SXElem > > &inputv, const std::vector< Matrix< SXElem > > &outputv, const std::vector< std::string > &name_in, const std::vector< std::string > &name_out)
Constructor.
void eval_mx(const MXVector &arg, MXVector &res, bool always_inline, bool never_inline) const override
Evaluate symbolically, MX type.
SX instructions_sx() const override
get SX expression associated with instructions
void call_activity(const AlgEl &e, const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const
void ad_reverse(const std::vector< std::vector< SX > > &aseed, std::vector< std::vector< SX > > &asens) const
Calculate reverse mode directional derivatives.
std::string print(const ScalarAtomic &a) const
bool should_inline(bool with_sx, bool always_inline, bool never_inline) const override
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
void print_res(std::ostream &stream, casadi_int k, const ScalarAtomic &el, const double *w) const
const std::vector< SX > sx_in() const override
Get function input(s) and output(s)
void init(const Dict &opts) override
Initialize.
void export_code_body(const std::string &lang, std::ostream &stream, const Dict &options) const override
Export function in a specific language.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void init_copy_elision()
Part of initialize responsible of prepaprign copy elision.
static const Options options_
Options.
std::vector< bool > copy_elision_
Copy elision per algel.
int eval_activity(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate signal activity forward.
bool is_smooth() const
Check if smooth.
int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity forward.
size_t codegen_sz_w(const CodeGenerator &g) const override
Get the size of the work vector, for codegen.
void call_rev(const AlgEl &e, T **arg, T **res, casadi_int *iw, T *w) const
bool has_free() const override
Does the function have free variables.
std::vector< std::string > get_function() const override
Get list of dependency functions.
void call_fwd(const AlgEl &e, const T **arg, T **res, casadi_int *iw, T *w) const
std::vector< SXElem > constants_
The expressions corresponding to each constant.
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity backwards.
bool just_in_time_opencl_
With just-in-time compilation using OpenCL.
struct casadi::SXFunction::CallInfo call_
void change_option(const std::string &option_name, const GenericType &option_value) override
Change option after object creation for debugging.
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
static std::vector< SX > order(const std::vector< SX > &expr)
void print_arg(std::ostream &stream, casadi_int k, const ScalarAtomic &el, const double *w) const
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
std::vector< std::string > get_free() const override
Print free variables.
std::vector< AlgEl > algorithm_
all binary nodes of the tree in the order of execution
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate numerically, work vectors given.
std::vector< SXElem > free_vars_
Free variables.
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
std::vector< double > default_in_
Default input values.
void trace_instruction(std::ostream &trace, casadi_int k, const double *w, bool output) const
void disp_more(std::ostream &stream) const override
Print the algorithm.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize without type information.
~SXFunction() override
Destructor.
Dict generate_options(const std::string &target="clone") const override
Reconstruct options dict.
bool print_instructions_
Print each operation during evaluation.
void call_setup(const ExtendedAlgEl &m, CT ***call_arg, T ***call_res, casadi_int **call_iw, T **call_w, T **nz_in, T **nz_out) const
bool live_variables_
Live variables?
void find(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, casadi_int max_depth) const override
void ad_forward(const std::vector< std::vector< SX > > &fseed, std::vector< std::vector< SX > > &fsens) const
Calculate forward mode directional derivatives.
casadi_int n_instructions() const override
Get the number of atomic operations.
bool just_in_time_sparsity_
With just-in-time compilation for the sparsity propagation.
Internal node class for SX.
virtual const SXElem & dep(casadi_int i) const
get the reference of a child
virtual double to_double() const
Get value of a constant node.
virtual bool is_symbolic() const
check properties of a node
virtual casadi_int op() const =0
get the operation
virtual bool is_constant() const
check properties of a node
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
Internal node class for the base class of SXFunction and MXFunction.
std::vector< Matrix< SXElem > > out_
Outputs of the function (needed for symbolic calculations)
void delayed_deserialize_members(DeserializingStream &s)
void init(const Dict &opts) override
Initialize.
std::vector< Matrix< SXElem > > in_
Inputs of the function (needed for symbolic calculations)
void delayed_serialize_members(SerializingStream &s) const
Helper functions to avoid recursion limit.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
static void sort_depth_first(std::stack< SXNode * > &s, std::vector< SXNode * > &nodes)
Topological sorting of the nodes based on Depth-First Search (DFS)
std::string join(const std::vector< std::string > &l, const std::string &delim)
double if_else_zero(double x, double y)
Conditional assignment.
unsigned long long bvec_t
void casadi_project(const T1 *x, const casadi_int *sp_x, T1 *y, const casadi_int *sp_y, T1 *w)
Sparse copy: y <- x, w work vector (length >= number of rows)
std::vector< MX > MXVector
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
Function memory with temporary work vectors.
Options metadata for a class.
std::vector< ExtendedAlgEl > el
std::vector< int > copy_elision_offset
std::vector< int > copy_elision_arg
std::vector< int > f_nnz_out
ExtendedAlgEl(const Function &fun)
std::vector< int > f_nnz_in
An atomic operation for the SXElem virtual machine.
Easy access to all the functions for a particular type.
static casadi_int ndeps(unsigned char op)
Number of dependencies.
static std::string print(unsigned char op, const std::string &x, const std::string &y)
Print.