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)
72 casadi_int* iw,
double* w,
void* mem)
const {
74 setup(mem, arg, res, iw, w);
80 casadi_error(
"Cannot evaluate \"" + ss.str() +
"\" since variables "
91 CASADI_MATH_FUN_BUILTIN(w[e.i1], w[e.i2], w[e.i0])
94 case OP_INPUT: w[e.i0] = arg[e.i1]==
nullptr ? 0 : arg[e.i1][e.i2];
break;
95 case OP_OUTPUT:
if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
break;
100 casadi_error(
"Unknown operation" +
str(e.op));
109 if (!operation_checker<SmoothChecker>(a.op)) {
117 stream <<
"Algorithm:";
120 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
127 stream <<
"output[" << a.i0 <<
"][" << a.i2 <<
"] = @" << a.i1;
132 for (casadi_int i=0; i<m.
f.
n_out(); ++i) {
133 if (m.
f.
nnz_out(i)>1) stream <<
"[";
134 for (casadi_int j=0; j<m.
f.
nnz_out(i); ++j) {
141 if (j<m.
f.
nnz_out(i)-1) stream <<
",";
143 if (m.
f.
nnz_out(i)>1) stream <<
"]";
144 if (i<m.
f.
n_out()-1) stream <<
",";
147 stream << m.
f.
name() <<
"(";
149 for (casadi_int i=0; i<m.
f.
n_in(); ++i) {
150 if (m.
f.
nnz_in(i)==0) stream <<
"0x0";
151 if (m.
f.
nnz_in(i)>1) stream <<
"[";
152 for (casadi_int j=0; j<m.
f.
nnz_in(i); ++j) {
153 stream <<
"@" << m.
dep[k++];
154 if (j<m.
f.
nnz_in(i)-1) stream <<
",";
156 if (m.
f.
nnz_in(i)>1) stream <<
"]";
157 if (i<m.
f.
n_in()-1) stream <<
",";
161 stream <<
"@" << a.i0 <<
" = ";
163 stream <<
"input[" << a.i1 <<
"][" << a.i2 <<
"]";
171 stream << casadi_math<double>::pre(a.op);
172 for (casadi_int c=0; c<ndep; ++c) {
174 stream <<
"@" << a.i1;
176 stream << casadi_math<double>::sep(a.op);
177 stream <<
"@" << a.i2;
181 stream << casadi_math<double>::post(a.op);
198 casadi_error(
"Code generation of '" +
name_ +
"' is not possible since variables "
215 g <<
"if (res[" << a.i0 <<
"]!=0) "
216 << g.
res(a.i0) <<
"[" << a.i2 <<
"]=" << g.
sx_work(a.i1) <<
";\n";
223 casadi_int offset = worksize;
224 for (casadi_int i=0; i<m.
f_n_in; ++i) {
226 g <<
"arg[" <<
n_in_+i <<
"] = "
232 g <<
"arg[" <<
n_in_+i <<
"]=" << 0 <<
";\n";
234 g <<
"arg[" <<
n_in_+i <<
"]=" <<
"w+" +
str(offset) <<
";\n";
241 casadi_int out_offset = offset;
244 for (casadi_int i=0; i<m.
f_n_out; ++i) {
245 g <<
"res[" <<
n_out_+i <<
"]=" <<
"w+" +
str(offset) <<
";\n";
249 for (casadi_int i=0; i<m.
f_n_in; ++i) {
251 for (casadi_int j=0; j<m.
f_nnz_in[i]; ++j) {
252 g <<
"w["+
str(k+worksize) +
"] = " << g.
sx_work(m.
dep[k]) <<
";\n";
262 g <<
"if (" << flag <<
") return 1;\n";
263 for (casadi_int i=0;i<m.
n_res;++i) {
266 g <<
"w[" +
str(i+out_offset) +
"];\n";
272 << g.
arg(a.i1) <<
"? " << g.
arg(a.i1) <<
"[" << a.i2 <<
"] : 0;\n";
284 casadi_assert_dev(ndep>0);
298 "Default input values"}},
299 {
"just_in_time_sparsity",
301 "Propagate sparsity patterns using just-in-time "
302 "compilation to a CPU or GPU using OpenCL"}},
303 {
"just_in_time_opencl",
305 "Just-in-time compilation for numeric evaluation using OpenCL (experimental)"}},
308 "Reuse variables in the work vector"}},
311 "Perform common subexpression elimination (complexity is N*log(N) in graph size)"}},
314 "Allow construction with free variables (Default: false)"}},
315 {
"allow_duplicate_io_names",
317 "Allow construction with duplicate io names (Default: false)"}}
338 bool cse_opt =
false;
339 bool allow_free =
false;
342 for (
auto&& op : opts) {
343 if (op.first==
"default_in") {
345 }
else if (op.first==
"live_variables") {
347 }
else if (op.first==
"just_in_time_opencl") {
349 }
else if (op.first==
"just_in_time_sparsity") {
351 }
else if (op.first==
"cse") {
353 }
else if (op.first==
"allow_free") {
354 allow_free = op.second;
367 "Option 'default_in' has incorrect length");
370 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
371 std::lock_guard<std::mutex> lock(SX::get_mutex_temp());
375 std::stack<SXNode*> s;
378 std::vector<SXNode*> nodes;
382 for (
auto it =
out_.begin(); it !=
out_.end(); ++it, ++ind) {
384 for (
auto itc = (*it)->begin(); itc != (*it)->end(); ++itc, ++nz) {
390 nodes.push_back(
static_cast<SXNode*
>(
nullptr));
394 casadi_assert(nodes.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
396 for (casadi_int i=0; i<nodes.size(); ++i) {
398 nodes[i]->temp =
static_cast<int>(i);
405 for (std::vector<SXNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
416 std::vector<std::pair<int, SXNode*> > symb_loc;
419 int curr_oind, curr_nz=0;
420 casadi_assert(
out_.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
421 for (curr_oind=0; curr_oind<
out_.size(); ++curr_oind) {
422 if (
out_[curr_oind].nnz()!=0) {
428 std::vector<casadi_int> refcount(nodes.size(), 0);
435 std::vector<int> alg_index;
436 alg_index.reserve(nodes.size());
438 for (std::vector<SXNode*>::iterator it=nodes.begin(); it!=nodes.end(); ++it) {
446 ae.
op = n==
nullptr ?
static_cast<int>(
OP_OUTPUT) :
static_cast<int>(n->
op());
459 symb_loc.push_back(std::make_pair(
algorithm_.size(), n));
465 ae.
i1 =
out_[curr_oind]->at(curr_nz)->temp;
469 casadi_assert(curr_nz < std::numeric_limits<int>::max(),
"Integer overflow");
471 if (curr_nz>=
out_[curr_oind].nnz()) {
473 casadi_assert(curr_oind < std::numeric_limits<int>::max(),
"Integer overflow");
475 for (; curr_oind<
out_.size(); ++curr_oind) {
476 if (
out_[curr_oind].nnz()!=0) {
509 for (casadi_int i=0; i<ndeps; ++i) {
517 int oind =
static_cast<OutputSX*
>(n)->oind_;
518 casadi_assert(
call_.
el.at(dep[0]).res.at(oind)==-1,
"Duplicate");
529 for (casadi_int c=0; c<ndeps; ++c) {
530 refcount.at(dep[c])++;
542 std::vector<int> place(nodes.size());
545 std::stack<int> unused;
572 for (casadi_int c=ndeps-1; c>=0; --c) {
573 casadi_int ch_ind = dep[c];
574 casadi_int remaining = --refcount.at(ch_ind);
575 if (remaining==0) unused.push(place[ch_ind]);
580 for (casadi_int c=0; c<nres; ++c) {
581 if (res[c]<0)
continue;
584 res[c] = place[res[c]] = unused.top();
588 res[c] = place[res[c]] = worksize++;
594 for (casadi_int c=0; c<ndeps; ++c) {
595 dep[c] = place[dep[c]];
609 casadi_message(
"Using live variables: work array is " +
str(
worksize_)
610 +
" instead of " +
str(nodes.size()));
612 casadi_message(
"Live variables disabled.");
625 for (casadi_int i=0; i<nodes.size(); ++i) {
632 for (
auto it=symb_loc.begin(); it!=symb_loc.end(); ++it) {
633 it->second->temp = it->first+1;
637 casadi_assert(
in_.size() <= std::numeric_limits<int>::max(),
"Integer overflow");
638 for (
int ind=0; ind<
in_.size(); ++ind) {
640 for (
auto itc =
in_[ind]->begin(); itc !=
in_[ind]->end(); ++itc, ++nz) {
641 int i = itc->get_temp()-1;
658 for (std::vector<std::pair<int, SXNode*> >::const_iterator it=symb_loc.begin();
659 it!=symb_loc.end(); ++it) {
660 if (it->second->temp!=0) {
670 casadi_error(
name_ +
"::init: Initialization failed since variables [" +
671 join(
get_free(),
", ") +
"] are free. These symbols occur in the output expressions "
672 "but you forgot to declare these as inputs. "
673 "Set option 'allow_free' to allow free variables.");
680 casadi_error(
"OpenCL is not supported in this version of CasADi");
685 casadi_error(
"OpenCL is not supported in this version of CasADi");
705 std::vector<casadi_int> alg_i(
worksize_, -1);
721 if (arg_i[e.i1]>=0) {
730 casadi_int offset_input = 0;
731 for (casadi_int i=0; i<m.f_n_in; ++i) {
734 casadi_int offset = -1;
735 for (casadi_int j=0; j<m.f_nnz_in[i]; ++j) {
736 casadi_int k = offset_input+j;
738 arg = arg_i[m.dep[k]];
739 offset = nz_i[m.dep[k]];
741 if (arg_i[m.dep[k]]==-1) {
746 if (nz_i[m.dep[k]]!=offset+j) {
756 for (casadi_int j=0; j<m.f_nnz_in[i]; ++j) {
757 casadi_int k = offset_input+j;
758 if (arg_i[m.dep[k]]>=0) {
764 m.copy_elision_arg[i] = arg;
765 m.copy_elision_offset[i] = offset;
767 offset += m.f_nnz_in[i];
768 offset_input += m.f_nnz_in[i];
772 for (casadi_int i=0; i<m.n_res; ++i) {
774 arg_i[m.res[i]] = -1;
785 if (arg_i[e.i1]>=0) {
789 if (arg_i[e.i2]>=0) {
803 std::vector<SXElem>::iterator it=ret.begin();
806 std::vector<SXElem>::const_iterator b_it =
operations_.begin();
809 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
812 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
815 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
832 casadi_assert(it==ret.end(),
"Dimension mismatch");
838 bool always_inline,
bool never_inline)
const {
851 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
854 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
857 std::vector<SXElem>::const_iterator p_it =
free_vars_.begin();
860 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
864 w[a.i0] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
867 if (res[a.i0]!=
nullptr) res[a.i0][a.i2] = w[a.i1];
873 w[a.i0] = *p_it++;
break;
877 const SXElem& orig = *b_it++;
878 std::vector<SXElem> deps(m.
n_dep);
879 bool identical =
true;
881 std::vector<SXElem> ret;
882 for (casadi_int i=0;i<m.
n_dep;++i) {
888 for (casadi_int i=0;i<m.
n_dep;++i) deps[i] = w[m.
dep[i]];
891 for (casadi_int i=0;i<m.
n_res;++i) {
892 if (m.
res[i]>=0) w[m.
res[i]] = ret[i];
902 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
907 const casadi_int depth = 2;
919 bool always_inline,
bool never_inline)
const {
924 if (!always_inline) {
931 std::vector<SXElem>::const_iterator c_it =
constants_.begin();
934 "Free variables not supported in inlining call to SXFunction::eval_mx");
937 casadi_assert(arg.size()==
n_in_,
"Wrong number of input arguments");
938 res.resize(
out_.size());
941 std::vector<MX> w(
sz_w());
942 if (
verbose_) casadi_message(
"Allocated work vector");
945 std::vector<std::vector<MX> > arg_split(
in_.size());
946 for (casadi_int i=0; i<
in_.size(); ++i) {
948 std::vector<MX> orig = arg[i].get_nonzeros();
952 std::vector<MX> w(arg[i].size1());
957 arg_split[i] = target;
961 std::vector<std::vector<MX> > res_split(
out_.size());
962 for (casadi_int i=0; i<
out_.size(); ++i) res_split[i].resize(
nnz_out(i));
965 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
969 w[a.i0] = arg_split[a.i1][a.i2];
972 res_split[a.i0][a.i2] = w[a.i1];
975 w[a.i0] =
static_cast<double>(*c_it++);
980 std::vector<MX> deps(m.
n_dep);
981 std::vector<MX> args;
985 for (casadi_int i=0;i<m.
f_n_in;++i) {
987 for (casadi_int j=0;j<m.
f_nnz_in[i];++j) {
988 arg.push_back(w[m.
dep[k++]]);
990 args.push_back(sparsity_cast(vertcat(arg), m.
f.
sparsity_in(i)));
994 std::vector<MX> ret = m.
f(args);
998 for (casadi_int i=0;i<m.
f_n_out;++i) {
999 std::vector<MX> nz = ret[i].get_nonzeros();
1000 res.insert(res.end(), nz.begin(), nz.end());
1004 for (casadi_int i=0;i<m.
n_res;++i) {
1005 if (m.
res[i]>=0) w[m.
res[i]] = res[i];
1014 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1023 for (casadi_int i=0; i<res.size(); ++i) {
1024 res[i] = sparsity_cast(vertcat(res_split[i]),
sparsity_out_[i]);
1030 casadi_assert(!(always_inline && never_inline),
1032 casadi_assert(!(never_inline &&
has_free()),
1034 if (always_inline)
return true;
1035 if (never_inline)
return false;
1043 std::vector<std::vector<SX> >& fsens)
const {
1047 casadi_int nfwd = fseed.size();
1051 if (nfwd==0)
return;
1054 casadi_int npar = 1;
1055 for (
auto&& r : fseed) {
1057 casadi_assert_dev(npar==1);
1063 for (
auto it=fseed.begin(); it!=fseed.end(); ++it) {
1064 casadi_assert_dev(it->size()==
n_in_);
1065 for (casadi_int i=0; i<
n_in_; ++i) {
1068 std::vector<std::vector<SX> > fseed2(fseed);
1069 for (
auto&& r : fseed2) {
1078 for (casadi_int d=0; d<nfwd; ++d) {
1080 for (casadi_int i=0; i<fsens[d].size(); ++i)
1086 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1089 std::vector<TapeEl<SXElem> > s_pdwork(
operations_.size());
1090 std::vector<TapeEl<SXElem> >::iterator it1 = s_pdwork.begin();
1093 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1105 CASADI_MATH_DER_BUILTIN(f->
dep(0), f->
dep(1), f, it1++->d)
1117 if (
verbose_) casadi_message(
"Calculating forward derivatives");
1118 for (casadi_int dir=0; dir<nfwd; ++dir) {
1119 std::vector<TapeEl<SXElem> >::const_iterator it2 = s_pdwork.begin();
1123 w[a.i0] = fseed[dir][a.i1].nonzeros()[a.i2];
break;
1125 fsens[dir][a.i0].nonzeros()[a.i2] = w[a.i1];
break;
1136 CallSX* call_node =
static_cast<CallSX*
>(it2->d[0].get());
1142 std::vector<SXElem> deps;
1143 deps.reserve(2*m.n_dep);
1146 casadi_int offset = 0;
1147 for (casadi_int i=0;i<m.f_n_in;++i) {
1148 casadi_int nnz = ff.
nnz_in(i);
1149 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1150 for (casadi_int j=0;j<nnz;++j) {
1151 deps.push_back(call_node->
dep(offset+j));
1153 offset += m.f_nnz_in[i];
1158 for (casadi_int i=0;i<m.f_n_out;++i) {
1159 casadi_int nnz = ff.
nnz_in(i+m.f_n_in);
1160 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1161 for (casadi_int j=0;j<nnz;++j) {
1162 deps.push_back(call_node->
get_output(offset+j));
1164 offset += m.f_nnz_out[i];
1169 for (casadi_int i=0;i<m.f_n_in;++i) {
1170 casadi_int nnz = ff.
nnz_in(i+m.f_n_in+m.f_n_out);
1172 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1174 for (casadi_int j=0;j<nnz;++j) {
1175 deps.push_back(w[m.dep[offset+j]]);
1178 offset += m.f_nnz_in[i];
1187 for (casadi_int i=0;i<m.f_n_out;++i) {
1188 casadi_int nnz = ff.
nnz_out(i);
1190 casadi_assert(nnz==0 || nnz==m.f_nnz_out[i],
"Not implemented");
1192 for (casadi_int j=0;j<nnz;++j) {
1193 if (m.res[offset+j]>=0) w[m.res[offset+j]] = ret[k];
1197 offset += m.f_nnz_out[i];
1202 CASADI_MATH_BINARY_BUILTIN
1203 w[a.i0] = it2->d[0] * w[a.i1] + it2->d[1] * w[a.i2];
1207 w[a.i0] = it2->d[0] * w[a.i1];
1215 std::vector<std::vector<SX> >& asens)
const {
1219 casadi_int nadj = aseed.size();
1223 if (nadj==0)
return;
1226 casadi_int npar = 1;
1227 for (
auto&& r : aseed) {
1229 casadi_assert_dev(npar==1);
1235 bool matching_sparsity =
true;
1236 for (casadi_int d=0; d<nadj; ++d) {
1237 casadi_assert_dev(aseed[d].size()==
n_out_);
1238 for (casadi_int i=0; matching_sparsity && i<
n_out_; ++i)
1239 matching_sparsity = aseed[d][i].sparsity()==
sparsity_out_[i];
1243 if (!matching_sparsity) {
1244 std::vector<std::vector<SX> > aseed2(aseed);
1245 for (casadi_int d=0; d<nadj; ++d)
1246 for (casadi_int i=0; i<
n_out_; ++i)
1253 for (casadi_int d=0; d<nadj; ++d) {
1254 asens[d].resize(
n_in_);
1255 for (casadi_int i=0; i<asens[d].size(); ++i) {
1259 std::fill(asens[d][i]->begin(), asens[d][i]->end(), 0);
1265 std::vector<SXElem>::const_iterator b_it=
operations_.begin();
1268 std::vector<TapeEl<SXElem> > s_pdwork(
operations_.size());
1269 std::vector<TapeEl<SXElem> >::iterator it1 = s_pdwork.begin();
1272 if (
verbose_) casadi_message(
"Evaluating algorithm forward");
1284 CASADI_MATH_DER_BUILTIN(f->
dep(0), f->
dep(1), f, it1++->d)
1293 if (
verbose_) casadi_message(
"Calculating adjoint derivatives");
1298 for (casadi_int dir=0; dir<nadj; ++dir) {
1299 auto it2 = s_pdwork.rbegin();
1304 asens[dir][it->i1].nonzeros()[it->i2] = w[it->i0];
1308 w[it->i1] += aseed[dir][it->i0].nonzeros()[it->i2];
1321 auto& m =
call_.
el.at(it->i1);
1322 CallSX* call_node =
static_cast<CallSX*
>(it2->d[0].get());
1328 std::vector<SXElem> deps;
1329 deps.reserve(m.n_dep+m.n_res);
1332 casadi_int offset = 0;
1333 for (casadi_int i=0;i<m.f_n_in;++i) {
1334 casadi_int nnz = fr.
nnz_in(i);
1335 casadi_assert(nnz==0 || nnz==m.f.nnz_in(i),
"Not implemented");
1336 for (casadi_int j=0;j<nnz;++j) {
1337 deps.push_back(call_node->
dep(offset+j));
1339 offset += m.f_nnz_in[i];
1344 for (casadi_int i=0;i<m.f_n_out;++i) {
1345 casadi_int nnz = fr.
nnz_in(i+m.f_n_in);
1346 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1347 for (casadi_int j=0;j<nnz;++j) {
1348 deps.push_back(call_node->
get_output(offset+j));
1350 offset += m.f_nnz_out[i];
1355 for (casadi_int i=0;i<m.f_n_out;++i) {
1356 casadi_int nnz = fr.
nnz_in(i+m.f_n_in+m.f_n_out);
1358 casadi_assert(nnz==0 || nnz==m.f.nnz_out(i),
"Not implemented");
1360 for (casadi_int j=0;j<nnz;++j) {
1361 deps.push_back((m.res[offset+j]>=0) ? w[m.res[offset+j]] : 0);
1364 offset += m.f.nnz_out(i);
1371 for (casadi_int i=0;i<m.n_res;++i) {
1372 if (m.res[i]>=0) w[m.res[i]] = 0;
1378 for (casadi_int i=0;i<m.f_n_in;++i) {
1379 casadi_int nnz = fr.
nnz_out(i);
1381 casadi_assert(nnz==0 || nnz==m.f_nnz_in[i],
"Not implemented");
1383 for (casadi_int j=0;j<nnz;++j) {
1384 w[m.dep[offset+j]] += ret[k++];
1387 offset += m.f_nnz_in[i];
1392 CASADI_MATH_BINARY_BUILTIN
1395 w[it->i1] += it2->d[0] * seed;
1396 w[it->i2] += it2++->d[1] * seed;
1401 w[it->i1] += it2++->d[0] * seed;
1407 template<
typename T,
typename CT>
1409 CT*** call_arg, T*** call_res, casadi_int** call_iw, T** call_w, T**
nz_in, T**
nz_out)
const {
1418 for (casadi_int i=0;i<m.
f_n_in;++i) {
1419 (*call_arg)[i] = ptr_w;
1425 for (casadi_int i=0;i<m.
f_n_out;++i) {
1426 (*call_res)[i] = ptr_w;
1431 template<
typename T>
1434 const T** call_arg = arg;
1436 casadi_int* call_iw = iw;
1444 for (casadi_int i=0;i<m.n_dep;++i) {
1445 nz_in[i] = w[m.dep[i]];
1448 m.f(call_arg, call_res, call_iw, call_w);
1451 for (casadi_int i=0;i<m.n_res;++i) {
1460 template<
typename T>
1465 casadi_int* call_iw = iw;
1472 std::fill_n(
nz_in, m.n_dep, 0);
1475 for (casadi_int i=0;i<m.n_res;++i) {
1476 nz_out[i] = (m.res[i]>=0) ? w[m.res[i]] : 0;
1480 m.f.rev(call_arg, call_res, call_iw, call_w);
1483 for (casadi_int i=0;i<m.n_res;++i) {
1484 if (m.res[i]>=0) w[m.res[i]] = 0;
1488 for (casadi_int i=0;i<m.n_dep;++i) {
1489 w[m.dep[i]] |=
nz_in[i];
1505 w[e.i0] = arg[e.i1]==
nullptr ? 0 : arg[e.i1][e.i2];
1508 if (res[e.i0]!=
nullptr) res[e.i0][e.i2] = w[e.i1];
1514 w[e.i0] = w[e.i1] | w[e.i2];
break;
1521 casadi_int* iw,
bvec_t* w,
void* mem)
const {
1525 std::fill_n(w,
sz_w(), 0);
1539 if (arg[it->i1]!=
nullptr) arg[it->i1][it->i2] |= w[it->i0];
1543 if (res[it->i0]!=
nullptr) {
1544 w[it->i1] |= res[it->i0][it->i2];
1545 res[it->i0][it->i2] = 0;
1575 std::ostream &ss,
const Dict& options)
const {
1578 casadi_int indent_level = 0;
1581 for (
auto&& op : options) {
1582 if (op.first==
"indent_level") {
1583 indent_level = op.second;
1585 casadi_error(
"Unknown option '" + op.first +
"'.");
1591 for (casadi_int i=0;i<indent_level;++i) {
1596 for (casadi_int i=0;i<
n_in_;++i) {
1597 ss << indent <<
"argin_" << i <<
" = nonzeros_gen(varargin{" << i+1 <<
"});" << std::endl;
1600 Function f = shared_from_this<Function>();
1612 ss << indent <<
"w" << o[0] <<
" = " <<
"argin_" << i[0] <<
"(" << i[1]+1 <<
");";
1618 ss << indent <<
"argout_" << o[0] <<
"{" << o[1]+1 <<
"} = w" << i[0] <<
";";
1624 std::ios_base::fmtflags fmtfl = ss.flags();
1625 ss << indent <<
"w" << o[0] <<
" = ";
1626 ss << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1);
1633 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
"^2;" << std::endl;
1638 ss << indent <<
"w" << o[0] <<
" = abs(" <<
"w" << i[0] <<
");" << std::endl;
1643 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".^w" << i[1] <<
";" << std::endl;
1646 ss << indent <<
"w" << o[0] <<
" = ~" <<
"w" << i[0] <<
";" << std::endl;
1649 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" | w" << i[1] <<
";" << std::endl;
1652 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" & w" << i[1] <<
";" << std::endl;
1655 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" ~= w" << i[1] <<
";" << std::endl;
1658 ss << indent <<
"w" << o[0] <<
" = ";
1659 ss <<
"if_else_zero_gen(w" << i[0] <<
", w" << i[1] <<
");" << std::endl;
1664 "w"+std::to_string(i[0]),
"w"+std::to_string(i[1])) <<
";" << std::endl;
1667 "w"+std::to_string(i[0])) <<
";" << std::endl;
1676 int version = s.
version(
"SXFunction", 1, 2);
1696 s.
unpack(
"SXFunction::call_el_size", el_size);
1700 for (casadi_int k=0;k<el_size;++k) {
1702 s.
unpack(
"SXFunction::call_el_f", f);
1705 s.
unpack(
"SXFunction::call_el_dep", e.dep);
1706 s.
unpack(
"SXFunction::call_el_res", e.res);
1707 s.
unpack(
"SXFunction::call_el_copy_elision_arg", e.copy_elision_arg);
1708 s.
unpack(
"SXFunction::call_el_copy_elision_offset", e.copy_elision_offset);
1727 s.
unpack(
"SXFunction::ScalarAtomic::op", e.
op);
1728 s.
unpack(
"SXFunction::ScalarAtomic::i0", e.
i0);
1729 s.
unpack(
"SXFunction::ScalarAtomic::i1", e.
i1);
1730 s.
unpack(
"SXFunction::ScalarAtomic::i2", e.
i2);
1760 s.
pack(
"SXFunction::call_el_size",
call_.
el.size());
1762 for (
const auto& n :
call_.
el) {
1763 s.
pack(
"SXFunction::call_el_f", n.f);
1764 s.
pack(
"SXFunction::call_el_dep", n.dep);
1765 s.
pack(
"SXFunction::call_el_res", n.res);
1766 s.
pack(
"SXFunction::call_el_copy_elision_arg", n.copy_elision_arg);
1767 s.
pack(
"SXFunction::call_el_copy_elision_offset", n.copy_elision_offset);
1774 s.
pack(
"SXFunction::ScalarAtomic::op", e.op);
1775 s.
pack(
"SXFunction::ScalarAtomic::i0", e.i0);
1776 s.
pack(
"SXFunction::ScalarAtomic::i1", e.i1);
1777 s.
pack(
"SXFunction::ScalarAtomic::i2", e.i2);
1790 casadi_int max_depth)
const {
1800 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
1801 std::lock_guard<std::mutex> lock(SX::get_mutex_temp());
1804 std::stack<SXNode*> s;
1807 std::vector<SXNode*> nodes;
1811 for (
auto it = expr.begin(); it != expr.end(); ++it, ++ind) {
1813 for (
auto itc = (*it)->begin(); itc != (*it)->end(); ++itc, ++nz) {
1821 for (casadi_int i=0; i<nodes.size(); ++i) {
1825 std::vector<SX> ret(nodes.size());
1826 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 print_op(casadi_int op, const std::string &a0)
Print an operation 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.
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.
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.
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.
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)
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.
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.