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"}},
63 {
"print_instructions",
65 "Print each operation during evaluation. Influenced by print_canonical."}},
68 "Perform common subexpression elimination (complexity is N*log(N) in graph size)"}},
71 "Allow construction with free variables (Default: false)"}},
72 {
"allow_duplicate_io_names",
74 "Allow construction with duplicate io names (Default: false)"}}
80 if (target==
"clone") opts[
"default_in"] =
default_in_;
104 return { io->
ind() };
118 bool cse_opt =
false;
119 bool allow_free =
false;
122 for (
auto&& op : opts) {
123 if (op.first==
"default_in") {
125 }
else if (op.first==
"live_variables") {
127 }
else if (op.first==
"print_instructions") {
129 }
else if (op.first==
"cse") {
131 }
else if (op.first==
"allow_free") {
132 allow_free = op.second;
141 "Option 'default_in' has incorrect length");
145 for (
const MX& e :
out_) {
146 casadi_assert(!e->has_output(),
147 "Function output contains MultiOutput nodes. "
148 "You must use get_output() to make a concrete instance.");
154 std::stack<MXNode*> s;
157 std::vector<MXNode*> nodes;
158 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
159 std::lock_guard<std::mutex> lock(MX::get_mutex_temp());
163 for (casadi_int ind=0; ind<
out_.size(); ++ind) {
165 std::vector<MX> prim =
out_[ind].primitives();
166 casadi_int nz_offset=0;
167 for (casadi_int p=0; p<prim.size(); ++p) {
169 s.push(prim[p].get());
172 nodes.push_back(
new Output(prim[p], ind, p, nz_offset));
174 nz_offset += prim[p].nnz();
179 for (casadi_int i=0; i<nodes.size(); ++i) {
184 std::vector<casadi_int> place_in_alg;
185 place_in_alg.reserve(nodes.size());
188 std::vector<std::pair<casadi_int, MXNode*> > symb_loc;
191 std::vector<casadi_int> refcount(nodes.size(), 0);
199 casadi_int op = n->op();
203 symb_loc.push_back(std::make_pair(
algorithm_.size(), n));
211 ae.
arg.resize(n->n_dep());
212 for (casadi_int i=0; i<n->n_dep(); ++i) {
213 ae.
arg[i] = n->dep(i)->temp;
215 ae.
res.resize(n->nout());
216 if (n->has_output()) {
217 std::fill(ae.
res.begin(), ae.
res.end(), -1);
218 }
else if (!ae.
res.empty()) {
223 for (casadi_int c=0; c<ae.
arg.size(); ++c) {
225 refcount[ae.
arg[c]]++;
235 casadi_int oind = n->which_output();
238 casadi_int pind = place_in_alg[n->dep(0)->temp];
241 casadi_int& otmp =
algorithm_[pind].res.at(oind);
249 place_in_alg.push_back(-1);
254 std::vector<casadi_int>& place = place_in_alg;
255 place.resize(nodes.size());
258 SPARSITY_MAP<casadi_int, std::stack<casadi_int> > unused_all;
261 casadi_int worksize = 0;
268 casadi_int first_to_free = 0;
269 casadi_int last_to_free = e.data->n_inplace();
270 for (casadi_int task=0; task<2; ++task) {
273 for (casadi_int c=last_to_free-1; c>=first_to_free; --c) {
278 casadi_int& ch_ind = e.arg[c];
283 casadi_int remaining = --refcount[ch_ind];
289 casadi_int nnz = nodes[ch_ind]->sparsity().nnz();
292 unused_all[nnz].push(place[ch_ind]);
296 ch_ind = place[ch_ind];
304 first_to_free = last_to_free;
305 last_to_free = e.arg.size();
308 for (casadi_int c=0; c<e.res.size(); ++c) {
314 casadi_int nnz = e.data->sparsity(c).nnz();
317 std::stack<casadi_int>& unused = unused_all[nnz];
320 if (!unused.empty()) {
321 e.res[c] = place[e.res[c]] = unused.top();
328 e.res[c] = place[e.res[c]] = worksize++;
336 casadi_message(
"Using live variables: work array is " +
str(worksize)
337 +
" instead of " +
str(nodes.size()));
339 casadi_message(
"Live variables disabled.");
346 size_t wind=0,
sz_w=0;
349 for (casadi_int c=0; c<e.res.size(); ++c) {
356 sz_w = std::max(
sz_w, std::max(e.data->sz_w(), e.data->codegen_sz_w()));
359 wind += e.data->sparsity(c).nnz();
366 for (casadi_int i=0; i<
workloc_.size(); ++i) {
374 for (casadi_int i=0; i<nodes.size(); ++i) {
381 for (
auto it=symb_loc.begin(); it!=symb_loc.end(); ++it) {
382 it->second->temp = it->first+1;
386 for (casadi_int ind=0; ind<
in_.size(); ++ind) {
388 std::vector<MX> prim =
in_[ind].primitives();
389 casadi_int nz_offset=0;
390 for (casadi_int p=0; p<prim.size(); ++p) {
391 casadi_int i = prim[p].get_temp()-1;
397 algorithm_[i].data.own(
new Input(prim[p].sparsity(), ind, p, nz_offset));
400 nz_offset += prim[p]->nnz();
406 for (
auto it=symb_loc.begin(); it!=symb_loc.end(); ++it) {
407 casadi_int i = it->second->temp-1;
418 casadi_error(
name_ +
"::init: Initialization failed since variables [" +
419 join(
get_free(),
", ") +
"] are free. These symbols occur in the output expressions "
420 "but you forgot to declare these as inputs. "
421 "Set option 'allow_free' to allow free variables.");
427 if (a.data->has_refcount()) {
436 casadi_int* iw,
double* w,
void* mem)
const {
438 setup(mem, arg, res, iw, w);
440 const double** arg1 = arg+
n_in_;
441 double** res1 = res+
n_out_;
445 std::stringstream ss;
447 casadi_error(
"Cannot evaluate \"" + ss.str() +
"\" since variables "
460 double *w1 = w+
workloc_[e.res.front()];
461 casadi_int nnz=e.data.nnz();
462 casadi_int i=e.data->ind();
463 casadi_int nz_offset=e.data->offset();
464 if (arg[i]==
nullptr) {
465 std::fill(w1, w1+nnz, 0);
467 std::copy(arg[i]+nz_offset, arg[i]+nz_offset+nnz, w1);
471 double *w1 = w+
workloc_[e.arg.front()];
472 casadi_int nnz=e.data->dep().nnz();
473 casadi_int i=e.data->ind();
474 casadi_int nz_offset=e.data->offset();
475 if (res[i]) std::copy(w1, w1+nnz, res[i]+nz_offset);
478 for (casadi_int i=0; i<e.arg.size(); ++i)
479 arg1[i] = e.arg[i]>=0 ? w+
workloc_[e.arg[i]] :
nullptr;
480 for (casadi_int i=0; i<e.res.size(); ++i)
481 res1[i] = e.res[i]>=0 ? w+
workloc_[e.res[i]] :
nullptr;
485 if (e.data->eval(arg1, res1, iw, w))
return 1;
498 <<
" = @" << el.
arg.at(0);
500 if (el.
res.front()!=el.
arg.at(0)) {
501 s <<
"@" << el.
res.front() <<
" = @" << el.
arg.at(0) <<
"; ";
503 std::vector<std::string> arg(2);
504 arg[0] =
"@" +
str(el.
res.front());
505 arg[1] =
"@" +
str(el.
arg.at(1));
508 if (el.
res.size()==1) {
509 s <<
"@" << el.
res.front() <<
" = ";
512 for (casadi_int i=0; i<el.
res.size(); ++i) {
515 s <<
"@" << el.
res[i];
522 std::vector<std::string> arg;
524 arg.resize(el.
arg.size());
525 for (casadi_int i=0; i<el.
arg.size(); ++i) {
527 arg[i] =
"@" +
str(el.
arg[i]);
539 const double** arg)
const {
540 stream <<
name_ <<
":" << k <<
": " <<
print(el) <<
" inputs:" << std::endl;
541 for (
size_t i = 0; i < el.
arg.size(); ++i) {
555 const std::vector<casadi_int>& arg,
const std::vector<bool>& arg_is_ref)
const {
557 for (
size_t i = 0; i < el.
arg.size(); ++i) {
560 std::string a = g.
work(arg[i], el.
data->
dep(i).
nnz(), arg_is_ref[i]);
562 g << g.
printf(
"\\n") <<
"\n";
568 const std::vector<casadi_int>& res,
const std::vector<bool>& res_is_ref)
const {
570 for (
size_t i = 0; i < el.
res.size(); ++i) {
575 g << g.
printf(
"\\n") <<
"\n";
581 double** res)
const {
582 stream <<
name_ <<
":" << k <<
": " <<
print(el) <<
" outputs:" << std::endl;
583 for (
size_t i = 0; i < el.
res.size(); ++i) {
597 stream <<
"Algorithm:";
600 stream << std::endl <<
print(e);
617 casadi_int nnz=e.data.nnz();
618 casadi_int i=e.data->ind();
619 casadi_int nz_offset=e.data->offset();
620 const bvec_t* argi = arg[i];
623 std::copy(argi+nz_offset, argi+nz_offset+nnz, w1);
625 std::fill_n(w1, nnz, 0);
629 casadi_int nnz=e.data.dep().nnz();
630 casadi_int i=e.data->ind();
631 casadi_int nz_offset=e.data->offset();
635 std::copy(w1, w1+nnz, resi+nz_offset);
636 }
else if (resi!=
nullptr) {
637 std::fill_n(resi+nz_offset, nnz, 0);
641 for (casadi_int i=0; i<e.arg.size(); ++i)
642 arg1[i] = e.arg[i]>=0 ? w+
workloc_[e.arg[i]] :
nullptr;
643 for (casadi_int i=0; i<e.res.size(); ++i)
644 res1[i] = e.res[i]>=0 ? w+
workloc_[e.res[i]] :
nullptr;
647 if (e.data->sp_forward(arg1, res1, iw, w))
return 1;
662 casadi_int nnz=e.data.nnz();
663 casadi_int i=e.data->ind();
664 casadi_int nz_offset=e.data->offset();
665 const bvec_t* argi = arg[i];
668 std::copy(argi+nz_offset, argi+nz_offset+nnz, w1);
670 std::fill_n(w1, nnz, 0);
673 casadi_int nnz=e.data.dep().nnz();
674 casadi_int i=e.data->ind();
675 casadi_int nz_offset=e.data->offset();
678 if (resi!=
nullptr) std::copy(w1, w1+nnz, resi+nz_offset);
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;
684 if (e.data->eval_activity(arg1, res1, iw, w))
return 1;
691 std::map<std::string, bool> flagged;
694 const Function &f = it->data->which_function();
695 if (flagged.find(f.
name())==flagged.end()) {
696 flagged[f.
name()] =
true;
700 std::vector<std::string> ret;
701 for (
auto it : flagged) {
702 ret.push_back(it.first);
710 const Function &f = it->data->which_function();
711 if (name==f.
name())
return f;
714 casadi_error(
"No such function '" + name +
"'.");
718 casadi_int* iw,
bvec_t* w,
void* mem)
const {
726 std::fill_n(w,
sz_w(), 0);
732 casadi_int nnz=it->data.nnz();
733 casadi_int i=it->data->ind();
734 casadi_int nz_offset=it->data->offset();
738 for (casadi_int k=0; k<nnz; ++k) argi[nz_offset+k] |= w1[k];
739 std::fill_n(w1, nnz, 0);
742 casadi_int nnz=it->data.dep().nnz();
743 casadi_int i=it->data->ind();
744 casadi_int nz_offset=it->data->offset();
745 bvec_t* resi = res[i] ? res[i] + nz_offset :
nullptr;
748 for (casadi_int k=0; k<nnz; ++k) w1[k] |= resi[k];
749 std::fill_n(resi, nnz, 0);
753 for (casadi_int i=0; i<it->arg.size(); ++i)
754 arg1[i] = it->arg[i]>=0 ? w+
workloc_[it->arg[i]] :
nullptr;
755 for (casadi_int i=0; i<it->res.size(); ++i)
756 res1[i] = it->res[i]>=0 ? w+
workloc_[it->res[i]] :
nullptr;
759 if (it->data->sp_reverse(arg1, res1, iw, w))
return 1;
767 const casadi_int checking_depth = 2;
768 bool input_given =
true;
769 for (casadi_int i=0; i<arg.size() && input_given; ++i) {
784 bool always_inline,
bool never_inline)
const {
790 casadi_assert(arg.size()==
n_in_,
"Wrong number of input arguments");
791 res.resize(
out_.size());
794 if (!never_inline &&
isInput(arg)) {
795 std::copy(
out_.begin(),
out_.end(), res.begin());
806 std::vector<MX> swork(
workloc_.size()-1);
807 if (
verbose_) casadi_message(
"Allocated work vector");
810 std::vector<std::vector<MX> > arg_split(
in_.size());
811 for (casadi_int i=0; i<
in_.size(); ++i) arg_split[i] =
in_[i].split_primitives(arg[i]);
814 std::vector<std::vector<MX> > res_split(
out_.size());
815 for (casadi_int i=0; i<
out_.size(); ++i) res_split[i].resize(
out_[i].n_primitives());
817 std::vector<MX> arg1, res1;
820 casadi_int alg_counter = 0;
823 swork[it->res.front()] = project(arg_split.at(it->data->ind()).at(it->data->segment()),
824 it->data.sparsity(),
true);
827 res_split.at(it->data->ind()).at(it->data->segment()) = swork[it->arg.front()];
830 swork[it->res.front()] = it->data;
833 arg1.resize(it->arg.size());
834 for (casadi_int i=0; i<arg1.size(); ++i) {
835 casadi_int el = it->arg[i];
836 arg1[i] = el<0 ?
MX(it->data->dep(i).size()) : swork[el];
840 res1.resize(it->res.size());
841 it->data->eval_mx(arg1, res1);
844 for (casadi_int i=0; i<res1.size(); ++i) {
845 casadi_int el = it->res[i];
846 if (el>=0) swork[el] = res1[i];
852 for (casadi_int i=0; i<res.size(); ++i) res[i] =
out_[i].join_primitives(res_split[i]);
853 }
catch (std::exception& e) {
854 CASADI_THROW_ERROR(
"eval_mx", e.what());
859 std::vector<std::vector<MX> >& fsens)
const {
860 if (
verbose_) casadi_message(
name_ +
"::ad_forward(" +
str(fseed.size())+
")");
863 casadi_int nfwd = fseed.size();
865 for (casadi_int d=0; d<nfwd; ++d) {
874 for (
auto&& r : fseed) {
876 casadi_assert_dev(npar==1);
883 for (
auto&& r : fseed) {
886 std::vector<std::vector<MX> > fseed_purged, fsens_purged;
887 fseed_purged.reserve(nfwd);
888 std::vector<casadi_int> index_purged;
889 for (casadi_int d=0; d<nfwd; ++d) {
891 for (casadi_int i=0; i<fsens[d].size(); ++i) {
895 fseed_purged.push_back(fsens[d]);
896 index_purged.push_back(d);
904 for (casadi_int d=0; d<fseed_purged.size(); ++d) {
905 fsens[index_purged[d]] = fsens_purged[d];
919 std::vector<std::vector<MX> > dwork(
workloc_.size()-1);
920 fill(dwork.begin(), dwork.end(), std::vector<MX>(nfwd));
921 if (
verbose_) casadi_message(
"Allocated derivative work vector (forward mode)");
924 std::vector<std::vector<std::vector<MX>>> fseed_split(nfwd);
925 for (casadi_int d=0; d<nfwd; ++d) {
926 fseed_split[d].resize(fseed[d].size());
927 for (casadi_int i=0; i<fseed[d].size(); ++i) {
928 fseed_split[d][i] =
in_[i].split_primitives(fseed[d][i]);
933 std::vector<std::vector<std::vector<MX>>> fsens_split(nfwd);
934 for (casadi_int d=0; d<nfwd; ++d) {
935 fsens_split[d].resize(
out_.size());
936 for (casadi_int i=0; i<
out_.size(); ++i) {
937 fsens_split[d][i].resize(
out_[i].n_primitives());
942 std::vector<std::vector<MX> > oseed, osens;
945 std::vector<bool> skip(nfwd,
false);
951 for (casadi_int d=0; d<nfwd; ++d) {
952 dwork[e.res.front()][d] =
953 project(fseed_split[d].at(e.data->ind()).at(e.data->segment()),
954 e.data.sparsity(),
true);
958 for (casadi_int d=0; d<nfwd; ++d) {
959 fsens_split[d][e.data->ind()][e.data->segment()] = dwork[e.arg.front()][d];
963 for (casadi_int d=0; d<nfwd; ++d) {
964 dwork[e.res.front()][d] =
MX();
969 for (casadi_int d=0; d<nfwd; ++d) {
971 std::vector<MX> seed(e.arg.size());
973 for (casadi_int i=0; i<e.arg.size(); ++i) {
974 casadi_int el = e.arg[i];
975 if (el<0 || dwork[el][d].is_empty(
true)) {
976 seed[i] =
MX(e.data->dep(i).size());
978 seed[i] = dwork[el][d];
980 if (skip[d] && !seed[i].
is_zero()) skip[d] =
false;
982 if (!skip[d]) oseed.push_back(seed);
986 osens.resize(oseed.size());
987 if (!osens.empty()) {
988 fill(osens.begin(), osens.end(), std::vector<MX>(e.res.size()));
989 e.data.ad_forward(oseed, osens);
994 for (casadi_int d=0; d<nfwd; ++d) {
995 for (casadi_int i=0; i<e.res.size(); ++i) {
996 casadi_int el = e.res[i];
998 dwork[el][d] = skip[d] ?
MX(e.data->sparsity(i).size()) : osens[d1][i];
1007 for (casadi_int d=0; d<nfwd; ++d) {
1008 for (casadi_int i=0; i<
out_.size(); ++i) {
1009 fsens[d][i] =
out_[i].join_primitives(fsens_split[d][i]);
1012 }
catch (std::exception& e) {
1013 CASADI_THROW_ERROR(
"ad_forward", e.what());
1018 std::vector<std::vector<MX> >& asens)
const {
1019 if (
verbose_) casadi_message(
name_ +
"::ad_reverse(" +
str(aseed.size())+
")");
1023 casadi_int nadj = aseed.size();
1025 for (casadi_int d=0; d<nadj; ++d) {
1026 asens[d].resize(
n_in_);
1030 if (nadj==0)
return;
1033 casadi_int npar = 1;
1034 for (
auto&& r : aseed) {
1036 casadi_assert_dev(npar==1);
1043 for (
auto&& r : aseed) {
1047 std::vector<std::vector<MX> > aseed_purged, asens_purged;
1048 aseed_purged.reserve(nadj);
1049 std::vector<casadi_int> index_purged;
1050 for (casadi_int d=0; d<nadj; ++d) {
1052 for (casadi_int i=0; i<asens[d].size(); ++i) {
1056 aseed_purged.push_back(asens[d]);
1057 index_purged.push_back(d);
1065 for (casadi_int d=0; d<aseed_purged.size(); ++d) {
1066 asens[index_purged[d]] = asens_purged[d];
1073 std::vector<std::vector<MX> > v;
1077 for (casadi_int i=0; i<v.size(); ++i) {
1078 for (casadi_int j=0; j<v[i].size(); ++j) {
1079 if (!v[i][j].is_empty()) {
1080 if (asens[i][j].is_empty()) {
1081 asens[i][j] = v[i][j];
1083 asens[i][j] += v[i][j];
1092 std::vector<std::vector<std::vector<MX>>> aseed_split(nadj);
1093 for (casadi_int d=0; d<nadj; ++d) {
1094 aseed_split[d].resize(
out_.size());
1095 for (casadi_int i=0; i<
out_.size(); ++i) {
1096 aseed_split[d][i] =
out_[i].split_primitives(aseed[d][i]);
1101 std::vector<std::vector<std::vector<MX>>> asens_split(nadj);
1102 for (casadi_int d=0; d<nadj; ++d) {
1103 asens_split[d].resize(
in_.size());
1104 for (casadi_int i=0; i<
in_.size(); ++i) {
1105 asens_split[d][i].resize(
in_[i].n_primitives());
1110 std::vector<std::vector<MX>> oseed, osens;
1111 oseed.reserve(nadj);
1112 osens.reserve(nadj);
1113 std::vector<bool> skip(nadj,
false);
1116 std::vector<std::vector<MX> > dwork(
workloc_.size()-1);
1117 fill(dwork.begin(), dwork.end(), std::vector<MX>(nadj));
1123 for (casadi_int d=0; d<nadj; ++d) {
1124 asens_split[d].at(it->data->ind()).at(it->data->segment()) = dwork[it->res.front()][d];
1125 dwork[it->res.front()][d] =
MX();
1129 for (casadi_int d=0; d<nadj; ++d) {
1130 MX a = project(aseed_split[d].at(it->data->ind()).at(it->data->segment()),
1131 it->data.dep().sparsity(),
true);
1132 if (dwork[it->arg.front()][d].is_empty(
true)) {
1133 dwork[it->arg.front()][d] = a;
1135 dwork[it->arg.front()][d] += a;
1140 for (casadi_int d=0; d<nadj; ++d) {
1141 dwork[it->res.front()][d] =
MX();
1146 for (casadi_int d=0; d<nadj; ++d) {
1151 std::vector<MX> seed(it->res.size());
1152 for (casadi_int i=0; i<it->res.size(); ++i) {
1154 casadi_int el = it->res[i];
1156 seed[i] = dwork[el][d];
1157 dwork[el][d] =
MX();
1163 if (seed[i].is_empty(
true)) seed[i] =
MX(it->data->sparsity(i).size());
1166 if (skip[d] && !seed[i].
is_zero()) skip[d] =
false;
1169 if (!skip[d]) oseed.push_back(seed);
1173 osens.resize(oseed.size());
1175 for (casadi_int d=0; d<nadj; ++d) {
1176 if (skip[d])
continue;
1177 osens[d1].resize(it->arg.size());
1178 for (casadi_int i=0; i<it->arg.size(); ++i) {
1180 casadi_int el = it->arg[i];
1182 osens[d1][i] = dwork[el][d];
1183 dwork[el][d] =
MX();
1185 osens[d1][i] =
MX();
1189 if (osens[d1][i].is_empty(
true)) osens[d1][i] =
MX(it->data->dep(i).size());
1195 if (!osens.empty()) {
1196 it->data.ad_reverse(oseed, osens);
1201 for (casadi_int d=0; d<nadj; ++d) {
1202 if (skip[d])
continue;
1203 for (casadi_int i=0; i<it->arg.size(); ++i) {
1204 casadi_int el = it->arg[i];
1206 if (dwork[el][d].is_empty(
true)) {
1207 dwork[el][d] = osens[d1][i];
1209 dwork[el][d] += osens[d1][i];
1219 for (casadi_int d=0; d<nadj; ++d) {
1220 for (casadi_int i=0; i<
in_.size(); ++i) {
1221 asens[d][i] =
in_[i].join_primitives(asens_split[d][i]);
1224 }
catch (std::exception& e) {
1225 CASADI_THROW_ERROR(
"ad_reverse", e.what());
1230 casadi_int* iw,
SXElem* w,
void* mem,
1231 bool always_inline,
bool never_inline)
const {
1241 std::vector<const SXElem*> argp(
sz_arg());
1242 std::vector<SXElem*> resp(
sz_res());
1250 casadi_int nnz=a.data.nnz();
1251 casadi_int i=a.data->ind();
1252 casadi_int nz_offset=a.data->offset();
1253 if (arg[i]==
nullptr) {
1254 std::fill(w1, w1+nnz, 0);
1256 std::copy(arg[i]+nz_offset, arg[i]+nz_offset+nnz, w1);
1261 casadi_int nnz=a.data.dep().nnz();
1262 casadi_int i=a.data->ind();
1263 casadi_int nz_offset=a.data->offset();
1264 if (res[i]) std::copy(w1, w1+nnz, res[i]+nz_offset);
1269 for (casadi_int i=0; i<a.arg.size(); ++i)
1270 argp[i] = a.arg[i]>=0 ? w+
workloc_[a.arg[i]] :
nullptr;
1271 for (casadi_int i=0; i<a.res.size(); ++i)
1272 resp[i] = a.res[i]>=0 ? w+
workloc_[a.res[i]] :
nullptr;
1275 if (a.data->eval_sx(
get_ptr(argp),
get_ptr(resp), iw, w))
return 1;
1285 casadi_error(
"Code generation of '" +
name_ +
"' is not possible since variables "
1291 a.data->add_dependency(g);
1297 std::set<void*> added;
1299 a.data->codegen_incref(g, added);
1305 std::set<void*> added;
1307 a.data->codegen_decref(g, added);
1322 std::vector<casadi_int> arg, res;
1325 std::vector<bool> work_is_ref(
workloc_.size()-1,
false);
1328 std::vector<bool> arg_is_ref, res_is_ref;
1331 std::vector<bool> needs_reference(
workloc_.size()-1,
false);
1332 std::vector<bool> needs_value(
workloc_.size()-1,
false);
1338 g <<
"/* #" << k <<
": " <<
print(e) <<
" */\n";
1342 arg.resize(e.arg.size());
1343 arg_is_ref.resize(e.arg.size());
1344 for (casadi_int i=0; i<e.arg.size(); ++i) {
1345 casadi_int j=e.arg.at(i);
1348 arg_is_ref.at(i) = work_is_ref.at(j);
1351 arg_is_ref.at(i) =
false;
1356 res.resize(e.res.size());
1357 for (casadi_int i=0; i<e.res.size(); ++i) {
1358 casadi_int j=e.res.at(i);
1366 res_is_ref.resize(e.res.size());
1368 std::fill(res_is_ref.begin(), res_is_ref.end(),
false);
1375 e.data->generate(g, arg, res, arg_is_ref, res_is_ref);
1377 for (casadi_int i=0; i<e.res.size(); ++i) {
1378 casadi_int j=e.res.at(i);
1380 work_is_ref.at(j) = res_is_ref.at(i);
1381 if (res_is_ref.at(i)) {
1382 needs_reference[j] =
true;
1384 needs_value[j] =
true;
1398 for (casadi_int i=0; i<
workloc_.size()-1; ++i) {
1411 if (needs_value[i]) {
1415 if (needs_reference[i]) {
1423 std::vector<MX> swork(
workloc_.size()-1);
1425 std::vector<MX> arg1, res1;
1428 std::vector<std::vector<MX> > in_split(
in_.size());
1429 for (casadi_int i=0; i<
in_.size(); ++i) in_split[i] =
in_[i].primitives();
1434 std::vector<std::vector<MX> > f_G(
out_.size());
1435 for (casadi_int i=0; i<
out_.size(); ++i) f_G[i].resize(
out_[i].n_primitives());
1438 std::vector<MX> x_init;
1441 std::stringstream ss;
1443 for (casadi_int algNo=0; algNo<2; ++algNo) {
1448 MX& arg = swork[e.arg.at(0)];
1449 MX& arg_init = swork[e.arg.at(1)];
1450 MX& res = swork[e.res.front()];
1453 ss.str(std::string());
1454 ss <<
"y" << y.
size();
1460 x_init.push_back(arg_init);
1467 swork[e.res.front()] = in_split.at(e.data->ind()).at(e.data->segment());
1470 swork[e.res.front()] = e.data;
1474 f_G.at(e.data->ind()).at(e.data->segment()) = swork[e.arg.front()];
1480 arg1.resize(e.arg.size());
1481 for (casadi_int i=0; i<arg1.size(); ++i) {
1482 casadi_int el = e.arg[i];
1483 arg1[i] = el<0 ?
MX(e.data->dep(i).size()) : swork[el];
1487 res1.resize(e.res.size());
1488 e.data->eval_mx(arg1, res1);
1491 for (casadi_int i=0; i<res1.size(); ++i) {
1492 casadi_int el = e.res[i];
1493 if (el>=0) swork[el] = res1[i];
1501 std::vector<MX> f_in =
in_;
1502 f_in.insert(f_in.end(), y.begin(), y.end());
1503 std::vector<MX> f_out;
1504 for (casadi_int i=0; i<
out_.size(); ++i) f_out.push_back(
out_[i].join_primitives(f_G[i]));
1505 f_out.insert(f_out.end(), g.begin(), g.end());
1506 vdef_fcn =
Function(
"lifting_variable_definition", f_in, f_out);
1511 vinit_fcn =
Function(
"lifting_variable_guess", f_in, f_out);
1523 return type==
"MXFunction"
1529 std::vector<MX> work(
workloc_.size()-1);
1530 std::vector<MX> oarg, ores;
1533 std::vector<std::vector<MX>> out_split(
out_.size());
1534 for (casadi_int i = 0; i < out_split.size(); ++i) out_split[i].resize(
out_[i].n_primitives());
1540 casadi_assert(it->data->segment()==0,
"Not implemented");
1541 work.at(it->res.front())
1542 =
out_.at(it->data->ind()).join_primitives(out_split.at(it->data->ind()));
1546 work.at(it->res.front()) = it->data;
1549 out_split.at(it->data->ind()).at(it->data->segment()) = work.at(it->arg.front());
1554 oarg.resize(it->arg.size());
1555 for (casadi_int i=0; i<oarg.size(); ++i) {
1556 casadi_int el = it->arg[i];
1557 oarg[i] = el<0 ?
MX(it->data->dep(i).size()) : work.at(el);
1561 ores.resize(it->res.size());
1562 it->data->eval_mx(oarg, ores);
1565 for (casadi_int i=0; i<ores.size(); ++i) {
1566 casadi_int el = it->res[i];
1567 if (el>=0) work.at(el) = ores[i];
1573 for (
size_t k = 0; k < out_split.size(); ++k) {
1574 MX a =
out_.at(k).join_primitives(out_split.at(k));
1575 if (k < vdef.size()) {
1578 ex.at(k - vdef.size()) = a;
1585 casadi_assert(!(always_inline && never_inline),
1587 casadi_assert(!(never_inline &&
has_free()),
1589 if (always_inline)
return true;
1590 if (never_inline)
return false;
1598 std::ostream &ss,
const Dict& options)
const {
1601 casadi_int indent_level = 0;
1604 for (
auto&& op : options) {
1605 if (op.first==
"indent_level") {
1606 indent_level = op.second;
1608 casadi_error(
"Unknown option '" + op.first +
"'.");
1614 for (casadi_int i=0;i<indent_level;++i) {
1618 Function f = shared_from_this<Function>();
1633 ss << indent <<
"w" << o[0] <<
" = varargin{" << i[0]+1 <<
"};" << std::endl;
1638 casadi_int segment =
info[
"segment"];
1640 {{
"name",
"sp_in"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1641 ss << indent <<
"argout_" << o[0] <<
"{" << (1+segment) <<
"} = ";
1642 ss <<
"w" << i[0] <<
"(sp_in==1);" << std::endl;
1647 DM v =
static_cast<DM>(x);
1650 opts[
"indent_level"] = indent_level;
1652 ss << indent <<
"w" << o[0] <<
" = m;" << std::endl;
1656 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".^2;" << std::endl;
1659 ss << indent <<
"w" << o[0] <<
" = ";
1660 ss <<
"w" << i[1] <<
"*w" << i[2] <<
"+w" << i[0] <<
";" << std::endl;
1665 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] << prefix <<
"*w" << i[1] <<
";";
1670 ss << indent <<
"w" << o[0] <<
" = 2*w" << i[0] <<
";" << std::endl;
1673 ss << indent <<
"w" << o[0] <<
" = 1./w" << i[0] <<
";" << std::endl;
1676 ss << indent <<
"w" << o[0] <<
" = dot(w" << i[0] <<
",w" << i[1]<<
");" << std::endl;
1679 ss << indent <<
"w" << o[0] <<
" = w" << i[1] <<
".'*w" << i[0]<<
"*w" << i[2] <<
";";
1683 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
"+";
1684 ss <<
"w" << i[1] <<
"*w" << i[2] <<
"*w" << i[3] <<
".';";
1688 ss << indent <<
"w" << o[0] <<
" = abs(w" << i[0] <<
");" << std::endl;
1691 ss << indent <<
"w" << o[0] <<
" = det(w" << i[0] <<
");" << std::endl;
1694 ss << indent <<
"w" << o[0] <<
" = inv(w" << i[0] <<
");";
1695 ss <<
"w" << o[0] <<
"(w" << o[0] <<
"==0) = 1e-200;" << std::endl;
1699 bool tr = x.
info()[
"tr"];
1701 ss << indent <<
"w" << o[0] <<
" = ((w" << i[1] <<
".')\\w" << i[0] <<
").';";
1704 ss << indent <<
"w" << o[0] <<
" = w" << i[1] <<
"\\w" << i[0] <<
";" << std::endl;
1706 ss <<
"w" << o[0] <<
"(w" << o[0] <<
"==0) = 1e-200;" << std::endl;
1712 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] << prefix <<
"/w" << i[1] <<
";";
1718 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".^w" << i[1] <<
";" << std::endl;
1721 ss << indent <<
"w" << o[0] <<
" = " <<
"w" << i[0] <<
".';" << std::endl;
1726 ss << indent <<
"w" << o[0] <<
" = [";
1727 for (casadi_int e : i) {
1728 ss <<
"w" << e << (op==
OP_HORZCAT ?
" " :
";");
1730 ss <<
"];" << std::endl;
1735 for (casadi_int k=0;k<i.size();++k) {
1737 {{
"name",
"sp_in" +
str(k)}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1739 ss << indent <<
"w" << o[0] <<
" = [";
1740 for (casadi_int k=0;k<i.size();++k) {
1741 ss <<
"w" << i[k] <<
"(sp_in" << k <<
"==1);";
1743 ss <<
"];" << std::endl;
1745 opts[
"name"] =
"sp";
1746 opts[
"indent_level"] = indent_level;
1747 opts[
"as_matrix"] =
false;
1749 ss << indent <<
"w" << o[0] <<
" = ";
1750 ss <<
"sparse(sp_i, sp_j, w" << o[0] <<
", sp_m, sp_n);" << std::endl;
1757 std::vector<casadi_int> offset =
info[
"offset"];
1759 std::vector<Sparsity> sp;
1760 for (casadi_int i=0;i<output.
n_out();i++)
1762 for (casadi_int k=0;k<o.size();++k) {
1763 if (o[k]==-1)
continue;
1765 {{
"name",
"sp_in"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1766 ss << indent <<
"tmp = w" << i[0]<<
"(sp_in==1);" << std::endl;
1768 opts[
"name"] =
"sp";
1769 opts[
"indent_level"] = indent_level;
1770 opts[
"as_matrix"] =
false;
1771 sp[k].export_code(
"matlab", ss, opts);
1772 ss << indent <<
"w" << o[k] <<
" = sparse(sp_i, sp_j, ";
1773 ss <<
"tmp(" << offset[k]+1 <<
":" << offset[k+1] <<
"), sp_m, sp_n);" << std::endl;
1782 std::string nonzeros;
1784 nonzeros =
"1+" +
str(
info[
"nz"]);
1785 }
else if (
info.find(
"slice")!=
info.end()) {
1787 casadi_int start = s[
"start"];
1788 casadi_int step = s[
"step"];
1789 casadi_int stop = s[
"stop"];
1790 nonzeros =
str(start+1) +
":" +
str(step) +
":" +
str(stop);
1791 nonzeros =
"nonzeros(" + nonzeros +
")";
1795 casadi_int inner_start = inner[
"start"];
1796 casadi_int inner_step = inner[
"step"];
1797 casadi_int inner_stop = inner[
"stop"];
1798 casadi_int outer_start = outer[
"start"];
1799 casadi_int outer_step = outer[
"step"];
1800 casadi_int outer_stop = outer[
"stop"];
1801 std::string inner_slice =
"(" +
str(inner_start) +
":" +
1802 str(inner_step) +
":" +
str(inner_stop-1)+
")";
1803 std::string outer_slice =
"(" +
str(outer_start+1) +
":" +
1804 str(outer_step) +
":" +
str(outer_stop)+
")";
1805 casadi_int N =
range(outer_start, outer_stop, outer_step).size();
1806 casadi_int M =
range(inner_start, inner_stop, inner_step).size();
1807 nonzeros =
"repmat("+ inner_slice +
"', 1, " +
str(N) +
")+" +
1808 "repmat("+ outer_slice +
", " +
str(M) +
", 1)";
1809 nonzeros =
"nonzeros(" + nonzeros +
")";
1813 opts[
"name"] =
"sp";
1814 opts[
"indent_level"] = indent_level;
1815 opts[
"as_matrix"] =
false;
1820 {{
"name",
"sp_in"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1823 ss << indent <<
"in_flat = w" << i[0] <<
"(sp_in==1);" << std::endl;
1826 ss << indent <<
"w" << o[0] <<
" = in_flat(" << nonzeros <<
");" << std::endl;
1829 {{
"name",
"sp_in0"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1831 {{
"name",
"sp_in1"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1832 ss << indent <<
"in_flat = w" << i[1] <<
"(sp_in1==1);" << std::endl;
1833 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
"(sp_in0==1);" << std::endl;
1834 ss << indent <<
"w" << o[0] <<
"(" << nonzeros <<
") = ";
1835 if (
info[
"add"]) ss <<
"w" << o[0] <<
"(" << nonzeros <<
") + ";
1838 ss << indent <<
"w" << o[0] <<
" = ";
1839 ss <<
"sparse(sp_i, sp_j, w" << o[0] <<
", sp_m, sp_n);" << std::endl;
1845 opts[
"name"] =
"sp";
1846 opts[
"indent_level"] = indent_level;
1848 ss << indent <<
"w" << o[0] <<
" = ";
1849 ss <<
"sparse(sp_i, sp_j, w" << i[0] <<
"(sp==1), sp_m, sp_n);" << std::endl;
1853 ss << indent <<
"w" << o[0] <<
" = norm(w" << i[0] <<
", 1);" << std::endl;
1856 ss << indent <<
"w" << o[0] <<
" = norm(w" << i[0] <<
", 2);" << std::endl;
1859 ss << indent <<
"w" << o[0] <<
" = norm(w" << i[0] <<
", 'fro');" << std::endl;
1862 ss << indent <<
"w" << o[0] <<
" = norm(w" << i[0] <<
", inf);" << std::endl;
1865 ss << indent <<
"w" << o[0] <<
" = min(w" << i[0] <<
");" << std::endl;
1868 ss << indent <<
"w" << o[0] <<
" = max(w" << i[0] <<
");" << std::endl;
1871 ss << indent <<
"w" << o[0] <<
" = ~" <<
"w" << i[0] <<
";" << std::endl;
1874 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" | w" << i[1] <<
";" << std::endl;
1877 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" & w" << i[1] <<
";" << std::endl;
1880 ss << indent <<
"w" << o[0] <<
" = w" << i[0] <<
" ~= w" << i[1] <<
";" << std::endl;
1883 ss << indent <<
"w" << o[0] <<
" = ";
1884 ss <<
"if_else_zero_gen(w" << i[0] <<
", w" << i[1] <<
");" << std::endl;
1889 {{
"name",
"sp_in"}, {
"indent_level", indent_level}, {
"as_matrix",
true}});
1891 {{
"name",
"sp_out"}, {
"indent_level", indent_level}, {
"as_matrix",
false}});
1892 ss << indent <<
"w" << o[0] <<
" = sparse(sp_out_i, sp_out_j, ";
1893 ss <<
"w" << i[0] <<
"(sp_in==1), sp_out_m, sp_out_n);" << std::endl;
1899 "w"+std::to_string(i[0]),
"w"+std::to_string(i[1])) <<
";" << std::endl;
1902 "w"+std::to_string(i[0])) <<
";" << std::endl;
1904 ss <<
"unknown" + x.
class_name() << std::endl;
1916 Function d = e.data.which_function();
1917 if (d.
is_a(
"Conic",
true) || d.
is_a(
"Nlpsol")) {
1918 if (!dep.
is_null())
return stats;
1923 if (dep.
is_null())
return stats;
1924 return dep.
stats(1);
1935 s.
pack(
"MXFunction::alg::data", e.data);
1936 s.
pack(
"MXFunction::alg::arg", e.arg);
1937 s.
pack(
"MXFunction::alg::res", e.res);
1951 int version = s.
version(
"MXFunction", 1, 2);
1959 s.
unpack(
"MXFunction::alg::arg", e.
arg);
1960 s.
unpack(
"MXFunction::alg::res", e.
res);
1978 casadi_int max_depth)
const {
1988 if (option_name ==
"print_instructions") {
1997 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
1998 std::lock_guard<std::mutex> lock(MX::get_mutex_temp());
2001 std::stack<MXNode*> s;
2004 std::vector<MXNode*> nodes;
2007 for (casadi_int ind=0; ind<expr.size(); ++ind) {
2009 std::vector<MX> prim = expr[ind].primitives();
2010 for (casadi_int p=0; p<prim.size(); ++p) {
2012 s.push(prim[p].get());
2018 for (casadi_int i=0; i<nodes.size(); ++i) {
2022 std::vector<MX> ret(nodes.size());
2023 for (casadi_int i=0; i<nodes.size(); ++i) {
2024 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.
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 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.
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.
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.
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 Sparsity & sparsity_out(casadi_int ind) const
Get sparsity of a given output.
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)
casadi_int n_out() const
Get the number of function outputs.
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.
casadi_int ind() const override
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)
int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity forward.
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.
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.