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 {
75 setup(mem, arg, res, iw, w);
81 casadi_error(
"Cannot evaluate \"" + ss.str() +
"\" since variables "
95 CASADI_MATH_FUN_BUILTIN(w[e.i1], w[e.i2], w[e.i0])
98 case OP_INPUT: w[e.i0] = arg[e.i1]==
nullptr ? 0 : arg[e.i1][e.i2];
break;
99 case OP_OUTPUT:
if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
break;
104 casadi_error(
"Unknown operation" +
str(e.op));
113 CASADI_MATH_FUN_BUILTIN(w[e.i1], w[e.i2], w[e.i0])
115 case OP_CONST: w[e.i0] = e.d;
break;
116 case OP_INPUT: w[e.i0] = arg[e.i1]==
nullptr ? 0 : arg[e.i1][e.i2];
break;
117 case OP_OUTPUT:
if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
break;
122 casadi_error(
"Unknown operation" +
str(e.op));
132 if (!operation_checker<SmoothChecker>(a.op)) {
139 std::stringstream stream;
141 stream <<
"output[" << a.
i0 <<
"][" << a.
i2 <<
"] = @" << a.
i1;
146 for (casadi_int i=0; i<m.
f.
n_out(); ++i) {
147 if (m.
f.
nnz_out(i)>1) stream <<
"[";
148 for (casadi_int j=0; j<m.
f.
nnz_out(i); ++j) {
155 if (j<m.
f.
nnz_out(i)-1) stream <<
",";
157 if (m.
f.
nnz_out(i)>1) stream <<
"]";
158 if (i<m.
f.
n_out()-1) stream <<
",";
161 stream << m.
f.
name() <<
"(";
163 for (casadi_int i=0; i<m.
f.
n_in(); ++i) {
164 if (m.
f.
nnz_in(i)==0) stream <<
"0x0";
165 if (m.
f.
nnz_in(i)>1) stream <<
"[";
166 for (casadi_int j=0; j<m.
f.
nnz_in(i); ++j) {
167 stream <<
"@" << m.
dep[k++];
168 if (j<m.
f.
nnz_in(i)-1) stream <<
",";
170 if (m.
f.
nnz_in(i)>1) stream <<
"]";
171 if (i<m.
f.
n_in()-1) stream <<
",";
175 stream <<
"@" << a.
i0 <<
" = ";
177 stream <<
"input[" << a.
i1 <<
"][" << a.
i2 <<
"]";
185 stream << casadi_math<double>::pre(a.
op);
186 for (casadi_int c=0; c<ndep; ++c) {
188 stream <<
"@" << a.
i1;
190 stream << casadi_math<double>::sep(a.
op);
191 stream <<
"@" << a.
i2;
195 stream << casadi_math<double>::post(a.
op);
203 stream <<
"Algorithm:";
223 casadi_error(
"Code generation of '" +
name_ +
"' is not possible since variables "
235 const double* w)
const {
237 stream <<
name_ <<
":" << k <<
": " <<
print(el) <<
" inputs:" << std::endl;
240 const int* dep = &el.
i1;
249 for (
size_t i = 0; i < ndeps; ++i) {
250 if (i>0) stream <<
", ";
262 for (
size_t i = 0; i < ndeps; ++i) {
284 }
else if (ndeps==2) {
305 const double* w)
const {
307 stream <<
name_ <<
":" << k <<
": " <<
print(el) <<
" outputs:" << std::endl;
310 const int* res = &el.
i0;
319 for (
size_t i = 0; i < nres; ++i) {
320 if (i>0) stream <<
", ";
332 for (
size_t i = 0; i < nres; ++i) {
351 g <<
"if (res[" << a.i0 <<
"]!=0) "
352 << g.
res(a.i0) <<
"[" << a.i2 <<
"]=" << g.
sx_work(a.i1) <<
";\n";
359 casadi_int offset = worksize;
360 for (casadi_int i=0; i<m.
f_n_in; ++i) {
362 g <<
"arg[" <<
n_in_+i <<
"] = "
368 g <<
"arg[" <<
n_in_+i <<
"]=" << 0 <<
";\n";
370 g <<
"arg[" <<
n_in_+i <<
"]=" <<
"w+" +
str(offset) <<
";\n";
377 casadi_int out_offset = offset;
380 for (casadi_int i=0; i<m.
f_n_out; ++i) {
381 g <<
"res[" <<
n_out_+i <<
"]=" <<
"w+" +
str(offset) <<
";\n";
385 for (casadi_int i=0; i<m.
f_n_in; ++i) {
387 for (casadi_int j=0; j<m.
f_nnz_in[i]; ++j) {
388 g <<
"w["+
str(k+worksize) +
"] = " << g.
sx_work(m.
dep[k]) <<
";\n";
399 g <<
"if (" << flag <<
") return 1;\n";
401 for (casadi_int i=0;i<m.
n_res;++i) {
404 g <<
"w[" +
str(i+out_offset) +
"];\n";
410 << g.
arg(a.i1) <<
"? " << g.
arg(a.i1) <<
"[" << a.i2 <<
"] : 0;\n";
423 casadi_assert_dev(ndep>0);
440 "Default input values"}},
441 {
"just_in_time_sparsity",
443 "Propagate sparsity patterns using just-in-time "
444 "compilation to a CPU or GPU using OpenCL"}},
445 {
"just_in_time_opencl",
447 "Just-in-time compilation for numeric evaluation using OpenCL (experimental)"}},
450 "Reuse variables in the work vector"}},
453 "Perform common subexpression elimination (complexity is N*log(N) in graph size)"}},
456 "Allow construction with free variables (Default: false)"}},
457 {
"allow_duplicate_io_names",
459 "Allow construction with duplicate io names (Default: false)"}},
460 {
"print_instructions",
462 "Print each operation during evaluation. Influenced by print_canonical."}}
468 if (target==
"clone") opts[
"default_in"] =
default_in_;
484 bool cse_opt =
false;
485 bool allow_free =
false;
488 for (
auto&& op : opts) {
489 if (op.first==
"default_in") {
491 }
else if (op.first==
"live_variables") {
493 }
else if (op.first==
"just_in_time_opencl") {
495 }
else if (op.first==
"just_in_time_sparsity") {
497 }
else if (op.first==
"cse") {
499 }
else if (op.first==
"allow_free") {
500 allow_free = op.second;
501 }
else if (op.first==
"print_instructions") {
515 "Option 'default_in' has incorrect length");
518 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
519 std::lock_guard<std::mutex> lock(SX::get_mutex_temp());
523 std::stack<SXNode*> s;
526 std::vector<SXNode*> nodes;
530 for (
auto it =
out_.begin(); it !=
out_.end(); ++it, ++ind) {
532 for (
auto itc = (*it)->begin(); itc != (*it)->end(); ++itc, ++nz) {
538 nodes.push_back(
static_cast<SXNode*
>(
nullptr));
542 casadi_assert(nodes.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
544 for (casadi_int i=0; i<nodes.size(); ++i) {
546 nodes[i]->temp =
static_cast<int>(i);
553 for (std::vector<SXNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
564 std::vector<std::pair<int, SXNode*> > symb_loc;
567 int curr_oind, curr_nz=0;
568 casadi_assert(
out_.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
569 for (curr_oind=0; curr_oind<
out_.size(); ++curr_oind) {
570 if (
out_[curr_oind].nnz()!=0) {
576 std::vector<casadi_int> refcount(nodes.size(), 0);
583 std::vector<int> alg_index;
584 alg_index.reserve(nodes.size());
586 for (std::vector<SXNode*>::iterator it=nodes.begin(); it!=nodes.end(); ++it) {
594 ae.
op = n==
nullptr ?
static_cast<int>(
OP_OUTPUT) :
static_cast<int>(n->
op());
607 symb_loc.push_back(std::make_pair(
algorithm_.size(), n));
613 ae.
i1 =
out_[curr_oind]->at(curr_nz)->temp;
617 casadi_assert(curr_nz < std::numeric_limits<int>::max(),
"Integer overflow");
619 if (curr_nz>=
out_[curr_oind].nnz()) {
621 casadi_assert(curr_oind < std::numeric_limits<int>::max(),
"Integer overflow");
623 for (; curr_oind<
out_.size(); ++curr_oind) {
624 if (
out_[curr_oind].nnz()!=0) {
657 for (casadi_int i=0; i<ndeps; ++i) {
665 int oind =
static_cast<OutputSX*
>(n)->oind_;
666 casadi_assert(
call_.
el.at(dep[0]).res.at(oind)==-1,
"Duplicate");
677 for (casadi_int c=0; c<ndeps; ++c) {
678 refcount.at(dep[c])++;
690 std::vector<int> place(nodes.size());
693 std::stack<int> unused;
720 for (casadi_int c=ndeps-1; c>=0; --c) {
721 casadi_int ch_ind = dep[c];
722 casadi_int remaining = --refcount.at(ch_ind);
723 if (remaining==0) unused.push(place[ch_ind]);
728 for (casadi_int c=0; c<nres; ++c) {
729 if (res[c]<0)
continue;
732 res[c] = place[res[c]] = unused.top();
736 res[c] = place[res[c]] = worksize++;
742 for (casadi_int c=0; c<ndeps; ++c) {
743 dep[c] = place[dep[c]];
757 casadi_message(
"Using live variables: work array is " +
str(
worksize_)
758 +
" instead of " +
str(nodes.size()));
760 casadi_message(
"Live variables disabled.");
773 for (casadi_int i=0; i<nodes.size(); ++i) {
780 for (
auto it=symb_loc.begin(); it!=symb_loc.end(); ++it) {
781 it->second->temp = it->first+1;
785 casadi_assert(
in_.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
786 for (
int ind=0; ind<
in_.size(); ++ind) {
788 for (
auto itc =
in_[ind]->begin(); itc !=
in_[ind]->end(); ++itc, ++nz) {
789 int i = itc->get_temp()-1;
806 for (std::vector<std::pair<int, SXNode*> >::const_iterator it=symb_loc.begin();
807 it!=symb_loc.end(); ++it) {
808 if (it->second->temp!=0) {
821 casadi_error(
name_ +
"::init: Initialization failed since variables [" +
822 join(
get_free(),
", ") +
"] are free. These symbols occur in the output expressions "
823 "but you forgot to declare these as inputs. "
824 "Set option 'allow_free' to allow free variables.");
831 casadi_error(
"OpenCL is not supported in this version of CasADi");
836 casadi_error(
"OpenCL is not supported in this version of CasADi");
856 std::vector<casadi_int> alg_i(
worksize_, -1);
872 if (arg_i[e.i1]>=0) {
881 casadi_int offset_input = 0;
882 for (casadi_int i=0; i<m.f_n_in; ++i) {
885 casadi_int offset = -1;
886 for (casadi_int j=0; j<m.f_nnz_in[i]; ++j) {
887 casadi_int k = offset_input+j;
889 arg = arg_i[m.dep[k]];
890 offset = nz_i[m.dep[k]];
892 if (arg_i[m.dep[k]]==-1) {
897 if (nz_i[m.dep[k]]!=offset+j) {
907 for (casadi_int j=0; j<m.f_nnz_in[i]; ++j) {
908 casadi_int k = offset_input+j;
909 if (arg_i[m.dep[k]]>=0) {
915 m.copy_elision_arg[i] = arg;
916 m.copy_elision_offset[i] = offset;
918 offset += m.f_nnz_in[i];
919 offset_input += m.f_nnz_in[i];
923 for (casadi_int i=0; i<m.n_res; ++i) {
925 arg_i[m.res[i]] = -1;
936 if (arg_i[e.i1]>=0) {
940 if (arg_i[e.i2]>=0) {
954 std::vector<SXElem>::iterator it=ret.begin();
957 std::vector<SXElem>::const_iterator b_it =
operations_.begin();
960 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
963 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
966 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
983 casadi_assert(it==ret.end(),
"Dimension mismatch");
989 bool always_inline,
bool never_inline)
const {
1002 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1005 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
1008 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
1011 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1015 w[a.i0] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
1018 if (res[a.i0]!=
nullptr) res[a.i0][a.i2] = w[a.i1];
1024 w[a.i0] = *p_it++;
break;
1028 const SXElem& orig = *b_it++;
1029 std::vector<SXElem> deps(m.
n_dep);
1030 bool identical =
true;
1032 std::vector<SXElem> ret;
1033 for (casadi_int i=0;i<m.
n_dep;++i) {
1039 for (casadi_int i=0;i<m.
n_dep;++i) deps[i] = w[m.
dep[i]];
1042 for (casadi_int i=0;i<m.
n_res;++i) {
1043 if (m.
res[i]>=0) w[m.
res[i]] = ret[i];
1053 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1058 const casadi_int depth = 2;
1070 bool always_inline,
bool never_inline)
const {
1075 if (!always_inline) {
1083 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
1086 "Free variables not supported in inlining call to SXFunction::eval_mx");
1089 casadi_assert(arg.size()==
n_in_,
"Wrong number of input arguments");
1090 res.resize(
out_.size());
1093 std::vector<MX> w(
sz_w());
1094 if (
verbose_) casadi_message(
"Allocated work vector");
1097 std::vector<std::vector<MX> > arg_split(
in_.size());
1098 for (casadi_int i=0; i<
in_.size(); ++i) {
1100 std::vector<MX> orig = arg[i].get_nonzeros();
1104 std::vector<MX> w(arg[i].size1());
1109 arg_split[i] = target;
1113 std::vector<std::vector<MX> > res_split(
out_.size());
1114 for (casadi_int i=0; i<
out_.size(); ++i) res_split[i].resize(
nnz_out(i));
1117 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1121 w[a.i0] = arg_split[a.i1][a.i2];
1124 res_split[a.i0][a.i2] = w[a.i1];
1127 w[a.i0] =
static_cast<double>(*c_it++);
1132 std::vector<MX> deps(m.
n_dep);
1133 std::vector<MX> args;
1137 for (casadi_int i=0;i<m.
f_n_in;++i) {
1138 std::vector<MX> arg;
1139 for (casadi_int j=0;j<m.
f_nnz_in[i];++j) {
1140 arg.push_back(w[m.
dep[k++]]);
1142 args.push_back(sparsity_cast(vertcat(arg), m.
f.
sparsity_in(i)));
1146 std::vector<MX> ret = m.
f(args);
1147 std::vector<MX> res;
1150 for (casadi_int i=0;i<m.
f_n_out;++i) {
1151 std::vector<MX> nz = ret[i].get_nonzeros();
1152 res.insert(res.end(), nz.begin(), nz.end());
1156 for (casadi_int i=0;i<m.
n_res;++i) {
1157 if (m.
res[i]>=0) w[m.
res[i]] = res[i];
1166 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1175 for (casadi_int i=0; i<res.size(); ++i) {
1176 res[i] = sparsity_cast(vertcat(res_split[i]),
sparsity_out_[i]);
1182 casadi_assert(!(always_inline && never_inline),
1184 casadi_assert(!(never_inline &&
has_free()),
1186 if (always_inline)
return true;
1187 if (never_inline)
return false;
1195 std::vector<std::vector<SX> >& fsens)
const {
1199 casadi_int nfwd = fseed.size();
1203 if (nfwd==0)
return;
1206 casadi_int npar = 1;
1207 for (
auto&& r : fseed) {
1209 casadi_assert_dev(npar==1);
1216 for (
auto it=fseed.begin(); it!=fseed.end(); ++it) {
1217 casadi_assert_dev(it->size()==
n_in_);
1218 for (casadi_int i=0; i<
n_in_; ++i) {
1221 std::vector<std::vector<SX> > fseed2(fseed);
1222 for (
auto&& r : fseed2) {
1232 for (casadi_int d=0; d<nfwd; ++d) {
1234 for (casadi_int i=0; i<fsens[d].size(); ++i)
1240 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1243 std::vector<TapeEl<SXElem> > s_pdwork(
operations_.size());
1244 std::vector<TapeEl<SXElem> >::iterator it1 = s_pdwork.begin();
1247 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1259 CASADI_MATH_DER_BUILTIN(f->
dep(0), f->
dep(1), f, it1++->d)
1271 if (
verbose_) casadi_message(
"Calculating forward derivatives");
1272 for (casadi_int dir=0; dir<nfwd; ++dir) {
1273 std::vector<TapeEl<SXElem> >::const_iterator it2 = s_pdwork.begin();
1277 w[a.i0] = fseed[dir][a.i1].nonzeros()[a.i2];
break;
1279 fsens[dir][a.i0].nonzeros()[a.i2] = w[a.i1];
break;
1289 const auto& m =
call_.
el.at(a.i1);
1290 CallSX* call_node =
static_cast<CallSX*
>(it2->d[0].get());
1296 std::vector<SXElem> deps;
1297 deps.reserve(2*m.n_dep);
1300 casadi_int offset = 0;
1301 for (casadi_int i=0;i<m.f_n_in;++i) {
1302 casadi_int nnz = ff.
nnz_in(i);
1303 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1304 for (casadi_int j=0;j<nnz;++j) {
1305 deps.push_back(call_node->
dep(offset+j));
1307 offset += m.f_nnz_in[i];
1312 for (casadi_int i=0;i<m.f_n_out;++i) {
1313 casadi_int nnz = ff.
nnz_in(i+m.f_n_in);
1314 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1315 for (casadi_int j=0;j<nnz;++j) {
1316 deps.push_back(call_node->
get_output(offset+j));
1318 offset += m.f_nnz_out[i];
1323 for (casadi_int i=0;i<m.f_n_in;++i) {
1324 casadi_int nnz = ff.
nnz_in(i+m.f_n_in+m.f_n_out);
1326 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1328 for (casadi_int j=0;j<nnz;++j) {
1329 deps.push_back(w[m.dep[offset+j]]);
1332 offset += m.f_nnz_in[i];
1341 for (casadi_int i=0;i<m.f_n_out;++i) {
1342 casadi_int nnz = ff.
nnz_out(i);
1344 casadi_assert(nnz==0 || nnz==m.f_nnz_out[i],
"Not implemented");
1346 for (casadi_int j=0;j<nnz;++j) {
1347 if (m.res[offset+j]>=0) w[m.res[offset+j]] = ret[k];
1351 offset += m.f_nnz_out[i];
1356 CASADI_MATH_BINARY_BUILTIN
1357 w[a.i0] = it2->d[0] * w[a.i1] + it2->d[1] * w[a.i2];
1361 w[a.i0] = it2->d[0] * w[a.i1];
1369 std::vector<std::vector<SX> >& asens)
const {
1373 casadi_int nadj = aseed.size();
1377 if (nadj==0)
return;
1380 casadi_int npar = 1;
1381 for (
auto&& r : aseed) {
1383 casadi_assert_dev(npar==1);
1390 bool matching_sparsity =
true;
1391 for (casadi_int d=0; d<nadj; ++d) {
1392 casadi_assert_dev(aseed[d].size()==
n_out_);
1393 for (casadi_int i=0; matching_sparsity && i<
n_out_; ++i)
1394 matching_sparsity = aseed[d][i].sparsity()==
sparsity_out_[i];
1398 if (!matching_sparsity) {
1399 std::vector<std::vector<SX> > aseed2(aseed);
1400 for (casadi_int d=0; d<nadj; ++d)
1401 for (casadi_int i=0; i<
n_out_; ++i)
1409 for (casadi_int d=0; d<nadj; ++d) {
1410 asens[d].resize(
n_in_);
1411 for (casadi_int i=0; i<asens[d].size(); ++i) {
1415 std::fill(asens[d][i]->begin(), asens[d][i]->end(), 0);
1421 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1424 std::vector<TapeEl<SXElem> > s_pdwork(
operations_.size());
1425 std::vector<TapeEl<SXElem> >::iterator it1 = s_pdwork.begin();
1428 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1440 CASADI_MATH_DER_BUILTIN(f->
dep(0), f->
dep(1), f, it1++->d)
1449 if (
verbose_) casadi_message(
"Calculating adjoint derivatives");
1454 for (casadi_int dir=0; dir<nadj; ++dir) {
1455 auto it2 = s_pdwork.rbegin();
1460 asens[dir][it->i1].nonzeros()[it->i2] = w[it->i0];
1464 w[it->i1] += aseed[dir][it->i0].nonzeros()[it->i2];
1477 const auto& m =
call_.
el.at(it->i1);
1478 CallSX* call_node =
static_cast<CallSX*
>(it2->d[0].get());
1484 std::vector<SXElem> deps;
1485 deps.reserve(m.n_dep+m.n_res);
1488 casadi_int offset = 0;
1489 for (casadi_int i=0;i<m.f_n_in;++i) {
1490 casadi_int nnz = fr.
nnz_in(i);
1491 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1492 for (casadi_int j=0;j<nnz;++j) {
1493 deps.push_back(call_node->
dep(offset+j));
1495 offset += m.f_nnz_in[i];
1500 for (casadi_int i=0;i<m.f_n_out;++i) {
1501 casadi_int nnz = fr.
nnz_in(i+m.f_n_in);
1502 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1503 for (casadi_int j=0;j<nnz;++j) {
1504 deps.push_back(call_node->
get_output(offset+j));
1506 offset += m.f_nnz_out[i];
1511 for (casadi_int i=0;i<m.f_n_out;++i) {
1512 casadi_int nnz = fr.
nnz_in(i+m.f_n_in+m.f_n_out);
1514 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1516 for (casadi_int j=0;j<nnz;++j) {
1517 deps.push_back((m.res[offset+j]>=0) ? w[m.res[offset+j]] : 0);
1520 offset += m.f.nnz_out(i);
1527 for (casadi_int i=0;i<m.n_res;++i) {
1528 if (m.res[i]>=0) w[m.res[i]] = 0;
1534 for (casadi_int i=0;i<m.f_n_in;++i) {
1535 casadi_int nnz = fr.
nnz_out(i);
1537 casadi_assert(nnz==0 || nnz==m.f_nnz_in[i],
"Not implemented");
1539 for (casadi_int j=0;j<nnz;++j) {
1540 w[m.dep[offset+j]] += ret[k++];
1543 offset += m.f_nnz_in[i];
1548 CASADI_MATH_BINARY_BUILTIN
1551 w[it->i1] += it2->d[0] * seed;
1552 w[it->i2] += it2++->d[1] * seed;
1557 w[it->i1] += it2++->d[0] * seed;
1563 for (casadi_int d=0; d<nadj; ++d) {
1564 for (casadi_int i=0; i<
n_in_; ++i) {
1565 SX& a = asens[d][i];
1571 template<
typename T,
typename CT>
1573 CT*** call_arg, T*** call_res, casadi_int** call_iw, T** call_w, T**
nz_in, T**
nz_out)
const {
1582 for (casadi_int i=0;i<m.
f_n_in;++i) {
1583 (*call_arg)[i] = ptr_w;
1589 for (casadi_int i=0;i<m.
f_n_out;++i) {
1590 (*call_res)[i] = ptr_w;
1595 template<
typename T>
1598 const T** call_arg = arg;
1600 casadi_int* call_iw = iw;
1608 for (casadi_int i=0;i<m.n_dep;++i) {
1609 nz_in[i] = w[m.dep[i]];
1612 m.f(call_arg, call_res, call_iw, call_w);
1615 for (casadi_int i=0;i<m.n_res;++i) {
1624 template<
typename T>
1629 casadi_int* call_iw = iw;
1636 std::fill_n(
nz_in, m.n_dep, 0);
1639 for (casadi_int i=0;i<m.n_res;++i) {
1640 nz_out[i] = (m.res[i]>=0) ? w[m.res[i]] : 0;
1644 m.f.rev(call_arg, call_res, call_iw, call_w);
1647 for (casadi_int i=0;i<m.n_res;++i) {
1648 if (m.res[i]>=0) w[m.res[i]] = 0;
1652 for (casadi_int i=0;i<m.n_dep;++i) {
1653 w[m.dep[i]] |=
nz_in[i];
1669 w[e.i0] = (arg[e.i1]!=
nullptr &&
is_diff_in_[e.i1]) ? arg[e.i1][e.i2] : 0;
1672 if (res[e.i0]!=
nullptr) res[e.i0][e.i2] =
is_diff_out_[e.i0] ? w[e.i1] : 0;
1678 w[e.i0] = w[e.i1] | w[e.i2];
break;
1686 const bvec_t nz = ~static_cast<bvec_t>(0);
1691 w[e.i0] = (e.d!=0) ? nz : 0;
break;
1693 w[e.i0] = nz;
break;
1695 w[e.i0] = (arg[e.i1]!=
nullptr) ? arg[e.i1][e.i2] : 0;
1698 if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
1706 w[e.i0] = w[e.i1] ? nz : (operation_checker<F0XChecker>(e.op) ? 0 : nz);
1708 const bool z0 = w[e.i1]!=0, z1 = w[e.i2]!=0;
1709 if (!z0 && !z1) w[e.i0] = operation_checker<F00Checker>(e.op) ? 0 : nz;
1710 else if (!z0 && z1) w[e.i0] = operation_checker<F0XChecker>(e.op) ? 0 : nz;
1711 else if ( z0 && !z1) w[e.i0] = operation_checker<FX0Checker>(e.op) ? 0 : nz;
1721 casadi_int* iw,
bvec_t* w)
const {
1723 const bvec_t** call_arg = arg;
1725 casadi_int* call_iw = iw;
1733 for (casadi_int i=0; i<m.n_dep; ++i)
nz_in[i] = w[m.dep[i]];
1735 m.f.eval_activity(call_arg, call_res, call_iw, call_w);
1737 for (casadi_int i=0; i<m.n_res; ++i) {
1738 if (m.res[i]>=0) w[m.res[i]] =
nz_out[i];
1743 casadi_int* iw,
bvec_t* w,
void* mem)
const {
1747 std::fill_n(w,
sz_w(), 0);
1762 arg[it->i1][it->i2] |= w[it->i0];
1767 w[it->i1] |= res[it->i0][it->i2];
1768 res[it->i0][it->i2] = 0;
1793 std::map<std::string, bool> flagged;
1796 const auto& m =
call_.
el.at(a.i1);
1798 if (flagged.find(f.
name())==flagged.end()) {
1799 flagged[f.
name()] =
true;
1803 std::vector<std::string> ret;
1804 for (
auto it : flagged) {
1805 ret.push_back(it.first);
1813 const auto& m =
call_.
el.at(a.i1);
1815 if (name==f.
name())
return f;
1818 casadi_error(
"No such function '" + name +
"'.");
1827 std::ostream &ss,
const Dict& options)
const {
1830 casadi_int indent_level = 0;
1833 for (
auto&& op : options) {
1834 if (op.first==
"indent_level") {
1835 indent_level = op.second;
1837 casadi_error(
"Unknown option '" + op.first +
"'.");
1843 for (casadi_int i=0;i<indent_level;++i) {
1848 for (casadi_int i=0;i<
n_in_;++i) {
1849 ss << indent <<
"argin_" << i <<
" = nonzeros_gen(varargin{" << i+1 <<
"});" << std::endl;
1852 Function f = shared_from_this<Function>();
1864 ss << indent <<
"w" << o[0] <<
" = " <<
"argin_" << i[0] <<
"(" << i[1]+1 <<
");";
1870 ss << indent <<
"argout_" << o[0] <<
"{" << o[1]+1 <<
"} = w" << i[0] <<
";";
1876 std::ios_base::fmtflags fmtfl = ss.flags();
1877 ss << indent <<
"w" << o[0] <<
" = ";
1878 ss << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1);
1885 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
"^2;" << std::endl;
1890 ss << indent <<
"w" << o[0] <<
" = abs(" <<
"w" << i[0] <<
");" << std::endl;
1895 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".^w" << i[1] <<
";" << std::endl;
1898 ss << indent <<
"w" << o[0] <<
" = ~" <<
"w" << i[0] <<
";" << std::endl;
1901 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" | w" << i[1] <<
";" << std::endl;
1904 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" & w" << i[1] <<
";" << std::endl;
1907 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" ~= w" << i[1] <<
";" << std::endl;
1910 ss << indent <<
"w" << o[0] <<
" = ";
1911 ss <<
"if_else_zero_gen(w" << i[0] <<
", w" << i[1] <<
");" << std::endl;
1916 "w"+std::to_string(i[0]),
"w"+std::to_string(i[1])) <<
";" << std::endl;
1919 "w"+std::to_string(i[0])) <<
";" << std::endl;
1928 int version = s.
version(
"SXFunction", 1, 3);
1948 s.
unpack(
"SXFunction::call_el_size", el_size);
1952 for (casadi_int k=0;k<el_size;++k) {
1954 s.
unpack(
"SXFunction::call_el_f", f);
1957 s.
unpack(
"SXFunction::call_el_dep", e.dep);
1958 s.
unpack(
"SXFunction::call_el_res", e.res);
1959 s.
unpack(
"SXFunction::call_el_copy_elision_arg", e.copy_elision_arg);
1960 s.
unpack(
"SXFunction::call_el_copy_elision_offset", e.copy_elision_offset);
1979 s.
unpack(
"SXFunction::ScalarAtomic::op", e.
op);
1980 s.
unpack(
"SXFunction::ScalarAtomic::i0", e.
i0);
1981 s.
unpack(
"SXFunction::ScalarAtomic::i1", e.
i1);
1982 s.
unpack(
"SXFunction::ScalarAtomic::i2", e.
i2);
2017 s.
pack(
"SXFunction::call_el_size",
call_.
el.size());
2019 for (
const auto& n :
call_.
el) {
2020 s.
pack(
"SXFunction::call_el_f", n.f);
2021 s.
pack(
"SXFunction::call_el_dep", n.dep);
2022 s.
pack(
"SXFunction::call_el_res", n.res);
2023 s.
pack(
"SXFunction::call_el_copy_elision_arg", n.copy_elision_arg);
2024 s.
pack(
"SXFunction::call_el_copy_elision_offset", n.copy_elision_offset);
2031 s.
pack(
"SXFunction::ScalarAtomic::op", e.op);
2032 s.
pack(
"SXFunction::ScalarAtomic::i0", e.i0);
2033 s.
pack(
"SXFunction::ScalarAtomic::i1", e.i1);
2034 s.
pack(
"SXFunction::ScalarAtomic::i2", e.i2);
2048 casadi_int max_depth)
const {
2061 if (option_name ==
"print_instructions") {
2070 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
2071 std::lock_guard<std::mutex> lock(SX::get_mutex_temp());
2074 std::stack<SXNode*> s;
2077 std::vector<SXNode*> nodes;
2081 for (
auto it = expr.begin(); it != expr.end(); ++it, ++ind) {
2083 for (
auto itc = (*it)->begin(); itc != (*it)->end(); ++itc, ++nz) {
2091 for (casadi_int i=0; i<nodes.size(); ++i) {
2095 std::vector<SX> ret(nodes.size());
2096 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 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.
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_
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.
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.
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 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.
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.