25 #define CASADI_SX_INSTANTIATOR_CPP
26 #include "matrix_impl.hpp"
28 #include "sx_function.hpp"
35 casadi_assert(
numel()==1,
36 "Only scalar Matrix could have a truth value, but you "
37 "provided a shape" +
dim());
38 return nonzeros().at(0).__nonzero__();
54 std::vector<SXElem> retv;
60 std::string modname =
name;
61 for (std::string::iterator it=modname.begin(); it!=modname.end(); ++it) {
63 case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case ',':
case ';': *it =
' ';
67 std::istringstream iss(modname);
84 for (casadi_int k=0; k<sp.
nnz(); ++k) {
86 ss <<
name <<
"_" << k;
95 return SX(sp, retv,
false);
102 for (casadi_int i=0; i<
nnz(); ++i) {
109 for (casadi_int i=0; i<
nnz(); ++i) {
110 if (!
nonzeros().at(i).is_regular())
return false;
118 Function temp(
"tmp_is_smooth", {
SX()}, {*
this},
Dict{{
"max_io", 0}, {
"allow_free",
true}});
127 return scalar().__hash__();
132 return scalar().is_leaf();
137 return scalar().is_commutative();
142 for (casadi_int k=0; k<
nnz(); ++k)
143 if (!
nonzeros().at(k)->is_symbolic())
151 return scalar().is_call();
156 return scalar().is_output();
161 return scalar().has_output();
166 return scalar().get_output(oind);
171 return scalar().which_function();
176 return scalar().which_output();
189 casadi_int CASADI_EXPORT
SX::op()
const {
200 for (
auto&& i : nonzeros_) {
201 bool is_duplicate = i.get_temp()!=0;
203 casadi_warning(
"Duplicate expression: " +
str(i));
212 for (
auto&& i : nonzeros_) {
238 std::vector<std::vector<SXNode*> > terms;
239 std::vector<std::vector<double> > weights;
240 std::map<SXNode*, casadi_int> indices;
243 std::stack<SXNode*> to_be_expanded;
244 to_be_expanded.push(ex.
get());
246 while (!to_be_expanded.empty()) {
249 if (indices.find(to_be_expanded.top()) != indices.end()) {
251 to_be_expanded.pop();
256 std::vector<double> w;
257 std::vector<SXNode*> f;
259 if (to_be_expanded.top()->is_constant()) {
260 w.push_back(to_be_expanded.top()->to_double());
262 }
else if (to_be_expanded.top()->is_symbolic()) {
265 f.push_back(to_be_expanded.top());
268 casadi_assert_dev(to_be_expanded.top()->n_dep());
271 SXNode* node = to_be_expanded.top();
274 (node->op() ==
OP_MUL && (node->dep(0)->is_constant() ||
275 node->dep(1)->is_constant()))) {
277 if (indices.find(node->dep(0).get()) == indices.end()) {
278 to_be_expanded.push(node->dep(0).get());
281 if (indices.find(node->dep(1).get()) == indices.end()) {
282 to_be_expanded.push(node->dep(1).get());
287 casadi_int ind1 = indices[node->dep(0).get()];
288 casadi_int ind2 = indices[node->dep(1).get()];
291 if (node->op() ==
OP_MUL) {
294 if (node->dep(0)->is_constant()) {
295 fac = node->dep(0)->to_double();
299 fac = node->dep(1)->to_double();
303 for (casadi_int i=0; i<w.size(); ++i) w[i] *= fac;
306 if (node->op() ==
OP_ADD) {
307 f = terms[ind1]; f.insert(f.end(), terms[ind2].begin(), terms[ind2].end());
308 w = weights[ind1]; w.insert(w.end(), weights[ind2].begin(), weights[ind2].end());
310 f = terms[ind1]; f.insert(f.end(), terms[ind2].begin(), terms[ind2].end());
313 for (casadi_int i=0; i<weights[ind2].size(); ++i) w.push_back(-weights[ind2][i]);
316 std::vector<double> w_new; w_new.reserve(w.size());
317 std::vector<SXNode*> f_new; f_new.reserve(f.size());
318 std::map<SXNode*, casadi_int> f_ind;
320 for (casadi_int i=0; i<w.size(); i++) {
322 auto it = f_ind.find(f[i]);
323 if (it == f_ind.end()) {
324 w_new.push_back(w[i]);
325 f_new.push_back(f[i]);
326 f_ind[f[i]] = f_new.size()-1;
328 w_new[it->second] += w[i];
343 weights.push_back(w);
345 indices[to_be_expanded.top()] = terms.size()-1;
348 to_be_expanded.pop();
352 casadi_int thisind = indices[ex.
get()];
353 ww =
SX(weights[thisind]);
355 std::vector<SXElem> termsv(terms[thisind].
size());
356 for (casadi_int i=0; i<termsv.size(); ++i)
364 casadi_int n = val.numel();
366 casadi_assert(t.is_scalar(),
"t must be a scalar");
367 casadi_assert(tval.numel() == n-1,
"dimensions do not match");
370 for (casadi_int i=0; i<n-1; ++i) {
371 ret += (val(i+1)-val(i)) * (t>=tval(i));
380 casadi_int N = tval.numel();
381 casadi_assert(N>=2,
"pw_lin: N>=2");
382 casadi_assert(val.numel() == N,
"dimensions do not match");
386 for (casadi_int i=0; i<N-1; ++i)
387 g(i) = (val(i+1)- val(i))/(tval(i+1)-tval(i));
390 SX lseg =
SX(1, N-1);
391 for (casadi_int i=0; i<N-1; ++i)
392 lseg(i) = val(i) + g(i)*(t-tval(i));
400 const SX& b, casadi_int order,
const SX& w) {
401 casadi_assert(order == 5,
"gauss_quadrature: order must be 5");
402 casadi_assert(w.is_empty(),
"gauss_quadrature: empty weights");
409 Function fcn(
"gauss_quadrature", {x}, {f});
415 std::vector<double> xi;
416 xi.push_back(-std::sqrt(5 + 2*std::sqrt(10.0/7))/3);
417 xi.push_back(-std::sqrt(5 - 2*std::sqrt(10.0/7))/3);
419 xi.push_back(std::sqrt(5 - 2*std::sqrt(10.0/7))/3);
420 xi.push_back(std::sqrt(5 + 2*std::sqrt(10.0/7))/3);
423 std::vector<double> wi;
424 wi.push_back((322-13*std::sqrt(70.0))/900.0);
425 wi.push_back((322+13*std::sqrt(70.0))/900.0);
426 wi.push_back(128/225.0);
427 wi.push_back((322+13*std::sqrt(70.0))/900.0);
428 wi.push_back((322-13*std::sqrt(70.0))/900.0);
431 Function fcn(
"gauss_quadrature", {x}, {f});
432 std::vector<SXElem> f_val(5);
433 for (casadi_int i=0; i<5; ++i)
434 f_val[i] = fcn(
SX(xi[i])).at(0).scalar();
438 for (casadi_int i=0; i<5; ++i)
439 sum += wi[i]*f_val[i];
447 for (casadi_int el=0; el<r.nnz(); ++el) {
450 expand(r.nz(el), weights, terms);
453 r.nz(el) =
mtimes(terms.T(), weights);
459 std::vector<SX> CASADI_EXPORT
460 SX::substitute(
const std::vector<SX>& ex,
const std::vector<SX>& v,
const std::vector<SX>& vdef) {
463 if (v.size()!=vdef.size()) {
464 casadi_warning(
"subtitute: number of symbols to replace ( " +
str(v.size()) +
") "
465 "must match number of expressions (" +
str(vdef.size()) +
") "
466 "to replace them with.");
470 bool all_equal =
true;
471 for (casadi_int k=0; k<v.size(); ++k) {
477 if (all_equal)
return ex;
480 for (casadi_int k=0; k<v.size(); ++k) {
484 std::vector<SX> vdef_mod = vdef;
485 vdef_mod[k] =
SX(v[k].
sparsity(), vdef[k]->at(0),
false);
488 casadi_error(
"Sparsities of v and vdef must match. Got v: "
489 + v[k].
dim() +
" and vdef: " + vdef[k].
dim() +
".");
496 Function F(
"tmp_substitute", v, ex,
Dict{{
"max_io", 0}, {
"allow_free",
true}});
502 return substitute(std::vector<SX>{ex}, std::vector<SX>{v}, std::vector<SX>{vdef}).front();
507 std::vector<SX >& ex,
bool reverse) {
509 casadi_assert_dev(v.size()==vdef.size());
510 for (casadi_int i=0; i<v.size(); ++i) {
511 casadi_assert(v[i].
is_symbolic(),
"the variable is not symbolic");
512 casadi_assert(v[i].
sparsity() == vdef[i].
sparsity(),
"the sparsity patterns of the "
513 "expression and its defining bexpression do not match");
517 if (v.empty())
return;
520 std::vector<SX> f_in;
521 if (!
reverse) f_in.insert(f_in.end(), v.begin(), v.end());
524 std::vector<SX> f_out = vdef;
525 f_out.insert(f_out.end(), ex.begin(), ex.end());
528 Function f(
"tmp_substitute_inplace", f_in, f_out,
Dict{{
"max_io", 0}, {
"allow_free",
true}});
531 SXFunction *ff = f.get<SXFunction>();
532 const std::vector<ScalarAtomic>& algorithm = ff->algorithm_;
533 std::vector<SXElem> work(f.sz_w());
536 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
539 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
542 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
545 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
549 work[it->i0] = vdef.at(it->i1)->at(it->i2);
552 if (it->i0 < v.size()) {
553 vdef.at(it->i0)->at(it->i2) = work[it->i1];
556 work[it->i1] = v.at(it->i0)->at(it->i2);
560 ex.at(it->i0 - v.size())->at(it->i2) = work[it->i1];
563 case OP_CONST: work[it->i0] = *c_it++;
break;
568 CASADI_MATH_FUN_BUILTIN(work[it->i1], work[it->i2], work[it->i0])
572 const casadi_int depth = 2;
573 work[it->i0].assignIfDuplicate(*b_it++, depth);
580 std::vector<SXElem>& symbol_v, std::vector<SXElem>& parametric_v,
581 bool extract_trivial, casadi_int v_offset,
582 const std::string& v_prefix,
const std::string& v_suffix) {
585 auto it = symbol_map.
find(node.
get());
589 if (is_trivial && !extract_trivial) {
593 if (it==symbol_map.end()) {
596 symbol_map[node.
get()] = sym;
599 symbol_v.push_back(sym);
600 parametric_v.push_back(node);
612 SX& expr_ret, std::vector<SX>& symbols, std::vector<SX>& parametric,
const Dict& opts) {
613 std::string v_prefix =
"e_";
614 std::string v_suffix =
"";
615 bool extract_trivial =
false;
616 casadi_int v_offset = 0;
617 for (
auto&&
op : opts) {
618 if (
op.first ==
"prefix") {
619 v_prefix = std::string(
op.second);
620 }
else if (
op.first ==
"suffix") {
621 v_suffix = std::string(
op.second);
622 }
else if (
op.first ==
"offset") {
623 v_offset =
op.second;
624 }
else if (
op.first ==
"extract_trivial") {
625 extract_trivial =
op.second;
627 casadi_error(
"No such option: " + std::string(
op.first));
630 Function f(
"f", std::vector<SX>{par},
631 std::vector<SX>{expr}, {{
"live_variables",
false},
632 {
"max_io", 0}, {
"allow_free",
true}});
633 SXFunction *ff = f.get<SXFunction>();
636 std::vector< SXElem > w(ff->worksize_);
642 std::vector< char > expr_status(ff->worksize_, 0);
645 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
648 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
651 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
654 const SXElem* arg =
get_ptr(par.nonzeros());
658 std::vector<SXElem>& ret = expr_ret.nonzeros();
661 std::map<SXNode*, SXElem> symbol_map;
664 std::vector<SXElem> symbol_v, parametric_v;
667 for (
auto&& a : ff->algorithm_) {
671 expr_status[a.i0] = 1;
674 casadi_assert_dev(a.i0==0);
676 SXElem arg = w[a.i1];
677 if (expr_status[a.i1]==1) {
679 extract_trivial, v_offset, v_prefix, v_suffix);
686 expr_status[a.i0] = 0;
690 expr_status[a.i0] = 2;
694 const auto& m = ff->call_.el.at(a.i1);
695 const SXElem& orig = *b_it++;
696 std::vector<SXElem> deps(m.n_dep);
698 bool identical =
true;
699 for (casadi_int i=0;i<m.n_dep;++i) {
705 for (casadi_int i=0;i<m.n_dep;++i) {
706 max_status = std::max(max_status, expr_status[m.dep[i]]);
709 bool any_tainted = max_status==2;
713 for (casadi_int i=0;i<m.n_dep;++i) {
715 if (expr_status[m.dep[i]]==2)
continue;
717 if (expr_status[m.dep[i]]==0)
continue;
719 w[m.dep[i]] =
register_symbol(w[m.dep[i]], symbol_map, symbol_v, parametric_v,
720 extract_trivial, v_offset, v_prefix, v_suffix);
726 std::vector<SXElem> ret;
729 for (casadi_int i=0;i<m.n_res;++i) {
730 ret.push_back(orig.get_output(i));
733 for (casadi_int i=0;i<m.n_dep;++i) deps[i] = w[m.dep[i]];
738 for (casadi_int i=0;i<m.n_res;++i) {
739 if (m.res[i]>=0) expr_status[m.res[i]] = max_status;
742 for (casadi_int i=0;i<m.n_res;++i) {
743 if (m.res[i]>=0) w[m.res[i]] = ret[i];
752 SXElem w2 = is_binary ? w[a.i2] : 0;
754 char max_status = expr_status[a.i1];
756 max_status = std::max(max_status, expr_status[a.i2]);
758 bool any_tainted = max_status==2;
762 for (
int k=0;k<1+is_binary;++k) {
764 casadi_int el = k==0 ? a.i1 : a.i2;
765 if (expr_status[el]==2)
continue;
767 if (expr_status[el]==0)
continue;
769 SXElem& arg = k==0 ? w1 : w2;
772 extract_trivial, v_offset, v_prefix, v_suffix);
780 CASADI_MATH_FUN_BUILTIN(w1, w2, f)
786 const casadi_int depth = 2;
787 w[a.i0].assignIfDuplicate(*b_it++, depth);
790 expr_status[a.i0] = max_status;
795 symbols.resize(symbol_v.size());
796 parametric.resize(parametric_v.size());
798 for (casadi_int i=0;i<symbol_v.size();++i) {
799 symbols[i] = symbol_v[i];
800 parametric[i] = parametric_v[i];
806 const SX &sym_lin,
const SX &sym_const,
807 SX& expr_const,
SX& expr_lin,
SX& expr_nonlin) {
809 Function f(
"f", std::vector<SX>{sym_const, sym_lin},
810 std::vector<SX>{expr}, {{
"live_variables",
false},
812 SXFunction *ff = f.get<SXFunction>();
817 expr_nonlin =
SX::zeros(expr.sparsity());
819 std::vector<SXElem*> ret = {
820 get_ptr(expr_const.nonzeros()),
822 get_ptr(expr_nonlin.nonzeros())};
825 std::vector< std::array<SXElem, 3> > w(ff->worksize_,
826 std::array<SXElem, 3>{{0, 0, 0}});
828 std::vector<const SXElem*> arg(f.sz_arg());
829 arg[0] =
get_ptr(sym_const.nonzeros());
830 arg[1] =
get_ptr(sym_lin.nonzeros());
833 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
836 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
839 for (
auto&& a : ff->algorithm_) {
842 w[a.i0][a.i1] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
845 casadi_assert_dev(a.i0==0);
846 ret[0][a.i2] = w[a.i1][0];
847 ret[1][a.i2] = w[a.i1][1];
848 ret[2][a.i2] = w[a.i1][2];
851 w[a.i0][0] = *c_it++;
854 w[a.i0][2] = *p_it++;
857 casadi_error(
"Not implemented");
866 bool CASADI_EXPORT SX::depends_on(
const SX &x,
const SX &arg) {
867 if (x.nnz()==0)
return false;
870 Function temp(
"tmp_depends_on", {arg}, {x},
Dict{{
"max_io", 0}, {
"allow_free",
true}});
873 std::vector<bvec_t> t_in(arg.nnz(), 1), t_out(x.nnz());
877 for (casadi_int i=0; i<t_out.size(); ++i) {
878 if (t_out[i])
return true;
885 bool CASADI_EXPORT SX::contains_all(
const std::vector<SX>& v,
const std::vector<SX> &n) {
886 if (n.empty())
return true;
890 for (
const SX& e : v) l.insert(e.scalar().get());
892 size_t l_unique = l.size();
894 for (
const SX& e : n) l.insert(e.scalar().get());
896 return l.size()==l_unique;
900 bool CASADI_EXPORT SX::contains_any(
const std::vector<SX>& v,
const std::vector<SX> &n) {
901 if (n.empty())
return true;
905 for (
const SX& e : v) l.insert(e.scalar().get());
907 size_t l_unique = l.size();
910 for (
const SX& e : n) r.insert(e.scalar().get());
912 size_t r_unique = r.size();
913 for (
const SX& e : n) l.insert(e.scalar().get());
915 return l.size()<l_unique+r_unique;
918 class IncrementalSerializer {
926 IncrementalSerializer() : serializer(ss) {
929 std::string pack(
const SXElem& a) {
932 a.serialize(serializer);
935 a.serialize(serializer);
936 std::string ret = ss.str();
943 std::stringstream ss;
945 std::vector<SXElem> ref;
946 SerializingStream serializer;
951 std::vector<SX> CASADI_EXPORT SX::cse(
const std::vector<SX>& e) {
955 Function f(
"f", std::vector<SX>{}, e, {{
"live_variables",
false},
956 {
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}});
957 SXFunction *ff = f.get<SXFunction>();
960 for (casadi_int i=0;i<e.size();++i) {
961 ret.push_back(SX::zeros(e.at(i).sparsity()));
965 std::vector<SXElem> w(ff->worksize_);
967 std::vector<const SXElem*> arg(f.sz_arg());
972 std::vector<SXElem*> res(f.sz_res());
973 for (casadi_int i=0;i<e.size();++i) {
974 res[i] =
get_ptr(ret.at(i).nonzeros());
977 std::unordered_map<std::string, SXElem > cache;
978 IncrementalSerializer s;
981 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
984 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
986 std::unordered_map<std::string, Function> function_cache;
989 for (
auto&& a : ff->algorithm_) {
992 w[a.i0] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
993 if (arg[a.i1]!=
nullptr) cache[s.pack(w[a.i0])] = w[a.i0];
996 if (res[a.i0]!=
nullptr) res[a.i0][a.i2] = w[a.i1];
1000 cache[s.pack(w[a.i0])] = w[a.i0];
1004 cache[s.pack(w[a.i0])] = w[a.i0];
1008 const auto& m = ff->call_.el.at(a.i1);
1011 std::vector<SXElem> deps(m.n_dep);
1012 for (casadi_int i=0;i<m.n_dep;++i) deps[i] = w[m.dep[i]];
1015 std::string key = m.f.serialize();
1016 auto itk = function_cache.find(key);
1017 if (itk==function_cache.end()) {
1018 function_cache[key] = m.f;
1022 std::vector<SXElem> ret = SXElem::call(function_cache[key], deps);
1027 key = s.pack(call_node);
1028 auto it = cache.find(key);
1029 if (it==cache.end()) {
1031 cache[key] = call_node;
1034 call_node = it->second;
1036 for (casadi_int i=0; i<ret.size(); ++i) {
1038 ret[i] = call_node.
get_output(ret[i].which_output());
1043 for (casadi_int i=0;i<m.n_res;++i) {
1044 if (m.res[i]>=0) w[m.res[i]] = ret[i];
1056 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1058 casadi_error(
"Not implemented");
1061 std::string key = s.pack(f);
1063 auto itk = cache.find(key);
1064 if (itk==cache.end()) {
1079 SX CASADI_EXPORT SX::jacobian(
const SX &f,
const SX &x,
const Dict& opts) {
1083 h_opts[
"allow_free"] =
true;
1084 Function h(
"jac_helper", {x}, {f}, h_opts);
1085 return h.
get<SXFunction>()->jac(opts_remainder).at(0);
1089 SX CASADI_EXPORT SX::hessian(
const SX &ex,
const SX &arg,
SX &g,
const Dict& opts) {
1090 Dict all_opts = opts;
1091 if (!opts.count(
"symmetric")) all_opts[
"symmetric"] =
true;
1092 g = gradient(ex, arg);
1093 return jacobian(g, arg, all_opts);
1097 SX CASADI_EXPORT SX::hessian(
const SX &ex,
const SX &arg,
const Dict& opts) {
1099 return hessian(ex, arg, g, opts);
1103 std::vector<std::vector<SX> > CASADI_EXPORT
1104 SX::forward(
const std::vector<SX> &ex,
const std::vector<SX> &arg,
1105 const std::vector<std::vector<SX> > &v,
const Dict& opts) {
1109 h_opts[
"allow_free"] =
true;
1111 bool always_inline =
false;
1112 bool never_inline =
false;
1113 for (
auto&& op : opts_remainder) {
1114 if (op.first==
"always_inline") {
1115 always_inline = op.second;
1116 }
else if (op.first==
"never_inline") {
1117 never_inline = op.second;
1119 casadi_error(
"No such option: " + std::string(op.first));
1123 Function temp(
"forward_temp", arg, ex, h_opts);
1124 std::vector<std::vector<SX> > ret;
1125 temp->call_forward(arg, ex, v, ret, always_inline, never_inline);
1130 std::vector<std::vector<SX> > CASADI_EXPORT
1131 SX::reverse(
const std::vector<SX> &ex,
const std::vector<SX> &arg,
1132 const std::vector<std::vector<SX> > &v,
const Dict& opts) {
1136 h_opts[
"allow_free"] =
true;
1138 bool always_inline =
false;
1139 bool never_inline =
false;
1140 for (
auto&& op : opts_remainder) {
1141 if (op.first==
"always_inline") {
1142 always_inline = op.second;
1143 }
else if (op.first==
"never_inline") {
1144 never_inline = op.second;
1146 casadi_error(
"No such option: " + std::string(op.first));
1150 Function temp(
"reverse_temp", arg, ex, h_opts);
1151 std::vector<std::vector<SX> > ret;
1152 temp->call_reverse(arg, ex, v, ret, always_inline, never_inline);
1157 std::vector<bool> CASADI_EXPORT SX::which_depends(
const SX &expr,
1158 const SX &var, casadi_int order,
bool tr) {
1168 SX CASADI_EXPORT SX::taylor(
const SX& f,
const SX& x,
1169 const SX& a, casadi_int order) {
1175 SX result = substitute(ff, x, a);
1179 for (casadi_int i=1; i<=order; i++) {
1180 ff = jacobian(ff, x);
1181 nf*=
static_cast<double>(i);
1182 result+=1/nf * substitute(ff, x, a) * dxa;
1189 const std::vector<casadi_int>&order_contributions,
1191 double current_denom=1, casadi_int current_order=1) {
1192 SX result = substitute(ex, x, a)*current_dx/current_denom;
1193 for (casadi_int i=0;i<x.
nnz();i++) {
1194 if (order_contributions[i]<=order) {
1197 order-order_contributions[i],
1198 order_contributions,
1199 current_dx*(x->at(i)-a->at(i)),
1200 current_denom*
static_cast<double>(current_order),
1208 SX CASADI_EXPORT SX::mtaylor(
const SX& f,
const SX& x,
const SX& a, casadi_int order,
1209 const std::vector<casadi_int>& order_contributions) {
1210 casadi_assert(f.nnz()==f.numel() && x.nnz()==x.numel(),
1211 "mtaylor: not implemented for sparse matrices");
1213 casadi_assert(x.nnz()==order_contributions.size(),
1214 "mtaylor: number of non-zero elements in x (" +
str(x.nnz())
1215 +
") must match size of order_contributions ("
1216 +
str(order_contributions.size()) +
")");
1219 order_contributions),
1220 f.
size2(), f.size1()).T();
1224 SX CASADI_EXPORT SX::mtaylor(
const SX& f,
const SX& x,
const SX& a, casadi_int order) {
1225 return mtaylor(f, x, a, order, std::vector<casadi_int>(x.nnz(), 1));
1229 casadi_int CASADI_EXPORT SX::n_nodes(
const SX& x) {
1230 Dict opts{{
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}};
1231 Function f(
"tmp_n_nodes", {
SX()}, {x}, opts);
1236 std::string CASADI_EXPORT
1237 SX::print_operator(
const SX& X,
const std::vector<std::string>& args) {
1238 SXElem x =
X.scalar();
1239 casadi_int ndeps = casadi_math<double>::ndeps(x.op());
1240 casadi_assert(ndeps==1 || ndeps==2,
"Not a unary or binary operator");
1241 casadi_assert(args.size()==ndeps,
"Wrong number of arguments");
1243 return casadi_math<double>::print(x.op(), args.at(0));
1250 std::vector<SX> CASADI_EXPORT SX::symvar(
const SX& x) {
1251 Dict opts{{
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}};
1252 Function f(
"tmp_symvar", std::vector<SX>{}, {x}, opts);
1257 void CASADI_EXPORT SX::extract(std::vector<SX>& ex, std::vector<SX>& v_sx,
1258 std::vector<SX>& vdef_sx,
const Dict& opts) {
1260 std::string v_prefix =
"v_", v_suffix =
"";
1261 bool lift_shared =
true, lift_calls =
false;
1262 casadi_int v_ind = 0;
1263 for (
auto&& op : opts) {
1264 if (op.first ==
"prefix") {
1265 v_prefix = std::string(op.second);
1266 }
else if (op.first ==
"suffix") {
1267 v_suffix = std::string(op.second);
1268 }
else if (op.first ==
"lift_shared") {
1269 lift_shared = op.second;
1270 }
else if (op.first ==
"lift_calls") {
1271 lift_calls = op.second;
1272 }
else if (op.first ==
"offset") {
1275 casadi_error(
"No such option: " + std::string(op.first));
1279 casadi_assert(lift_shared,
"Not implemented");
1280 casadi_assert(!lift_calls,
"Not implemented");
1282 Function f(
"tmp_extract", std::vector<SX>(), ex,
Dict{{
"max_io", 0}, {
"allow_free",
true}});
1283 SXFunction *ff = f.
get<SXFunction>();
1285 const std::vector<ScalarAtomic>& algorithm = ff->algorithm_;
1286 std::vector<SXElem> work(f.sz_w());
1287 std::vector<SXElem> work2 = work;
1289 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
1291 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
1293 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
1295 std::vector<casadi_int> usecount(work.size(), 0);
1297 std::vector<SXElem> v, vdef;
1298 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
1304 CASADI_MATH_BINARY_BUILTIN
1306 if (usecount[it->i2]==0) {
1308 }
else if (usecount[it->i2]==1) {
1310 vdef.push_back(work[it->i2]);
1311 usecount[it->i2]=-1;
1316 if (usecount[it->i1]==0) {
1318 }
else if (usecount[it->i1]==1) {
1319 vdef.push_back(work[it->i1]);
1320 usecount[it->i1]=-1;
1329 usecount[it->i0] = -1;
1332 work[it->i0] = *b_it++;
1333 usecount[it->i0] = 0;
1338 std::stringstream v_name;
1339 for (casadi_int i=0; i<vdef.size(); ++i) {
1340 v_name.str(std::string());
1341 v_name << v_prefix << (v_ind++) << v_suffix;
1342 v.push_back(SXElem::sym(v_name.str()));
1345 casadi_assert(vdef.size() < std::numeric_limits<int>::max(),
"Integer overflow");
1347 for (casadi_int i=0; i<vdef.size(); ++i) {
1348 vdef[i].set_temp(
static_cast<int>(i)+1);
1351 std::vector<SXElem> marked = vdef;
1353 b_it=ff->operations_.begin();
1355 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
1357 case OP_OUTPUT: ex.at(it->i0)->at(it->i2) = work[it->i1];
break;
1358 case OP_CONST: work2[it->i0] = work[it->i0] = *c_it++;
break;
1359 case OP_PARAMETER: work2[it->i0] = work[it->i0] = *p_it++;
break;
1363 CASADI_MATH_FUN_BUILTIN(work[it->i1], work[it->i2], work[it->i0])
1365 work2[it->i0] = *b_it++;
1367 casadi_int ind = work2[it->i0].get_temp()-1;
1369 vdef.at(ind) = work[it->i0];
1370 work[it->i0] = v.at(ind);
1376 for (std::vector<SXElem>::iterator it=marked.begin(); it!=marked.end(); ++it) {
1380 v_sx.resize(v.size());
1381 std::copy(v.begin(), v.end(), v_sx.begin());
1382 vdef_sx.resize(vdef.size());
1383 std::copy(vdef.begin(), vdef.end(), vdef_sx.begin());
1387 void CASADI_EXPORT SX::shared(std::vector<SX >& ex,
1388 std::vector<SX >& v,
1389 std::vector<SX >& vdef,
1390 const std::string& v_prefix,
1391 const std::string& v_suffix) {
1393 return extract(ex, v, vdef, Dict{{
"lift_shared",
true}, {
"lift_calls",
false},
1394 {
"prefix", v_prefix}, {
"suffix", v_suffix}});
1398 SX CASADI_EXPORT SX::poly_coeff(
const SX& ex,
const SX& x) {
1399 casadi_assert_dev(ex.is_scalar());
1400 casadi_assert_dev(x.is_scalar());
1401 casadi_assert_dev(x.is_symbolic());
1403 std::vector<SXElem> r;
1406 casadi_int mult = 1;
1407 bool success =
false;
1408 for (casadi_int i=0; i<1000; ++i) {
1409 r.push_back((substitute(j, x, 0)/
static_cast<double>(mult)).scalar());
1418 if (!success) casadi_error(
"poly: supplied expression does not appear to be polynomial.");
1420 std::reverse(r.begin(), r.end());
1426 SX CASADI_EXPORT SX::poly_roots(
const SX& p) {
1427 casadi_assert(p.size2()==1,
1428 "poly_root(): supplied parameter must be column vector but got "
1430 casadi_assert_dev(p.is_dense());
1435 }
else if (p.size1()==3) {
1439 SX ds = sqrt(b*b-4*a*c);
1442 SX ret = SX::vertcat({(bm-ds)/a2, (bm+ds)/a2});
1444 }
else if (p.size1()==4) {
1455 SX b = r + 2.0/27*pp*p_-p_*q/3;
1459 SX phi = acos(-b/2/sqrt(-a3*a3*a3));
1461 SX ret = SX::vertcat({cos(phi/3), cos((phi+2*pi)/3), cos((phi+4*pi)/3)});
1466 }
else if (p.size1()==5) {
1474 SX f = c - (3*bb/8);
1475 SX g = d + (bb*b / 8) - b*c/2;
1476 SX h = e - (3*bb*bb/256) + (bb * c/16) - (b*d/4);
1477 SX poly = SX::vertcat({1, f/2, ((f*f -4*h)/16), -g*g/64});
1478 SX y = poly_roots(poly);
1490 SX ret = SX::vertcat({
1496 }
else if (
is_equal(p(p.nnz()-1)->at(0), 0)) {
1497 SX ret = SX::vertcat({poly_roots(p(
range(p.nnz()-1))), 0});
1500 casadi_error(
"poly_root(): can only solve cases for first or second order polynomial. "
1501 "Got order " +
str(p.size1()-1) +
".");
1507 SX CASADI_EXPORT SX::eig_symbolic(
const SX& m) {
1508 casadi_assert(m.size1()==m.size2(),
"eig(): supplied matrix must be square");
1510 std::vector<SX> ret;
1513 std::vector<casadi_int> offset;
1514 std::vector<casadi_int> index;
1515 casadi_int nb = m.sparsity().scc(offset, index);
1517 SX m_perm = m(offset, offset);
1519 SX l = SX::sym(
"l");
1521 for (casadi_int k=0; k<nb; ++k) {
1522 std::vector<casadi_int> r =
range(index.at(k), index.at(k+1));
1524 ret.push_back(poly_roots(poly_coeff(det(SX::eye(r.size())*l-m_perm(r, r)), l)));
1527 return vertcat(ret);
1531 std::vector<SXElem> CASADI_EXPORT SX::call(
const Function& f,
const std::vector<SXElem>& dep) {
1532 return SXElem::call(f, dep);
1536 void CASADI_EXPORT SX::print_split(casadi_int nnz,
const SXElem* nonzeros,
1537 std::vector<std::string>& nz,
1538 std::vector<std::string>& inter) {
1540 std::map<const SXNode*, casadi_int> nodeind;
1541 for (casadi_int i=0; i<nnz; ++i) nonzeros[i]->can_inline(nodeind);
1547 for (casadi_int i=0; i<nnz; ++i) nz.push_back(nonzeros[i]->print_compact(nodeind, inter));
1550 template<> std::vector<SX> CASADI_EXPORT SX::get_input(
const Function& f) {
1554 template<> std::vector<SX> CASADI_EXPORT SX::get_free(
const Function& f) {
1559 Dict CASADI_EXPORT SX::info()
const {
1560 return {{
"function",
Function(
"f", std::vector<SX>{}, std::vector<SX>{*
this})}};
1564 void CASADI_EXPORT SX::to_file(
const std::string& filename,
1566 const std::string& format_hint) {
1567 casadi_error(
"Not implemented");
1570 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
1572 CASADI_EXPORT std::mutex& SX::get_mutex_temp() {
1573 return SXElem::mutex_temp;
1578 #pragma GCC diagnostic push
1579 #pragma GCC diagnostic ignored "-Wattributes"
1583 #pragma GCC diagnostic pop
FunctionInternal * get() const
const SX sx_in(casadi_int iind) const
Get symbolic primitives equivalent to the input expressions.
std::vector< SX > free_sx() const
Get all the free variables of the function.
casadi_int numel() const
Get the number of elements.
bool is_dense() const
Check if the matrix expression is dense.
std::pair< casadi_int, casadi_int > size() const
Get the shape.
casadi_int nnz() const
Get the number of (structural) non-zero elements.
casadi_int size2() const
Get the second dimension (i.e. number of columns)
casadi_int size1() const
Get the first dimension (i.e. number of rows)
std::string dim(bool with_nz=false) const
Get string representation of dimensions.
static Matrix< Scalar > zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
bool is_scalar(bool scalar_and_dense=false) const
Check if the matrix expression is scalar.
static MX find(const MX &x)
Sparse matrix class. SX and DM are specializations.
casadi_int which_output() const
Get the index of evaluation output - only valid when is_output() is true.
std::vector< Scalar > & nonzeros()
static std::vector< std::vector< Matrix< Scalar > > > reverse(const std::vector< Matrix< Scalar > > &ex, const std::vector< Matrix< Scalar > > &arg, const std::vector< std::vector< Matrix< Scalar > > > &v, const Dict &opts=Dict())
static Matrix< Scalar > simplify(const Matrix< Scalar > &x)
static void extract_parametric(const Matrix< Scalar > &expr, const Matrix< Scalar > &par, Matrix< Scalar > &expr_ret, std::vector< Matrix< Scalar > > &symbols, std::vector< Matrix< Scalar >> ¶metric, const Dict &opts)
static Matrix< Scalar > mtimes(const Matrix< Scalar > &x, const Matrix< Scalar > &y)
Matrix< Scalar > T() const
Transpose the matrix.
static void separate_linear(const Matrix< Scalar > &expr, const Matrix< Scalar > &sym_lin, const Matrix< Scalar > &sym_const, Matrix< Scalar > &expr_const, Matrix< Scalar > &expr_lin, Matrix< Scalar > &expr_nonlin)
bool is_smooth() const
Check if smooth.
static void set_max_depth(casadi_int eq_depth=1)
Set or reset the depth to which equalities are being checked for simplifications.
casadi_int n_dep() const
Get the number of dependencies of a binary SXElem.
void get(Matrix< Scalar > &m, bool ind1, const Slice &rr) const
friend Scalar * get_ptr(Matrix< Scalar > &v)
bool __nonzero__() const
Returns the truth value of a Matrix.
const Sparsity & sparsity() const
Const access the sparsity - reference to data member.
bool has_duplicates() const
Detect duplicate symbolic expressions.
bool has_output() const
Check if a multiple output node.
casadi_int element_hash() const
Returns a number that is unique for a given symbolic scalar.
bool is_leaf() const
Check if SX is a leaf of the SX graph.
static Matrix< Scalar > gauss_quadrature(const Matrix< Scalar > &f, const Matrix< Scalar > &x, const Matrix< Scalar > &a, const Matrix< Scalar > &b, casadi_int order=5)
static Matrix< Scalar > pw_lin(const Matrix< Scalar > &t, const Matrix< Scalar > &tval, const Matrix< Scalar > &val)
bool is_regular() const
Checks if expression does not contain NaN or Inf.
Matrix< Scalar > get_output(casadi_int oind) const
Get an output.
static void expand(const Matrix< Scalar > &x, Matrix< Scalar > &weights, Matrix< Scalar > &terms)
Matrix< Scalar > dep(casadi_int ch=0) const
Get expressions of the children of the expression.
void reset_input() const
Reset the marker for an input expression.
static Matrix< Scalar > _sym(const std::string &name, const Sparsity &sp)
bool is_symbolic() const
Check if symbolic (Dense)
static void substitute_inplace(const std::vector< Matrix< Scalar > > &v, std::vector< Matrix< Scalar > > &vdef, std::vector< Matrix< Scalar > > &ex, bool revers)
Function which_function() const
Get function - only valid when is_call() is true.
bool is_commutative() const
Check whether a binary SX is commutative.
static Matrix< Scalar > substitute(const Matrix< Scalar > &ex, const Matrix< Scalar > &v, const Matrix< Scalar > &vdef)
casadi_int op() const
Get operation type.
bool is_output() const
Check if evaluation output.
bool is_valid_input() const
Check if matrix can be used to define function inputs.
bool is_call() const
Check if function call.
std::string name() const
Get name (only if symbolic scalar)
static bool is_equal(const Matrix< Scalar > &x, const Matrix< Scalar > &y, casadi_int depth=0)
static casadi_int get_max_depth()
Get the depth to which equalities are being checked for simplifications.
static Matrix< Scalar > pw_const(const Matrix< Scalar > &t, const Matrix< Scalar > &tval, const Matrix< Scalar > &val)
const Scalar scalar() const
Convert to scalar type.
bool is_op(casadi_int op) const
Is it a certain operation.
The basic scalar symbolic class of CasADi.
SXElem dep(casadi_int ch=0) const
static std::vector< SXElem > call(const Function &f, const std::vector< SXElem > &deps)
bool is_minus_inf() const
static SXElem create(SXNode *node)
SXElem get_output(casadi_int oind) const
Get an output.
SXNode * get() const
Get a pointer to the node.
static bool is_equal(const SXElem &x, const SXElem &y, casadi_int depth=0)
Check equality up to a given depth.
static SXElem sym(const std::string &name)
Create a symbolic primitive.
Internal node class for SXFunction.
bool is_smooth() const
Check if smooth.
static casadi_int eq_depth_
bool is_scalar(bool scalar_and_dense=false) const
Is scalar?
casadi_int nnz() const
Get the number of (structural) non-zeros.
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::vector< bool > _which_depends(const MatType &expr, const MatType &var, casadi_int order, bool tr)
Sparsity _jacobian_sparsity(const MatType &expr, const MatType &var)
SX mtaylor_recursive(const SX &ex, const SX &x, const SX &a, casadi_int order, const std::vector< casadi_int > &order_contributions, const SXElem ¤t_dx=casadi_limits< SXElem >::one, double current_denom=1, casadi_int current_order=1)
MX register_symbol(const MX &node, std::map< MXNode *, MX > &symbol_map, std::vector< MX > &symbol_v, std::vector< MX > ¶metric_v, bool extract_trivial, casadi_int v_offset, const std::string &v_prefix, const std::string &v_suffix)
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.
std::vector< T > reverse(const std::vector< T > &v)
Reverse a list.
Dict extract_from_dict(const Dict &d, const std::string &key, T &value)
Easy access to all the functions for a particular type.
static bool is_binary(unsigned char op)
Is binary operation?
static void fun_linear(unsigned char op, const T *x, const T *y, T *f)
Evaluate function on a const/linear/nonlinear partition.