25 #include "mx_function.hpp"
26 #include "casadi_misc.hpp"
27 #include "casadi_common.hpp"
28 #include "global_options.hpp"
29 #include "casadi_interrupt.hpp"
30 #include "io_instruction.hpp"
31 #include "serializing_stream.hpp"
37 #define CASADI_THROW_ERROR(FNAME, WHAT) \
38 throw CasadiException("Error in MXFunction::" FNAME " at " + CASADI_WHERE + ":\n"\
44 const std::vector<MX>& inputv,
45 const std::vector<MX>& outputv,
46 const std::vector<std::string>& name_in,
47 const std::vector<std::string>& name_out) :
59 "Default input values"}},
62 "Reuse variables in the work vector"}},
65 "Dump interpreted instruction values to name.NNNNNN.trace.jsonl in dump_dir, "
66 "using the dump_in/dump_out counter. [false]"}},
67 {
"print_instructions",
69 "Print each operation during evaluation. Influenced by print_canonical."}},
72 "Perform common subexpression elimination (complexity is N*log(N) in graph size)"}},
75 "Allow construction with free variables (Default: false)"}},
76 {
"allow_duplicate_io_names",
78 "Allow construction with duplicate io names (Default: false)"}}
85 if (target==
"clone") opts[
"default_in"] =
default_in_;
109 return { io->ind() };
123 bool cse_opt =
false;
124 bool allow_free =
false;
127 for (
auto&& op : opts) {
128 if (op.first==
"default_in") {
130 }
else if (op.first==
"live_variables") {
132 }
else if (op.first==
"dump_trace") {
134 }
else if (op.first==
"print_instructions") {
136 }
else if (op.first==
"cse") {
138 }
else if (op.first==
"allow_free") {
139 allow_free = op.second;
143 casadi_assert(!
dump_trace_ || !
jit_,
"dump_trace is not supported for JIT evaluation");
150 "Option 'default_in' has incorrect length");
154 for (
const MX& e :
out_) {
155 casadi_assert(!e->has_output(),
156 "Function output contains MultiOutput nodes. "
157 "You must use get_output() to make a concrete instance.");
163 std::stack<MXNode*> s;
166 std::vector<MXNode*> nodes;
167 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
168 std::lock_guard<std::mutex> lock(MX::get_mutex_temp());
172 for (casadi_int ind=0; ind<
out_.size(); ++ind) {
174 std::vector<MX> prim =
out_[ind].primitives();
175 casadi_int nz_offset=0;
176 for (casadi_int p=0; p<prim.size(); ++p) {
178 s.push(prim[p].get());
181 nodes.push_back(
new Output(prim[p], ind, p, nz_offset));
183 nz_offset += prim[p].nnz();
188 for (casadi_int i=0; i<nodes.size(); ++i) {
193 std::vector<casadi_int> place_in_alg;
194 place_in_alg.reserve(nodes.size());
197 std::vector<std::pair<casadi_int, MXNode*> > symb_loc;
200 std::vector<casadi_int> refcount(nodes.size(), 0);
208 casadi_int op = n->op();
212 symb_loc.push_back(std::make_pair(
algorithm_.size(), n));
220 ae.
arg.resize(n->n_dep());
221 for (casadi_int i=0; i<n->n_dep(); ++i) {
222 ae.
arg[i] = n->dep(i)->temp;
224 ae.
res.resize(n->nout());
225 if (n->has_output()) {
226 std::fill(ae.
res.begin(), ae.
res.end(), -1);
227 }
else if (!ae.
res.empty()) {
232 for (casadi_int c=0; c<ae.
arg.size(); ++c) {
234 refcount[ae.
arg[c]]++;
244 casadi_int oind = n->which_output();
247 casadi_int pind = place_in_alg[n->dep(0)->temp];
250 casadi_int& otmp =
algorithm_[pind].res.at(oind);
258 place_in_alg.push_back(-1);
263 std::vector<casadi_int>& place = place_in_alg;
264 place.resize(nodes.size());
267 SPARSITY_MAP<casadi_int, std::stack<casadi_int> > unused_all;
270 casadi_int worksize = 0;
277 casadi_int first_to_free = 0;
278 casadi_int last_to_free = e.data->n_inplace();
279 for (casadi_int task=0; task<2; ++task) {
282 for (casadi_int c=last_to_free-1; c>=first_to_free; --c) {
287 casadi_int& ch_ind = e.arg[c];
292 casadi_int remaining = --refcount[ch_ind];
298 casadi_int nnz = nodes[ch_ind]->sparsity().nnz();
301 unused_all[nnz].push(place[ch_ind]);
305 ch_ind = place[ch_ind];
313 first_to_free = last_to_free;
314 last_to_free = e.arg.size();
317 for (casadi_int c=0; c<e.res.size(); ++c) {
323 casadi_int nnz = e.data->sparsity(c).nnz();
326 std::stack<casadi_int>& unused = unused_all[nnz];
329 if (!unused.empty()) {
330 e.res[c] = place[e.res[c]] = unused.top();
337 e.res[c] = place[e.res[c]] = worksize++;
345 casadi_message(
"Using live variables: work array is " +
str(worksize)
346 +
" instead of " +
str(nodes.size()));
348 casadi_message(
"Live variables disabled.");
355 size_t wind=0,
sz_w=0;
358 for (casadi_int c=0; c<e.res.size(); ++c) {
365 sz_w = std::max(
sz_w, std::max(e.data->sz_w(), e.data->codegen_sz_w()));
368 wind += e.data->sparsity(c).nnz();
375 for (casadi_int i=0; i<
workloc_.size(); ++i) {
383 for (casadi_int i=0; i<nodes.size(); ++i) {
390 for (
auto it=symb_loc.begin(); it!=symb_loc.end(); ++it) {
391 it->second->temp = it->first+1;
395 for (casadi_int ind=0; ind<
in_.size(); ++ind) {
397 std::vector<MX> prim =
in_[ind].primitives();
398 casadi_int nz_offset=0;
399 for (casadi_int p=0; p<prim.size(); ++p) {
400 casadi_int i = prim[p].get_temp()-1;
406 algorithm_[i].data.own(
new Input(prim[p].sparsity(), ind, p, nz_offset));
409 nz_offset += prim[p]->nnz();
415 for (
auto it=symb_loc.begin(); it!=symb_loc.end(); ++it) {
416 casadi_int i = it->second->temp-1;
427 casadi_error(
name_ +
"::init: Initialization failed since variables [" +
428 join(
get_free(),
", ") +
"] are free. These symbols occur in the output expressions "
429 "but you forgot to declare these as inputs. "
430 "Set option 'allow_free' to allow free variables.");
436 if (a.data->has_refcount()) {
445 casadi_int* iw,
double* w,
void* mem)
const {
450 setup(mem, arg, res, iw, w);
452 const double** arg1 = arg+
n_in_;
453 double** res1 = res+
n_out_;
457 std::stringstream ss;
459 casadi_error(
"Cannot evaluate \"" + ss.str() +
"\" since variables "
473 double *w1 = w+
workloc_[e.res.front()];
474 casadi_int nnz=e.data.nnz();
475 casadi_int i=e.data->ind();
476 casadi_int nz_offset=e.data->offset();
477 if (arg[i]==
nullptr) {
478 std::fill(w1, w1+nnz, 0);
480 std::copy(arg[i]+nz_offset, arg[i]+nz_offset+nnz, w1);
484 double *w1 = w+
workloc_[e.arg.front()];
485 casadi_int nnz=e.data->dep().nnz();
486 casadi_int i=e.data->ind();
487 casadi_int nz_offset=e.data->offset();
488 if (res[i]) std::copy(w1, w1+nnz, res[i]+nz_offset);
491 for (casadi_int i=0; i<e.arg.size(); ++i)
492 arg1[i] = e.arg[i]>=0 ? w+
workloc_[e.arg[i]] :
nullptr;
493 for (casadi_int i=0; i<e.res.size(); ++i)
494 res1[i] = e.res[i]>=0 ? w+
workloc_[e.res[i]] :
nullptr;
498 if (e.data->eval(arg1, res1, iw, w)) {
509 if (trace) *trace <<
"{\"event\":\"error\"}\n";
517 const double* w,
bool output)
const {
519 const auto& slots = output ? e.res : e.arg;
520 casadi_int n = slots.size();
521 if (e.op ==
OP_INPUT && !output) n = 0;
523 trace <<
"{\"instruction\":" << k <<
",\"op\":" << e.op
524 <<
",\"phase\":\"" << (output ?
"outputs" :
"inputs") <<
"\",\"values\":[";
525 for (casadi_int i = 0; i < n; ++i) {
527 casadi_int nnz = output ? e.data->sparsity(i).nnz() : e.data->dep(i).nnz();
537 <<
" = @" << el.
arg.at(0);
539 if (el.
res.front()!=el.
arg.at(0)) {
540 s <<
"@" << el.
res.front() <<
" = @" << el.
arg.at(0) <<
"; ";
542 std::vector<std::string> arg(2);
543 arg[0] =
"@" +
str(el.
res.front());
544 arg[1] =
"@" +
str(el.
arg.at(1));
547 if (el.
res.size()==1) {
548 s <<
"@" << el.
res.front() <<
" = ";
551 for (casadi_int i=0; i<el.
res.size(); ++i) {
554 s <<
"@" << el.
res[i];
561 std::vector<std::string> arg;
563 arg.resize(el.
arg.size());
564 for (casadi_int i=0; i<el.
arg.size(); ++i) {
566 arg[i] =
"@" +
str(el.
arg[i]);
578 const double** arg)
const {
579 stream <<
name_ <<
":" << k <<
": " <<
print(el) <<
" inputs:" << std::endl;
580 for (
size_t i = 0; i < el.
arg.size(); ++i) {
594 const std::vector<casadi_int>& arg,
const std::vector<bool>& arg_is_ref)
const {
596 for (
size_t i = 0; i < el.
arg.size(); ++i) {
599 std::string a = g.
work(arg[i], el.
data->
dep(i).
nnz(), arg_is_ref[i]);
601 g << g.
printf(
"\\n") <<
"\n";
607 const std::vector<casadi_int>& res,
const std::vector<bool>& res_is_ref)
const {
609 for (
size_t i = 0; i < el.
res.size(); ++i) {
614 g << g.
printf(
"\\n") <<
"\n";
620 double** res)
const {
621 stream <<
name_ <<
":" << k <<
": " <<
print(el) <<
" outputs:" << std::endl;
622 for (
size_t i = 0; i < el.
res.size(); ++i) {
636 stream <<
"Algorithm:";
639 stream << std::endl <<
print(e);
656 casadi_int nnz=e.data.nnz();
657 casadi_int i=e.data->ind();
658 casadi_int nz_offset=e.data->offset();
659 const bvec_t* argi = arg[i];
662 std::copy(argi+nz_offset, argi+nz_offset+nnz, w1);
664 std::fill_n(w1, nnz, 0);
668 casadi_int nnz=e.data.dep().nnz();
669 casadi_int i=e.data->ind();
670 casadi_int nz_offset=e.data->offset();
674 std::copy(w1, w1+nnz, resi+nz_offset);
675 }
else if (resi!=
nullptr) {
676 std::fill_n(resi+nz_offset, nnz, 0);
680 for (casadi_int i=0; i<e.arg.size(); ++i)
681 arg1[i] = e.arg[i]>=0 ? w+
workloc_[e.arg[i]] :
nullptr;
682 for (casadi_int i=0; i<e.res.size(); ++i)
683 res1[i] = e.res[i]>=0 ? w+
workloc_[e.res[i]] :
nullptr;
686 if (e.data->sp_forward(arg1, res1, iw, w))
return 1;
701 casadi_int nnz=e.data.nnz();
702 casadi_int i=e.data->ind();
703 casadi_int nz_offset=e.data->offset();
704 const bvec_t* argi = arg[i];
707 std::copy(argi+nz_offset, argi+nz_offset+nnz, w1);
709 std::fill_n(w1, nnz, 0);
712 casadi_int nnz=e.data.dep().nnz();
713 casadi_int i=e.data->ind();
714 casadi_int nz_offset=e.data->offset();
717 if (resi!=
nullptr) std::copy(w1, w1+nnz, resi+nz_offset);
719 for (casadi_int i=0; i<e.arg.size(); ++i)
720 arg1[i] = e.arg[i]>=0 ? w+
workloc_[e.arg[i]] :
nullptr;
721 for (casadi_int i=0; i<e.res.size(); ++i)
722 res1[i] = e.res[i]>=0 ? w+
workloc_[e.res[i]] :
nullptr;
723 if (e.data->eval_activity(arg1, res1, iw, w))
return 1;
730 std::map<std::string, bool> flagged;
733 const Function &f = it->data->which_function();
734 if (flagged.find(f.
name())==flagged.end()) {
735 flagged[f.
name()] =
true;
739 std::vector<std::string> ret;
740 for (
auto it : flagged) {
741 ret.push_back(it.first);
749 const Function &f = it->data->which_function();
750 if (name==f.
name())
return f;
753 casadi_error(
"No such function '" + name +
"'.");
757 casadi_int* iw,
bvec_t* w,
void* mem)
const {
765 std::fill_n(w,
sz_w(), 0);
771 casadi_int nnz=it->data.nnz();
772 casadi_int i=it->data->ind();
773 casadi_int nz_offset=it->data->offset();
777 for (casadi_int k=0; k<nnz; ++k) argi[nz_offset+k] |= w1[k];
778 std::fill_n(w1, nnz, 0);
781 casadi_int nnz=it->data.dep().nnz();
782 casadi_int i=it->data->ind();
783 casadi_int nz_offset=it->data->offset();
784 bvec_t* resi = res[i] ? res[i] + nz_offset :
nullptr;
787 for (casadi_int k=0; k<nnz; ++k) w1[k] |= resi[k];
788 std::fill_n(resi, nnz, 0);
792 for (casadi_int i=0; i<it->arg.size(); ++i)
793 arg1[i] = it->arg[i]>=0 ? w+
workloc_[it->arg[i]] :
nullptr;
794 for (casadi_int i=0; i<it->res.size(); ++i)
795 res1[i] = it->res[i]>=0 ? w+
workloc_[it->res[i]] :
nullptr;
798 if (it->data->sp_reverse(arg1, res1, iw, w))
return 1;
806 const casadi_int checking_depth = 2;
807 bool input_given =
true;
808 for (casadi_int i=0; i<arg.size() && input_given; ++i) {
823 bool always_inline,
bool never_inline)
const {
829 casadi_assert(arg.size()==
n_in_,
"Wrong number of input arguments");
830 res.resize(
out_.size());
833 if (!never_inline &&
isInput(arg)) {
834 std::copy(
out_.begin(),
out_.end(), res.begin());
845 std::vector<MX> swork(
workloc_.size()-1);
846 if (
verbose_) casadi_message(
"Allocated work vector");
849 std::vector<std::vector<MX> > arg_split(
in_.size());
850 for (casadi_int i=0; i<
in_.size(); ++i) arg_split[i] =
in_[i].split_primitives(arg[i]);
853 std::vector<std::vector<MX> > res_split(
out_.size());
854 for (casadi_int i=0; i<
out_.size(); ++i) res_split[i].resize(
out_[i].n_primitives());
856 std::vector<MX> arg1, res1;
859 casadi_int alg_counter = 0;
862 swork[it->res.front()] = project(arg_split.at(it->data->ind()).at(it->data->segment()),
863 it->data.sparsity(),
true);
866 res_split.at(it->data->ind()).at(it->data->segment()) = swork[it->arg.front()];
869 swork[it->res.front()] = it->data;
872 arg1.resize(it->arg.size());
873 for (casadi_int i=0; i<arg1.size(); ++i) {
874 casadi_int el = it->arg[i];
875 arg1[i] = el<0 ?
MX(it->data->dep(i).size()) : swork[el];
879 res1.resize(it->res.size());
880 it->data->eval_mx(arg1, res1);
883 for (casadi_int i=0; i<res1.size(); ++i) {
884 casadi_int el = it->res[i];
885 if (el>=0) swork[el] = res1[i];
891 for (casadi_int i=0; i<res.size(); ++i) res[i] =
out_[i].join_primitives(res_split[i]);
892 }
catch (std::exception& e) {
893 CASADI_THROW_ERROR(
"eval_mx", e.what());
898 std::vector<std::vector<MX> >& fsens)
const {
899 if (
verbose_) casadi_message(
name_ +
"::ad_forward(" +
str(fseed.size())+
")");
902 casadi_int nfwd = fseed.size();
904 for (casadi_int d=0; d<nfwd; ++d) {
913 for (
auto&& r : fseed) {
915 casadi_assert_dev(npar==1);
922 for (
auto&& r : fseed) {
925 std::vector<std::vector<MX> > fseed_purged, fsens_purged;
926 fseed_purged.reserve(nfwd);
927 std::vector<casadi_int> index_purged;
928 for (casadi_int d=0; d<nfwd; ++d) {
930 for (casadi_int i=0; i<fsens[d].size(); ++i) {
934 fseed_purged.push_back(fsens[d]);
935 index_purged.push_back(d);
943 for (casadi_int d=0; d<fseed_purged.size(); ++d) {
944 fsens[index_purged[d]] = fsens_purged[d];
958 std::vector<std::vector<MX> > dwork(
workloc_.size()-1);
959 fill(dwork.begin(), dwork.end(), std::vector<MX>(nfwd));
960 if (
verbose_) casadi_message(
"Allocated derivative work vector (forward mode)");
963 std::vector<std::vector<std::vector<MX>>> fseed_split(nfwd);
964 for (casadi_int d=0; d<nfwd; ++d) {
965 fseed_split[d].resize(fseed[d].size());
966 for (casadi_int i=0; i<fseed[d].size(); ++i) {
967 fseed_split[d][i] =
in_[i].split_primitives(fseed[d][i]);
972 std::vector<std::vector<std::vector<MX>>> fsens_split(nfwd);
973 for (casadi_int d=0; d<nfwd; ++d) {
974 fsens_split[d].resize(
out_.size());
975 for (casadi_int i=0; i<
out_.size(); ++i) {
976 fsens_split[d][i].resize(
out_[i].n_primitives());
981 std::vector<std::vector<MX> > oseed, osens;
984 std::vector<bool> skip(nfwd,
false);
990 for (casadi_int d=0; d<nfwd; ++d) {
991 dwork[e.res.front()][d] =
992 project(fseed_split[d].at(e.data->ind()).at(e.data->segment()),
993 e.data.sparsity(),
true);
997 for (casadi_int d=0; d<nfwd; ++d) {
998 fsens_split[d][e.data->ind()][e.data->segment()] = dwork[e.arg.front()][d];
1002 for (casadi_int d=0; d<nfwd; ++d) {
1003 dwork[e.res.front()][d] =
MX();
1008 for (casadi_int d=0; d<nfwd; ++d) {
1010 std::vector<MX> seed(e.arg.size());
1012 for (casadi_int i=0; i<e.arg.size(); ++i) {
1013 casadi_int el = e.arg[i];
1014 if (el<0 || dwork[el][d].is_empty(
true)) {
1015 seed[i] =
MX(e.data->dep(i).size());
1017 seed[i] = dwork[el][d];
1019 if (skip[d] && !seed[i].
is_zero()) skip[d] =
false;
1021 if (!skip[d]) oseed.push_back(seed);
1025 osens.resize(oseed.size());
1026 if (!osens.empty()) {
1027 fill(osens.begin(), osens.end(), std::vector<MX>(e.res.size()));
1028 e.data.ad_forward(oseed, osens);
1033 for (casadi_int d=0; d<nfwd; ++d) {
1034 for (casadi_int i=0; i<e.res.size(); ++i) {
1035 casadi_int el = e.res[i];
1037 dwork[el][d] = skip[d] ?
MX(e.data->sparsity(i).size()) : osens[d1][i];
1046 for (casadi_int d=0; d<nfwd; ++d) {
1047 for (casadi_int i=0; i<
out_.size(); ++i) {
1048 fsens[d][i] =
out_[i].join_primitives(fsens_split[d][i]);
1051 }
catch (std::exception& e) {
1052 CASADI_THROW_ERROR(
"ad_forward", e.what());
1057 std::vector<std::vector<MX> >& asens)
const {
1058 if (
verbose_) casadi_message(
name_ +
"::ad_reverse(" +
str(aseed.size())+
")");
1062 casadi_int nadj = aseed.size();
1064 for (casadi_int d=0; d<nadj; ++d) {
1065 asens[d].resize(
n_in_);
1069 if (nadj==0)
return;
1072 casadi_int npar = 1;
1073 for (
auto&& r : aseed) {
1075 casadi_assert_dev(npar==1);
1082 for (
auto&& r : aseed) {
1086 std::vector<std::vector<MX> > aseed_purged, asens_purged;
1087 aseed_purged.reserve(nadj);
1088 std::vector<casadi_int> index_purged;
1089 for (casadi_int d=0; d<nadj; ++d) {
1091 for (casadi_int i=0; i<asens[d].size(); ++i) {
1095 aseed_purged.push_back(asens[d]);
1096 index_purged.push_back(d);
1104 for (casadi_int d=0; d<aseed_purged.size(); ++d) {
1105 asens[index_purged[d]] = asens_purged[d];
1112 std::vector<std::vector<MX> > v;
1116 for (casadi_int i=0; i<v.size(); ++i) {
1117 for (casadi_int j=0; j<v[i].size(); ++j) {
1118 if (!v[i][j].is_empty()) {
1119 if (asens[i][j].is_empty()) {
1120 asens[i][j] = v[i][j];
1122 asens[i][j] += v[i][j];
1131 std::vector<std::vector<std::vector<MX>>> aseed_split(nadj);
1132 for (casadi_int d=0; d<nadj; ++d) {
1133 aseed_split[d].resize(
out_.size());
1134 for (casadi_int i=0; i<
out_.size(); ++i) {
1135 aseed_split[d][i] =
out_[i].split_primitives(aseed[d][i]);
1140 std::vector<std::vector<std::vector<MX>>> asens_split(nadj);
1141 for (casadi_int d=0; d<nadj; ++d) {
1142 asens_split[d].resize(
in_.size());
1143 for (casadi_int i=0; i<
in_.size(); ++i) {
1144 asens_split[d][i].resize(
in_[i].n_primitives());
1149 std::vector<std::vector<MX>> oseed, osens;
1150 oseed.reserve(nadj);
1151 osens.reserve(nadj);
1152 std::vector<bool> skip(nadj,
false);
1155 std::vector<std::vector<MX> > dwork(
workloc_.size()-1);
1156 fill(dwork.begin(), dwork.end(), std::vector<MX>(nadj));
1162 for (casadi_int d=0; d<nadj; ++d) {
1163 asens_split[d].at(it->data->ind()).at(it->data->segment()) = dwork[it->res.front()][d];
1164 dwork[it->res.front()][d] =
MX();
1168 for (casadi_int d=0; d<nadj; ++d) {
1169 MX a = project(aseed_split[d].at(it->data->ind()).at(it->data->segment()),
1170 it->data.dep().sparsity(),
true);
1171 if (dwork[it->arg.front()][d].is_empty(
true)) {
1172 dwork[it->arg.front()][d] = a;
1174 dwork[it->arg.front()][d] += a;
1179 for (casadi_int d=0; d<nadj; ++d) {
1180 dwork[it->res.front()][d] =
MX();
1185 for (casadi_int d=0; d<nadj; ++d) {
1190 std::vector<MX> seed(it->res.size());
1191 for (casadi_int i=0; i<it->res.size(); ++i) {
1193 casadi_int el = it->res[i];
1195 seed[i] = dwork[el][d];
1196 dwork[el][d] =
MX();
1202 if (seed[i].is_empty(
true)) seed[i] =
MX(it->data->sparsity(i).size());
1205 if (skip[d] && !seed[i].
is_zero()) skip[d] =
false;
1208 if (!skip[d]) oseed.push_back(seed);
1212 osens.resize(oseed.size());
1214 for (casadi_int d=0; d<nadj; ++d) {
1215 if (skip[d])
continue;
1216 osens[d1].resize(it->arg.size());
1217 for (casadi_int i=0; i<it->arg.size(); ++i) {
1219 casadi_int el = it->arg[i];
1221 osens[d1][i] = dwork[el][d];
1222 dwork[el][d] =
MX();
1224 osens[d1][i] =
MX();
1228 if (osens[d1][i].is_empty(
true)) osens[d1][i] =
MX(it->data->dep(i).size());
1234 if (!osens.empty()) {
1235 it->data.ad_reverse(oseed, osens);
1240 for (casadi_int d=0; d<nadj; ++d) {
1241 if (skip[d])
continue;
1242 for (casadi_int i=0; i<it->arg.size(); ++i) {
1243 casadi_int el = it->arg[i];
1245 if (dwork[el][d].is_empty(
true)) {
1246 dwork[el][d] = osens[d1][i];
1248 dwork[el][d] += osens[d1][i];
1258 for (casadi_int d=0; d<nadj; ++d) {
1259 for (casadi_int i=0; i<
in_.size(); ++i) {
1260 asens[d][i] =
in_[i].join_primitives(asens_split[d][i]);
1263 }
catch (std::exception& e) {
1264 CASADI_THROW_ERROR(
"ad_reverse", e.what());
1269 casadi_int* iw,
SXElem* w,
void* mem,
1270 bool always_inline,
bool never_inline)
const {
1280 std::vector<const SXElem*> argp(
sz_arg());
1281 std::vector<SXElem*> resp(
sz_res());
1289 casadi_int nnz=a.data.nnz();
1290 casadi_int i=a.data->ind();
1291 casadi_int nz_offset=a.data->offset();
1292 if (arg[i]==
nullptr) {
1293 std::fill(w1, w1+nnz, 0);
1295 std::copy(arg[i]+nz_offset, arg[i]+nz_offset+nnz, w1);
1300 casadi_int nnz=a.data.dep().nnz();
1301 casadi_int i=a.data->ind();
1302 casadi_int nz_offset=a.data->offset();
1303 if (res[i]) std::copy(w1, w1+nnz, res[i]+nz_offset);
1308 for (casadi_int i=0; i<a.arg.size(); ++i)
1309 argp[i] = a.arg[i]>=0 ? w+
workloc_[a.arg[i]] :
nullptr;
1310 for (casadi_int i=0; i<a.res.size(); ++i)
1311 resp[i] = a.res[i]>=0 ? w+
workloc_[a.res[i]] :
nullptr;
1314 if (a.data->eval_sx(
get_ptr(argp),
get_ptr(resp), iw, w))
return 1;
1324 casadi_error(
"Code generation of '" +
name_ +
"' is not possible since variables "
1330 a.data->add_dependency(g);
1336 std::set<void*> added;
1338 a.data->codegen_incref(g, added);
1344 std::set<void*> added;
1346 a.data->codegen_decref(g, added);
1361 std::vector<casadi_int> arg, res;
1364 std::vector<bool> work_is_ref(
workloc_.size()-1,
false);
1367 std::vector<bool> arg_is_ref, res_is_ref;
1370 std::vector<bool> needs_reference(
workloc_.size()-1,
false);
1371 std::vector<bool> needs_value(
workloc_.size()-1,
false);
1377 g <<
"/* #" << k <<
": " <<
print(e) <<
" */\n";
1381 arg.resize(e.arg.size());
1382 arg_is_ref.resize(e.arg.size());
1383 for (casadi_int i=0; i<e.arg.size(); ++i) {
1384 casadi_int j=e.arg.at(i);
1387 arg_is_ref.at(i) = work_is_ref.at(j);
1390 arg_is_ref.at(i) =
false;
1395 res.resize(e.res.size());
1396 for (casadi_int i=0; i<e.res.size(); ++i) {
1397 casadi_int j=e.res.at(i);
1405 res_is_ref.resize(e.res.size());
1407 std::fill(res_is_ref.begin(), res_is_ref.end(),
false);
1414 e.data->generate(g, arg, res, arg_is_ref, res_is_ref);
1416 for (casadi_int i=0; i<e.res.size(); ++i) {
1417 casadi_int j=e.res.at(i);
1419 work_is_ref.at(j) = res_is_ref.at(i);
1420 if (res_is_ref.at(i)) {
1421 needs_reference[j] =
true;
1423 needs_value[j] =
true;
1437 std::vector<casadi_int> cg_off(
workloc_.size()-1, 0);
1438 casadi_int cg_wind =
workloc_.front();
1439 for (casadi_int i=0; i<
workloc_.size()-1; ++i) {
1441 cg_off[i] = cg_wind;
1442 if (n==0 || !needs_value[i])
continue;
1449 for (casadi_int i=0; i<
workloc_.size()-1; ++i) {
1462 if (needs_value[i]) {
1466 if (needs_reference[i]) {
1476 return this->
sz_w();
1480 std::vector<MX> swork(
workloc_.size()-1);
1482 std::vector<MX> arg1, res1;
1485 std::vector<std::vector<MX> > in_split(
in_.size());
1486 for (casadi_int i=0; i<
in_.size(); ++i) in_split[i] =
in_[i].primitives();
1491 std::vector<std::vector<MX> > f_G(
out_.size());
1492 for (casadi_int i=0; i<
out_.size(); ++i) f_G[i].resize(
out_[i].n_primitives());
1495 std::vector<MX> x_init;
1498 std::stringstream ss;
1500 for (casadi_int algNo=0; algNo<2; ++algNo) {
1505 MX& arg = swork[e.arg.at(0)];
1506 MX& arg_init = swork[e.arg.at(1)];
1507 MX& res = swork[e.res.front()];
1510 ss.str(std::string());
1511 ss <<
"y" << y.
size();
1517 x_init.push_back(arg_init);
1524 swork[e.res.front()] = in_split.at(e.data->ind()).at(e.data->segment());
1527 swork[e.res.front()] = e.data;
1531 f_G.at(e.data->ind()).at(e.data->segment()) = swork[e.arg.front()];
1537 arg1.resize(e.arg.size());
1538 for (casadi_int i=0; i<arg1.size(); ++i) {
1539 casadi_int el = e.arg[i];
1540 arg1[i] = el<0 ?
MX(e.data->dep(i).size()) : swork[el];
1544 res1.resize(e.res.size());
1545 e.data->eval_mx(arg1, res1);
1548 for (casadi_int i=0; i<res1.size(); ++i) {
1549 casadi_int el = e.res[i];
1550 if (el>=0) swork[el] = res1[i];
1558 std::vector<MX> f_in =
in_;
1559 f_in.insert(f_in.end(), y.begin(), y.end());
1560 std::vector<MX> f_out;
1561 for (casadi_int i=0; i<
out_.size(); ++i) f_out.push_back(
out_[i].join_primitives(f_G[i]));
1562 f_out.insert(f_out.end(), g.begin(), g.end());
1563 vdef_fcn =
Function(
"lifting_variable_definition", f_in, f_out);
1568 vinit_fcn =
Function(
"lifting_variable_guess", f_in, f_out);
1580 return type==
"MXFunction"
1586 std::vector<MX> work(
workloc_.size()-1);
1587 std::vector<MX> oarg, ores;
1590 std::vector<std::vector<MX>> out_split(
out_.size());
1591 for (casadi_int i = 0; i < out_split.size(); ++i) out_split[i].resize(
out_[i].n_primitives());
1597 casadi_assert(it->data->segment()==0,
"Not implemented");
1598 work.at(it->res.front())
1599 =
out_.at(it->data->ind()).join_primitives(out_split.at(it->data->ind()));
1603 work.at(it->res.front()) = it->data;
1606 out_split.at(it->data->ind()).at(it->data->segment()) = work.at(it->arg.front());
1611 oarg.resize(it->arg.size());
1612 for (casadi_int i=0; i<oarg.size(); ++i) {
1613 casadi_int el = it->arg[i];
1614 oarg[i] = el<0 ?
MX(it->data->dep(i).size()) : work.at(el);
1618 ores.resize(it->res.size());
1619 it->data->eval_mx(oarg, ores);
1622 for (casadi_int i=0; i<ores.size(); ++i) {
1623 casadi_int el = it->res[i];
1624 if (el>=0) work.at(el) = ores[i];
1630 for (
size_t k = 0; k < out_split.size(); ++k) {
1631 MX a =
out_.at(k).join_primitives(out_split.at(k));
1632 if (k < vdef.size()) {
1635 ex.at(k - vdef.size()) = a;
1642 casadi_assert(!(always_inline && never_inline),
1644 casadi_assert(!(never_inline &&
has_free()),
1646 if (always_inline)
return true;
1647 if (never_inline)
return false;
1655 std::ostream &ss,
const Dict& options)
const {
1658 casadi_int indent_level = 0;
1661 for (
auto&& op : options) {
1662 if (op.first==
"indent_level") {
1663 indent_level = op.second;
1665 casadi_error(
"Unknown option '" + op.first +
"'.");
1671 for (casadi_int i=0;i<indent_level;++i) {
1675 Function f = shared_from_this<Function>();
1690 ss << indent <<
"w" << o[0] <<
" = varargin{" << i[0]+1 <<
"};" << std::endl;
1695 casadi_int segment =
info[
"segment"];
1697 {{
"name",
"sp_in"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1698 ss << indent <<
"argout_" << o[0] <<
"{" << (1+segment) <<
"} = ";
1699 ss <<
"w" << i[0] <<
"(sp_in==1);" << std::endl;
1704 DM v =
static_cast<DM>(x);
1707 opts[
"indent_level"] = indent_level;
1709 ss << indent <<
"w" << o[0] <<
" = m;" << std::endl;
1713 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".^2;" << std::endl;
1716 ss << indent <<
"w" << o[0] <<
" = ";
1717 ss <<
"w" << i[1] <<
"*w" << i[2] <<
"+w" << i[0] <<
";" << std::endl;
1722 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] << prefix <<
"*w" << i[1] <<
";";
1727 ss << indent <<
"w" << o[0] <<
" = 2*w" << i[0] <<
";" << std::endl;
1730 ss << indent <<
"w" << o[0] <<
" = 1./w" << i[0] <<
";" << std::endl;
1733 ss << indent <<
"w" << o[0] <<
" = dot(w" << i[0] <<
",w" << i[1]<<
");" << std::endl;
1736 ss << indent <<
"w" << o[0] <<
" = w" << i[1] <<
".'*w" << i[0]<<
"*w" << i[2] <<
";";
1740 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
"+";
1741 ss <<
"w" << i[1] <<
"*w" << i[2] <<
"*w" << i[3] <<
".';";
1745 ss << indent <<
"w" << o[0] <<
" = abs(w" << i[0] <<
");" << std::endl;
1748 ss << indent <<
"w" << o[0] <<
" = det(w" << i[0] <<
");" << std::endl;
1751 ss << indent <<
"w" << o[0] <<
" = inv(w" << i[0] <<
");";
1752 ss <<
"w" << o[0] <<
"(w" << o[0] <<
"==0) = 1e-200;" << std::endl;
1756 bool tr = x.
info()[
"tr"];
1758 ss << indent <<
"w" << o[0] <<
" = ((w" << i[1] <<
".')\\w" << i[0] <<
").';";
1761 ss << indent <<
"w" << o[0] <<
" = w" << i[1] <<
"\\w" << i[0] <<
";" << std::endl;
1763 ss <<
"w" << o[0] <<
"(w" << o[0] <<
"==0) = 1e-200;" << std::endl;
1769 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] << prefix <<
"/w" << i[1] <<
";";
1775 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".^w" << i[1] <<
";" << std::endl;
1778 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".';" << std::endl;
1783 ss << indent <<
"w" << o[0] <<
" = [";
1784 for (casadi_int e : i) {
1785 ss <<
"w" << e << (op==
OP_HORZCAT ?
" " :
";");
1787 ss <<
"];" << std::endl;
1792 for (casadi_int k=0;k<i.size();++k) {
1794 {{
"name",
"sp_in" +
str(k)}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1796 ss << indent <<
"w" << o[0] <<
" = [";
1797 for (casadi_int k=0;k<i.size();++k) {
1798 ss <<
"w" << i[k] <<
"(sp_in" << k <<
"==1);";
1800 ss <<
"];" << std::endl;
1802 opts[
"name"] =
"sp";
1803 opts[
"indent_level"] = indent_level;
1804 opts[
"as_matrix"] =
false;
1806 ss << indent <<
"w" << o[0] <<
" = ";
1807 ss <<
"sparse(sp_i, sp_j, w" << o[0] <<
", sp_m, sp_n);" << std::endl;
1814 std::vector<casadi_int> offset =
info[
"offset"];
1816 std::vector<Sparsity> sp;
1817 for (casadi_int i=0;i<output.n_out();i++)
1818 sp.push_back(output.sparsity_out(i));
1819 for (casadi_int k=0;k<o.size();++k) {
1820 if (o[k]==-1)
continue;
1822 {{
"name",
"sp_in"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1823 ss << indent <<
"tmp = w" << i[0]<<
"(sp_in==1);" << std::endl;
1825 opts[
"name"] =
"sp";
1826 opts[
"indent_level"] = indent_level;
1827 opts[
"as_matrix"] =
false;
1828 sp[k].export_code(
"matlab", ss, opts);
1829 ss << indent <<
"w" << o[k] <<
" = sparse(sp_i, sp_j, ";
1830 ss <<
"tmp(" << offset[k]+1 <<
":" << offset[k+1] <<
"), sp_m, sp_n);" << std::endl;
1839 std::string nonzeros;
1841 nonzeros =
"1+" +
str(
info[
"nz"]);
1842 }
else if (
info.find(
"slice")!=
info.end()) {
1844 casadi_int start = s[
"start"];
1845 casadi_int step = s[
"step"];
1846 casadi_int stop = s[
"stop"];
1847 nonzeros =
str(start+1) +
":" +
str(step) +
":" +
str(stop);
1848 nonzeros =
"nonzeros(" + nonzeros +
")";
1852 casadi_int inner_start = inner[
"start"];
1853 casadi_int inner_step = inner[
"step"];
1854 casadi_int inner_stop = inner[
"stop"];
1855 casadi_int outer_start = outer[
"start"];
1856 casadi_int outer_step = outer[
"step"];
1857 casadi_int outer_stop = outer[
"stop"];
1858 std::string inner_slice =
"(" +
str(inner_start) +
":" +
1859 str(inner_step) +
":" +
str(inner_stop-1)+
")";
1860 std::string outer_slice =
"(" +
str(outer_start+1) +
":" +
1861 str(outer_step) +
":" +
str(outer_stop)+
")";
1862 casadi_int N =
range(outer_start, outer_stop, outer_step).size();
1863 casadi_int M =
range(inner_start, inner_stop, inner_step).size();
1864 nonzeros =
"repmat("+ inner_slice +
"', 1, " +
str(N) +
")+" +
1865 "repmat("+ outer_slice +
", " +
str(M) +
", 1)";
1866 nonzeros =
"nonzeros(" + nonzeros +
")";
1870 opts[
"name"] =
"sp";
1871 opts[
"indent_level"] = indent_level;
1872 opts[
"as_matrix"] =
false;
1877 {{
"name",
"sp_in"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1880 ss << indent <<
"in_flat = w" << i[0] <<
"(sp_in==1);" << std::endl;
1883 ss << indent <<
"w" << o[0] <<
" = in_flat(" << nonzeros <<
");" << std::endl;
1886 {{
"name",
"sp_in0"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1888 {{
"name",
"sp_in1"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1889 ss << indent <<
"in_flat = w" << i[1] <<
"(sp_in1==1);" << std::endl;
1890 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
"(sp_in0==1);" << std::endl;
1891 ss << indent <<
"w" << o[0] <<
"(" << nonzeros <<
") = ";
1892 if (
info[
"add"]) ss <<
"w" << o[0] <<
"(" << nonzeros <<
") + ";
1895 ss << indent <<
"w" << o[0] <<
" = ";
1896 ss <<
"sparse(sp_i, sp_j, w" << o[0] <<
", sp_m, sp_n);" << std::endl;
1902 opts[
"name"] =
"sp";
1903 opts[
"indent_level"] = indent_level;
1905 ss << indent <<
"w" << o[0] <<
" = ";
1906 ss <<
"sparse(sp_i, sp_j, w" << i[0] <<
"(sp==1), sp_m, sp_n);" << std::endl;
1910 ss << indent <<
"w" << o[0] <<
" = norm(w" << i[0] <<
", 1);" << std::endl;
1913 ss << indent <<
"w" << o[0] <<
" = norm(w" << i[0] <<
", 2);" << std::endl;
1916 ss << indent <<
"w" << o[0] <<
" = norm(w" << i[0] <<
", 'fro');" << std::endl;
1919 ss << indent <<
"w" << o[0] <<
" = norm(w" << i[0] <<
", inf);" << std::endl;
1922 ss << indent <<
"w" << o[0] <<
" = min(w" << i[0] <<
");" << std::endl;
1925 ss << indent <<
"w" << o[0] <<
" = max(w" << i[0] <<
");" << std::endl;
1928 ss << indent <<
"w" << o[0] <<
" = ~" <<
"w" << i[0] <<
";" << std::endl;
1931 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" | w" << i[1] <<
";" << std::endl;
1934 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" & w" << i[1] <<
";" << std::endl;
1937 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" ~= w" << i[1] <<
";" << std::endl;
1940 ss << indent <<
"w" << o[0] <<
" = ";
1941 ss <<
"if_else_zero_gen(w" << i[0] <<
", w" << i[1] <<
");" << std::endl;
1946 {{
"name",
"sp_in"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1948 {{
"name",
"sp_out"}, {
"indent_level", indent_level}, {
"as_matrix",
false}});
1949 ss << indent <<
"w" << o[0] <<
" = sparse(sp_out_i, sp_out_j, ";
1950 ss <<
"w" << i[0] <<
"(sp_in==1), sp_out_m, sp_out_n);" << std::endl;
1956 "w"+std::to_string(i[0]),
"w"+std::to_string(i[1])) <<
";" << std::endl;
1959 "w"+std::to_string(i[0])) <<
";" << std::endl;
1961 ss <<
"unknown" + x.
class_name() << std::endl;
1973 Function d = e.data.which_function();
1974 if (d.
is_a(
"Conic",
true) || d.
is_a(
"Nlpsol")) {
1975 if (!dep.
is_null())
return stats;
1980 if (dep.
is_null())
return stats;
1981 return dep.
stats(1);
1992 s.
pack(
"MXFunction::alg::data", e.data);
1993 s.
pack(
"MXFunction::alg::arg", e.arg);
1994 s.
pack(
"MXFunction::alg::res", e.res);
2009 int version = s.
version(
"MXFunction", 1, 3);
2017 s.
unpack(
"MXFunction::alg::arg", e.
arg);
2018 s.
unpack(
"MXFunction::alg::res", e.
res);
2038 casadi_int max_depth)
const {
2048 if (option_name ==
"print_instructions") {
2050 }
else if (option_name ==
"dump_trace") {
2051 bool value = option_value;
2052 casadi_assert(!value || !
jit_,
"dump_trace is not supported for JIT evaluation");
2061 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
2062 std::lock_guard<std::mutex> lock(MX::get_mutex_temp());
2065 std::stack<MXNode*> s;
2068 std::vector<MXNode*> nodes;
2071 for (casadi_int ind=0; ind<expr.size(); ++ind) {
2073 std::vector<MX> prim = expr[ind].primitives();
2074 for (casadi_int p=0; p<prim.size(); ++p) {
2076 s.push(prim[p].get());
2082 for (casadi_int i=0; i<nodes.size(); ++i) {
2086 std::vector<MX> ret(nodes.size());
2087 for (casadi_int i=0; i<nodes.size(); ++i) {
2088 ret[i].own(nodes[i]);
Helper class for C code generation.
bool codegen_scalars
Codegen scalar.
std::string work(casadi_int n, casadi_int sz, bool is_ref) const
void reserve_work(casadi_int n)
Reserve a maximum size of work elements, used for padding of index.
std::string printf(const std::string &str, const std::vector< std::string > &arg=std::vector< std::string >())
Printf.
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
void init_local(const std::string &name, const std::string &def)
Specify the default value for a local variable.
bool get_codegen_sz_w(const FunctionInternal *f, size_t &sz_w) const
Retrieve a work vector size registered by set_codegen_sz_w.
void set_codegen_sz_w(const FunctionInternal *f, size_t sz_w)
Register the work vector size a function needs in generated code.
std::string print_canonical(const Sparsity &sp, const std::string &arg)
Print canonical representaion of a matrix.
std::string format_padded(casadi_int i) const
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.
bool has_refcount_
Reference counting in codegen?
void finish_trace(std::ostream &trace, double **res, int ret) const
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
Dict get_stats(void *mem) const override
Get all statistics.
virtual void call_forward(const std::vector< MX > &arg, const std::vector< MX > &res, const std::vector< std::vector< MX > > &fseed, std::vector< std::vector< MX > > &fsens, bool always_inline, bool never_inline) const
Forward mode AD, virtual functions overloaded in derived classes.
virtual void codegen_decref(CodeGenerator &g) const
Codegen decref for dependencies.
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::pair< casadi_int, casadi_int > size_in(casadi_int ind) const
Input/output dimensions.
std::string definition() const
Get function signature: name:(inputs)->(outputs)
virtual void call_reverse(const std::vector< MX > &arg, const std::vector< MX > &res, const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens, bool always_inline, bool never_inline) const
Reverse mode, virtual functions overloaded in derived classes.
void alloc_arg(size_t sz_arg, bool persistent=false)
Ensure required length of arg field.
static void print_canonical(std::ostream &stream, const Sparsity &sp, const double *nz)
Print canonical representation of a numeric matrix.
bool jit_
Use just-in-time compiler.
void add_embedded(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, const Function &dep, casadi_int max_depth) const
virtual void find(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, casadi_int max_depth) const
virtual double sp_weight() const
Weighting factor for chosing forward/reverse mode,.
size_t n_in_
Number of inputs and outputs.
size_t sz_res() const
Get required length of res field.
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.
std::pair< casadi_int, casadi_int > size_out(casadi_int ind) const
Input/output dimensions.
virtual int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const
Propagate sparsity forward.
static const Options options_
Options.
bool matching_res(const std::vector< M > &arg, casadi_int &npar) const
Check if output arguments that needs to be replaced.
void disp(std::ostream &stream, bool more) const override
Display object.
size_t sz_w() const
Get required length of w field.
virtual int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const
Propagate sparsity backwards.
std::unique_ptr< std::ostream > open_trace(const double **arg, casadi_int dump_id) const
virtual Dict info() const
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
size_t sz_arg() const
Get required length of arg field.
void setup(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const
Set the (persistent and temporary) work vectors.
static void trace_values(std::ostream &trace, const double *values, casadi_int nnz)
virtual std::vector< MX > symbolic_output(const std::vector< MX > &arg) const
Get a vector of symbolic variables corresponding to the outputs.
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.
static bool purgable(const std::vector< MatType > &seed)
Can a derivative direction be skipped.
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.
virtual void codegen_incref(CodeGenerator &g) const
Codegen incref for dependencies.
casadi_int n_instructions() const
Number of instruction in the algorithm (SXFunction/MXFunction)
const std::string & name() const
Name of the function.
std::vector< casadi_int > instruction_input(casadi_int k) const
Locations in the work vector for the inputs of the instruction.
std::vector< casadi_int > instruction_output(casadi_int k) const
Location in the work vector for the output of the instruction.
MX instruction_MX(casadi_int k) const
Get the MX node corresponding to an instruction (MXFunction)
bool is_a(const std::string &type, bool recursive=true) const
Check if the function is of a particular type.
Dict stats(int mem=0) const
Get all statistics obtained at the end of the last evaluate call.
casadi_int instruction_id(casadi_int k) const
Identifier index of the instruction (SXFunction/MXFunction)
std::pair< casadi_int, casadi_int > size() const
Get the shape.
casadi_int nnz() const
Get the number of (structural) non-zero elements.
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
bool is_scalar(bool scalar_and_dense=false) const
Check if the matrix expression is scalar.
bool is_null() const
Is a null pointer?
Generic data type, can hold different types such as bool, casadi_int, std::string etc.
An input or output instruction.
static void check()
Raises an error if an interrupt was captured.
Internal node class for MXFunction.
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
static const Options options_
Options.
std::vector< casadi_int > workloc_
Offsets for elements in the w_ vector.
bool live_variables_
Live variables?
MX instruction_MX(casadi_int k) const override
get MX expression associated with instruction
std::vector< casadi_int > instruction_output(casadi_int k) const override
Get the (integer) output argument of an atomic operation.
std::vector< double > default_in_
Default input values.
void change_option(const std::string &option_name, const GenericType &option_value) override
Change option after object creation for debugging.
std::vector< std::string > get_function() const override
Get list of dependency functions.
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity backwards.
const std::vector< MX > mx_in() const override
Get function input(s) and output(s)
void trace_instruction(std::ostream &trace, casadi_int k, const double *w, bool output) const
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
Work vector size of the generated code.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void init(const Dict &opts) override
Initialize.
int eval_activity(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate signal activity forward.
void print_arg(std::ostream &stream, casadi_int k, const AlgEl &el, const double **arg) const
void ad_reverse(const std::vector< std::vector< MX > > &adjSeed, std::vector< std::vector< MX > > &adjSens) const
Calculate reverse mode directional derivatives.
MXFunction(const std::string &name, const std::vector< MX > &input, const std::vector< MX > &output, const std::vector< std::string > &name_in, const std::vector< std::string > &name_out)
Constructor.
void codegen_decref(CodeGenerator &g) const override
Codegen decref for dependencies.
std::vector< std::string > get_free() const override
Print free variables.
~MXFunction() override
Destructor.
std::string print(const AlgEl &el) const
bool has_free() const override
Does the function have free variables.
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate numerically, work vectors given.
void disp_more(std::ostream &stream) const override
Print description.
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
bool print_instructions_
Print instructions during evaluation.
void substitute_inplace(std::vector< MX > &vdef, std::vector< MX > &ex) const
Substitute inplace, internal implementation.
std::vector< casadi_int > instruction_input(casadi_int k) const override
Get the (integer) input arguments of an atomic operation.
void find(std::map< FunctionInternal *, std::pair< Function, size_t > > &all_fun, casadi_int max_depth) const override
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w, void *mem, bool always_inline, bool never_inline) const override
Evaluate symbolically, SX type.
casadi_int n_instructions() const override
Get the number of atomic operations.
void codegen_incref(CodeGenerator &g) const override
Codegen incref for dependencies.
bool should_inline(bool with_sx, bool always_inline, bool never_inline) const override
std::vector< AlgEl > algorithm_
All the runtime elements in the order of evaluation.
void eval_mx(const MXVector &arg, MXVector &res, bool always_inline, bool never_inline) const override
Evaluate symbolically, MX type.
static std::vector< MX > order(const std::vector< MX > &expr)
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
void print_res(std::ostream &stream, casadi_int k, const AlgEl &el, double **res) const
void ad_forward(const std::vector< std::vector< MX > > &fwdSeed, std::vector< std::vector< MX > > &fwdSens) const
Calculate forward mode directional derivatives.
std::vector< MX > free_vars_
Free variables.
Dict generate_options(const std::string &target="clone") const override
Reconstruct options dict.
void generate_lifted(Function &vdef_fcn, Function &vinit_fcn) const override
Extract the residual function G and the modified function Z out of an expression.
std::vector< MX > symbolic_output(const std::vector< MX > &arg) const override
Get a vector of symbolic variables corresponding to the outputs.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Dict get_stats(void *mem) const override
Get all statistics.
void export_code_body(const std::string &lang, std::ostream &stream, const Dict &options) const override
Export function in a specific language.
Node class for MX objects.
virtual casadi_int ind() const
const Sparsity & sparsity() const
Get the sparsity.
const MX & dep(casadi_int ind=0) const
dependencies - functions that have to be evaluated before this one
virtual casadi_int segment() const
virtual std::string disp(const std::vector< std::string > &arg) const =0
Print expression.
static MX create(MXNode *node)
Create from node.
const Sparsity & sparsity() const
Get the sparsity pattern.
MX dep(casadi_int ch=0) const
Get the nth dependency as MX.
bool is_binary() const
Is binary operation.
bool is_unary() const
Is unary operation.
casadi_int op() const
Get operation type.
static void print_default(std::ostream &stream, const Sparsity &sp, const double *nonzeros, bool truncate=true)
Print default style.
void export_code(const std::string &lang, std::ostream &stream=casadi::uout(), const Dict &options=Dict()) const
Export matrix in specific language.
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.
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
std::string class_name() const
Get class name.
casadi_int nnz() const
Get the number of (structural) non-zeros.
void export_code(const std::string &lang, std::ostream &stream=casadi::uout(), const Dict &options=Dict()) const
Export matrix in specific language.
Internal node class for the base class of SXFunction and MXFunction.
std::vector< MX > out_
Outputs of the function (needed for symbolic calculations)
void delayed_deserialize_members(DeserializingStream &s)
void init(const Dict &opts) override
Initialize.
virtual bool isInput(const std::vector< MX > &arg) const
Helper function: Check if a vector equals ex_in.
std::vector< MX > 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< MXNode * > &s, std::vector< MXNode * > &nodes)
Topological sorting of the nodes based on Depth-First Search (DFS)
bool is_equal(double x, double y, casadi_int depth=0)
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
std::string join(const std::vector< std::string > &l, const std::string &delim)
unsigned long long bvec_t
std::vector< MX > MXVector
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
Function memory with temporary work vectors.
An element of the algorithm, namely an MX node.
MX data
Data associated with the operation.
std::vector< casadi_int > arg
Work vector indices of the arguments.
casadi_int op
Operator index.
std::vector< casadi_int > res
Work vector indices of the results.
Options metadata for a class.
static std::string print(unsigned char op, const std::string &x, const std::string &y)
Print.