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."}}
483 bool cse_opt =
false;
484 bool allow_free =
false;
487 for (
auto&& op : opts) {
488 if (op.first==
"default_in") {
490 }
else if (op.first==
"live_variables") {
492 }
else if (op.first==
"just_in_time_opencl") {
494 }
else if (op.first==
"just_in_time_sparsity") {
496 }
else if (op.first==
"cse") {
498 }
else if (op.first==
"allow_free") {
499 allow_free = op.second;
500 }
else if (op.first==
"print_instructions") {
514 "Option 'default_in' has incorrect length");
517 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
518 std::lock_guard<std::mutex> lock(SX::get_mutex_temp());
522 std::stack<SXNode*> s;
525 std::vector<SXNode*> nodes;
529 for (
auto it =
out_.begin(); it !=
out_.end(); ++it, ++ind) {
531 for (
auto itc = (*it)->begin(); itc != (*it)->end(); ++itc, ++nz) {
537 nodes.push_back(
static_cast<SXNode*
>(
nullptr));
541 casadi_assert(nodes.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
543 for (casadi_int i=0; i<nodes.size(); ++i) {
545 nodes[i]->temp =
static_cast<int>(i);
552 for (std::vector<SXNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
563 std::vector<std::pair<int, SXNode*> > symb_loc;
566 int curr_oind, curr_nz=0;
567 casadi_assert(
out_.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
568 for (curr_oind=0; curr_oind<
out_.size(); ++curr_oind) {
569 if (
out_[curr_oind].nnz()!=0) {
575 std::vector<casadi_int> refcount(nodes.size(), 0);
582 std::vector<int> alg_index;
583 alg_index.reserve(nodes.size());
585 for (std::vector<SXNode*>::iterator it=nodes.begin(); it!=nodes.end(); ++it) {
593 ae.
op = n==
nullptr ?
static_cast<int>(
OP_OUTPUT) :
static_cast<int>(n->
op());
606 symb_loc.push_back(std::make_pair(
algorithm_.size(), n));
612 ae.
i1 =
out_[curr_oind]->at(curr_nz)->temp;
616 casadi_assert(curr_nz < std::numeric_limits<int>::max(),
"Integer overflow");
618 if (curr_nz>=
out_[curr_oind].nnz()) {
620 casadi_assert(curr_oind < std::numeric_limits<int>::max(),
"Integer overflow");
622 for (; curr_oind<
out_.size(); ++curr_oind) {
623 if (
out_[curr_oind].nnz()!=0) {
656 for (casadi_int i=0; i<ndeps; ++i) {
664 int oind =
static_cast<OutputSX*
>(n)->oind_;
665 casadi_assert(
call_.
el.at(dep[0]).res.at(oind)==-1,
"Duplicate");
676 for (casadi_int c=0; c<ndeps; ++c) {
677 refcount.at(dep[c])++;
689 std::vector<int> place(nodes.size());
692 std::stack<int> unused;
719 for (casadi_int c=ndeps-1; c>=0; --c) {
720 casadi_int ch_ind = dep[c];
721 casadi_int remaining = --refcount.at(ch_ind);
722 if (remaining==0) unused.push(place[ch_ind]);
727 for (casadi_int c=0; c<nres; ++c) {
728 if (res[c]<0)
continue;
731 res[c] = place[res[c]] = unused.top();
735 res[c] = place[res[c]] = worksize++;
741 for (casadi_int c=0; c<ndeps; ++c) {
742 dep[c] = place[dep[c]];
756 casadi_message(
"Using live variables: work array is " +
str(
worksize_)
757 +
" instead of " +
str(nodes.size()));
759 casadi_message(
"Live variables disabled.");
772 for (casadi_int i=0; i<nodes.size(); ++i) {
779 for (
auto it=symb_loc.begin(); it!=symb_loc.end(); ++it) {
780 it->second->temp = it->first+1;
784 casadi_assert(
in_.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
785 for (
int ind=0; ind<
in_.size(); ++ind) {
787 for (
auto itc =
in_[ind]->begin(); itc !=
in_[ind]->end(); ++itc, ++nz) {
788 int i = itc->get_temp()-1;
805 for (std::vector<std::pair<int, SXNode*> >::const_iterator it=symb_loc.begin();
806 it!=symb_loc.end(); ++it) {
807 if (it->second->temp!=0) {
820 casadi_error(
name_ +
"::init: Initialization failed since variables [" +
821 join(
get_free(),
", ") +
"] are free. These symbols occur in the output expressions "
822 "but you forgot to declare these as inputs. "
823 "Set option 'allow_free' to allow free variables.");
830 casadi_error(
"OpenCL is not supported in this version of CasADi");
835 casadi_error(
"OpenCL is not supported in this version of CasADi");
855 std::vector<casadi_int> alg_i(
worksize_, -1);
871 if (arg_i[e.i1]>=0) {
880 casadi_int offset_input = 0;
881 for (casadi_int i=0; i<m.f_n_in; ++i) {
884 casadi_int offset = -1;
885 for (casadi_int j=0; j<m.f_nnz_in[i]; ++j) {
886 casadi_int k = offset_input+j;
888 arg = arg_i[m.dep[k]];
889 offset = nz_i[m.dep[k]];
891 if (arg_i[m.dep[k]]==-1) {
896 if (nz_i[m.dep[k]]!=offset+j) {
906 for (casadi_int j=0; j<m.f_nnz_in[i]; ++j) {
907 casadi_int k = offset_input+j;
908 if (arg_i[m.dep[k]]>=0) {
914 m.copy_elision_arg[i] = arg;
915 m.copy_elision_offset[i] = offset;
917 offset += m.f_nnz_in[i];
918 offset_input += m.f_nnz_in[i];
922 for (casadi_int i=0; i<m.n_res; ++i) {
924 arg_i[m.res[i]] = -1;
935 if (arg_i[e.i1]>=0) {
939 if (arg_i[e.i2]>=0) {
953 std::vector<SXElem>::iterator it=ret.begin();
956 std::vector<SXElem>::const_iterator b_it =
operations_.begin();
959 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
962 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
965 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
982 casadi_assert(it==ret.end(),
"Dimension mismatch");
988 bool always_inline,
bool never_inline)
const {
1001 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1004 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
1007 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
1010 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1014 w[a.i0] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
1017 if (res[a.i0]!=
nullptr) res[a.i0][a.i2] = w[a.i1];
1023 w[a.i0] = *p_it++;
break;
1027 const SXElem& orig = *b_it++;
1028 std::vector<SXElem> deps(m.
n_dep);
1029 bool identical =
true;
1031 std::vector<SXElem> ret;
1032 for (casadi_int i=0;i<m.
n_dep;++i) {
1038 for (casadi_int i=0;i<m.
n_dep;++i) deps[i] = w[m.
dep[i]];
1041 for (casadi_int i=0;i<m.
n_res;++i) {
1042 if (m.
res[i]>=0) w[m.
res[i]] = ret[i];
1052 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1057 const casadi_int depth = 2;
1069 bool always_inline,
bool never_inline)
const {
1074 if (!always_inline) {
1081 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
1084 "Free variables not supported in inlining call to SXFunction::eval_mx");
1087 casadi_assert(arg.size()==
n_in_,
"Wrong number of input arguments");
1088 res.resize(
out_.size());
1091 std::vector<MX> w(
sz_w());
1092 if (
verbose_) casadi_message(
"Allocated work vector");
1095 std::vector<std::vector<MX> > arg_split(
in_.size());
1096 for (casadi_int i=0; i<
in_.size(); ++i) {
1098 std::vector<MX> orig = arg[i].get_nonzeros();
1102 std::vector<MX> w(arg[i].size1());
1107 arg_split[i] = target;
1111 std::vector<std::vector<MX> > res_split(
out_.size());
1112 for (casadi_int i=0; i<
out_.size(); ++i) res_split[i].resize(
nnz_out(i));
1115 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1119 w[a.i0] = arg_split[a.i1][a.i2];
1122 res_split[a.i0][a.i2] = w[a.i1];
1125 w[a.i0] =
static_cast<double>(*c_it++);
1130 std::vector<MX> deps(m.
n_dep);
1131 std::vector<MX> args;
1135 for (casadi_int i=0;i<m.
f_n_in;++i) {
1136 std::vector<MX> arg;
1137 for (casadi_int j=0;j<m.
f_nnz_in[i];++j) {
1138 arg.push_back(w[m.
dep[k++]]);
1140 args.push_back(sparsity_cast(vertcat(arg), m.
f.
sparsity_in(i)));
1144 std::vector<MX> ret = m.
f(args);
1145 std::vector<MX> res;
1148 for (casadi_int i=0;i<m.
f_n_out;++i) {
1149 std::vector<MX> nz = ret[i].get_nonzeros();
1150 res.insert(res.end(), nz.begin(), nz.end());
1154 for (casadi_int i=0;i<m.
n_res;++i) {
1155 if (m.
res[i]>=0) w[m.
res[i]] = res[i];
1164 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1173 for (casadi_int i=0; i<res.size(); ++i) {
1174 res[i] = sparsity_cast(vertcat(res_split[i]),
sparsity_out_[i]);
1180 casadi_assert(!(always_inline && never_inline),
1182 casadi_assert(!(never_inline &&
has_free()),
1184 if (always_inline)
return true;
1185 if (never_inline)
return false;
1193 std::vector<std::vector<SX> >& fsens)
const {
1197 casadi_int nfwd = fseed.size();
1201 if (nfwd==0)
return;
1204 casadi_int npar = 1;
1205 for (
auto&& r : fseed) {
1207 casadi_assert_dev(npar==1);
1213 for (
auto it=fseed.begin(); it!=fseed.end(); ++it) {
1214 casadi_assert_dev(it->size()==
n_in_);
1215 for (casadi_int i=0; i<
n_in_; ++i) {
1218 std::vector<std::vector<SX> > fseed2(fseed);
1219 for (
auto&& r : fseed2) {
1228 for (casadi_int d=0; d<nfwd; ++d) {
1230 for (casadi_int i=0; i<fsens[d].size(); ++i)
1236 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1239 std::vector<TapeEl<SXElem> > s_pdwork(
operations_.size());
1240 std::vector<TapeEl<SXElem> >::iterator it1 = s_pdwork.begin();
1243 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1255 CASADI_MATH_DER_BUILTIN(f->
dep(0), f->
dep(1), f, it1++->d)
1267 if (
verbose_) casadi_message(
"Calculating forward derivatives");
1268 for (casadi_int dir=0; dir<nfwd; ++dir) {
1269 std::vector<TapeEl<SXElem> >::const_iterator it2 = s_pdwork.begin();
1273 w[a.i0] = fseed[dir][a.i1].nonzeros()[a.i2];
break;
1275 fsens[dir][a.i0].nonzeros()[a.i2] = w[a.i1];
break;
1286 CallSX* call_node =
static_cast<CallSX*
>(it2->d[0].get());
1292 std::vector<SXElem> deps;
1293 deps.reserve(2*m.n_dep);
1296 casadi_int offset = 0;
1297 for (casadi_int i=0;i<m.f_n_in;++i) {
1298 casadi_int nnz = ff.
nnz_in(i);
1299 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1300 for (casadi_int j=0;j<nnz;++j) {
1301 deps.push_back(call_node->
dep(offset+j));
1303 offset += m.f_nnz_in[i];
1308 for (casadi_int i=0;i<m.f_n_out;++i) {
1309 casadi_int nnz = ff.
nnz_in(i+m.f_n_in);
1310 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1311 for (casadi_int j=0;j<nnz;++j) {
1312 deps.push_back(call_node->
get_output(offset+j));
1314 offset += m.f_nnz_out[i];
1319 for (casadi_int i=0;i<m.f_n_in;++i) {
1320 casadi_int nnz = ff.
nnz_in(i+m.f_n_in+m.f_n_out);
1322 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1324 for (casadi_int j=0;j<nnz;++j) {
1325 deps.push_back(w[m.dep[offset+j]]);
1328 offset += m.f_nnz_in[i];
1337 for (casadi_int i=0;i<m.f_n_out;++i) {
1338 casadi_int nnz = ff.
nnz_out(i);
1340 casadi_assert(nnz==0 || nnz==m.f_nnz_out[i],
"Not implemented");
1342 for (casadi_int j=0;j<nnz;++j) {
1343 if (m.res[offset+j]>=0) w[m.res[offset+j]] = ret[k];
1347 offset += m.f_nnz_out[i];
1352 CASADI_MATH_BINARY_BUILTIN
1353 w[a.i0] = it2->d[0] * w[a.i1] + it2->d[1] * w[a.i2];
1357 w[a.i0] = it2->d[0] * w[a.i1];
1365 std::vector<std::vector<SX> >& asens)
const {
1369 casadi_int nadj = aseed.size();
1373 if (nadj==0)
return;
1376 casadi_int npar = 1;
1377 for (
auto&& r : aseed) {
1379 casadi_assert_dev(npar==1);
1385 bool matching_sparsity =
true;
1386 for (casadi_int d=0; d<nadj; ++d) {
1387 casadi_assert_dev(aseed[d].size()==
n_out_);
1388 for (casadi_int i=0; matching_sparsity && i<
n_out_; ++i)
1389 matching_sparsity = aseed[d][i].sparsity()==
sparsity_out_[i];
1393 if (!matching_sparsity) {
1394 std::vector<std::vector<SX> > aseed2(aseed);
1395 for (casadi_int d=0; d<nadj; ++d)
1396 for (casadi_int i=0; i<
n_out_; ++i)
1403 for (casadi_int d=0; d<nadj; ++d) {
1404 asens[d].resize(
n_in_);
1405 for (casadi_int i=0; i<asens[d].size(); ++i) {
1409 std::fill(asens[d][i]->begin(), asens[d][i]->end(), 0);
1415 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1418 std::vector<TapeEl<SXElem> > s_pdwork(
operations_.size());
1419 std::vector<TapeEl<SXElem> >::iterator it1 = s_pdwork.begin();
1422 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1434 CASADI_MATH_DER_BUILTIN(f->
dep(0), f->
dep(1), f, it1++->d)
1443 if (
verbose_) casadi_message(
"Calculating adjoint derivatives");
1448 for (casadi_int dir=0; dir<nadj; ++dir) {
1449 auto it2 = s_pdwork.rbegin();
1454 asens[dir][it->i1].nonzeros()[it->i2] = w[it->i0];
1458 w[it->i1] += aseed[dir][it->i0].nonzeros()[it->i2];
1471 auto& m =
call_.
el.at(it->i1);
1472 CallSX* call_node =
static_cast<CallSX*
>(it2->d[0].get());
1478 std::vector<SXElem> deps;
1479 deps.reserve(m.n_dep+m.n_res);
1482 casadi_int offset = 0;
1483 for (casadi_int i=0;i<m.f_n_in;++i) {
1484 casadi_int nnz = fr.
nnz_in(i);
1485 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1486 for (casadi_int j=0;j<nnz;++j) {
1487 deps.push_back(call_node->
dep(offset+j));
1489 offset += m.f_nnz_in[i];
1494 for (casadi_int i=0;i<m.f_n_out;++i) {
1495 casadi_int nnz = fr.
nnz_in(i+m.f_n_in);
1496 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1497 for (casadi_int j=0;j<nnz;++j) {
1498 deps.push_back(call_node->
get_output(offset+j));
1500 offset += m.f_nnz_out[i];
1505 for (casadi_int i=0;i<m.f_n_out;++i) {
1506 casadi_int nnz = fr.
nnz_in(i+m.f_n_in+m.f_n_out);
1508 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1510 for (casadi_int j=0;j<nnz;++j) {
1511 deps.push_back((m.res[offset+j]>=0) ? w[m.res[offset+j]] : 0);
1514 offset += m.f.nnz_out(i);
1521 for (casadi_int i=0;i<m.n_res;++i) {
1522 if (m.res[i]>=0) w[m.res[i]] = 0;
1528 for (casadi_int i=0;i<m.f_n_in;++i) {
1529 casadi_int nnz = fr.
nnz_out(i);
1531 casadi_assert(nnz==0 || nnz==m.f_nnz_in[i],
"Not implemented");
1533 for (casadi_int j=0;j<nnz;++j) {
1534 w[m.dep[offset+j]] += ret[k++];
1537 offset += m.f_nnz_in[i];
1542 CASADI_MATH_BINARY_BUILTIN
1545 w[it->i1] += it2->d[0] * seed;
1546 w[it->i2] += it2++->d[1] * seed;
1551 w[it->i1] += it2++->d[0] * seed;
1557 template<
typename T,
typename CT>
1559 CT*** call_arg, T*** call_res, casadi_int** call_iw, T** call_w, T**
nz_in, T**
nz_out)
const {
1568 for (casadi_int i=0;i<m.
f_n_in;++i) {
1569 (*call_arg)[i] = ptr_w;
1575 for (casadi_int i=0;i<m.
f_n_out;++i) {
1576 (*call_res)[i] = ptr_w;
1581 template<
typename T>
1584 const T** call_arg = arg;
1586 casadi_int* call_iw = iw;
1594 for (casadi_int i=0;i<m.n_dep;++i) {
1595 nz_in[i] = w[m.dep[i]];
1598 m.f(call_arg, call_res, call_iw, call_w);
1601 for (casadi_int i=0;i<m.n_res;++i) {
1610 template<
typename T>
1615 casadi_int* call_iw = iw;
1622 std::fill_n(
nz_in, m.n_dep, 0);
1625 for (casadi_int i=0;i<m.n_res;++i) {
1626 nz_out[i] = (m.res[i]>=0) ? w[m.res[i]] : 0;
1630 m.f.rev(call_arg, call_res, call_iw, call_w);
1633 for (casadi_int i=0;i<m.n_res;++i) {
1634 if (m.res[i]>=0) w[m.res[i]] = 0;
1638 for (casadi_int i=0;i<m.n_dep;++i) {
1639 w[m.dep[i]] |=
nz_in[i];
1655 w[e.i0] = arg[e.i1]==
nullptr ? 0 : arg[e.i1][e.i2];
1658 if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
1664 w[e.i0] = w[e.i1] | w[e.i2];
break;
1671 casadi_int* iw,
bvec_t* w,
void* mem)
const {
1675 std::fill_n(w,
sz_w(), 0);
1689 if (arg[it->i1]!=
nullptr) arg[it->i1][it->i2] |= w[it->i0];
1693 if (res[it->i0]!=
nullptr) {
1694 w[it->i1] |= res[it->i0][it->i2];
1695 res[it->i0][it->i2] = 0;
1725 std::ostream &ss,
const Dict& options)
const {
1728 casadi_int indent_level = 0;
1731 for (
auto&& op : options) {
1732 if (op.first==
"indent_level") {
1733 indent_level = op.second;
1735 casadi_error(
"Unknown option '" + op.first +
"'.");
1741 for (casadi_int i=0;i<indent_level;++i) {
1746 for (casadi_int i=0;i<
n_in_;++i) {
1747 ss << indent <<
"argin_" << i <<
" = nonzeros_gen(varargin{" << i+1 <<
"});" << std::endl;
1750 Function f = shared_from_this<Function>();
1762 ss << indent <<
"w" << o[0] <<
" = " <<
"argin_" << i[0] <<
"(" << i[1]+1 <<
");";
1768 ss << indent <<
"argout_" << o[0] <<
"{" << o[1]+1 <<
"} = w" << i[0] <<
";";
1774 std::ios_base::fmtflags fmtfl = ss.flags();
1775 ss << indent <<
"w" << o[0] <<
" = ";
1776 ss << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1);
1783 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
"^2;" << std::endl;
1788 ss << indent <<
"w" << o[0] <<
" = abs(" <<
"w" << i[0] <<
");" << std::endl;
1793 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".^w" << i[1] <<
";" << std::endl;
1796 ss << indent <<
"w" << o[0] <<
" = ~" <<
"w" << i[0] <<
";" << std::endl;
1799 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" | w" << i[1] <<
";" << std::endl;
1802 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" & w" << i[1] <<
";" << std::endl;
1805 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" ~= w" << i[1] <<
";" << std::endl;
1808 ss << indent <<
"w" << o[0] <<
" = ";
1809 ss <<
"if_else_zero_gen(w" << i[0] <<
", w" << i[1] <<
");" << std::endl;
1814 "w"+std::to_string(i[0]),
"w"+std::to_string(i[1])) <<
";" << std::endl;
1817 "w"+std::to_string(i[0])) <<
";" << std::endl;
1826 int version = s.
version(
"SXFunction", 1, 3);
1846 s.
unpack(
"SXFunction::call_el_size", el_size);
1850 for (casadi_int k=0;k<el_size;++k) {
1852 s.
unpack(
"SXFunction::call_el_f", f);
1855 s.
unpack(
"SXFunction::call_el_dep", e.dep);
1856 s.
unpack(
"SXFunction::call_el_res", e.res);
1857 s.
unpack(
"SXFunction::call_el_copy_elision_arg", e.copy_elision_arg);
1858 s.
unpack(
"SXFunction::call_el_copy_elision_offset", e.copy_elision_offset);
1877 s.
unpack(
"SXFunction::ScalarAtomic::op", e.
op);
1878 s.
unpack(
"SXFunction::ScalarAtomic::i0", e.
i0);
1879 s.
unpack(
"SXFunction::ScalarAtomic::i1", e.
i1);
1880 s.
unpack(
"SXFunction::ScalarAtomic::i2", e.
i2);
1915 s.
pack(
"SXFunction::call_el_size",
call_.
el.size());
1917 for (
const auto& n :
call_.
el) {
1918 s.
pack(
"SXFunction::call_el_f", n.f);
1919 s.
pack(
"SXFunction::call_el_dep", n.dep);
1920 s.
pack(
"SXFunction::call_el_res", n.res);
1921 s.
pack(
"SXFunction::call_el_copy_elision_arg", n.copy_elision_arg);
1922 s.
pack(
"SXFunction::call_el_copy_elision_offset", n.copy_elision_offset);
1929 s.
pack(
"SXFunction::ScalarAtomic::op", e.op);
1930 s.
pack(
"SXFunction::ScalarAtomic::i0", e.i0);
1931 s.
pack(
"SXFunction::ScalarAtomic::i1", e.i1);
1932 s.
pack(
"SXFunction::ScalarAtomic::i2", e.i2);
1946 casadi_int max_depth)
const {
1956 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
1957 std::lock_guard<std::mutex> lock(SX::get_mutex_temp());
1960 std::stack<SXNode*> s;
1963 std::vector<SXNode*> nodes;
1967 for (
auto it = expr.begin(); it != expr.end(); ++it, ++ind) {
1969 for (
auto itc = (*it)->begin(); itc != (*it)->end(); ++itc, ++nz) {
1977 for (casadi_int i=0; i<nodes.size(); ++i) {
1981 std::vector<SX> ret(nodes.size());
1982 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)
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.
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.
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.
Dict generate_options(const std::string &target) const override
Reconstruct options dict.
void add_embedded(std::map< FunctionInternal *, Function > &all_fun, const Function &dep, casadi_int max_depth) const
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)
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.
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.
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 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.
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.
void call_fwd(const AlgEl &e, const T **arg, T **res, casadi_int *iw, T *w) const
void find(std::map< FunctionInternal *, Function > &all_fun, casadi_int max_depth) const override
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 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 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.