25 #define CASADI_SX_INSTANTIATOR_CPP
26 #include "matrix_impl.hpp"
28 #include "sx_function.hpp"
29 #include "output_sx.hpp"
30 #include "linsol_internal.hpp"
37 casadi_assert(
numel()==1,
38 "Only scalar Matrix could have a truth value, but you "
39 "provided a shape" +
dim());
40 return nonzeros().at(0).__nonzero__();
56 std::vector<SXElem> retv;
62 std::string modname =
name;
63 for (std::string::iterator it=modname.begin(); it!=modname.end(); ++it) {
65 case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case ',':
case ';': *it =
' ';
69 std::istringstream iss(modname);
86 for (casadi_int k=0; k<sp.
nnz(); ++k) {
88 ss <<
name <<
"_" << k;
97 return SX(sp, retv,
false);
104 for (casadi_int i=0; i<
nnz(); ++i) {
111 for (casadi_int i=0; i<
nnz(); ++i) {
112 if (!
nonzeros().at(i).is_regular())
return false;
120 Function temp(
"tmp_is_smooth", {
SX()}, {*
this},
Dict{{
"max_io", 0}, {
"allow_free",
true}});
129 return scalar().__hash__();
134 return scalar().is_leaf();
139 return scalar().is_commutative();
144 for (casadi_int k=0; k<
nnz(); ++k)
145 if (!
nonzeros().at(k)->is_symbolic())
153 return scalar().is_call();
158 return scalar().is_output();
163 return scalar().has_output();
168 return scalar().get_output(oind);
173 return scalar().which_function();
178 return scalar().which_output();
191 casadi_int CASADI_EXPORT
SX::op()
const {
202 for (
auto&& i : nonzeros_) {
203 bool is_duplicate = i.get_temp()!=0;
205 casadi_warning(
"Duplicate expression: " +
str(i));
214 for (
auto&& i : nonzeros_) {
240 std::vector<std::vector<SXNode*> > terms;
241 std::vector<std::vector<double> > weights;
242 std::map<SXNode*, casadi_int> indices;
245 std::stack<SXNode*> to_be_expanded;
246 to_be_expanded.push(ex.
get());
248 while (!to_be_expanded.empty()) {
251 if (indices.find(to_be_expanded.top()) != indices.end()) {
253 to_be_expanded.pop();
258 std::vector<double> w;
259 std::vector<SXNode*> f;
261 if (to_be_expanded.top()->is_constant()) {
262 w.push_back(to_be_expanded.top()->to_double());
264 }
else if (to_be_expanded.top()->is_symbolic()) {
267 f.push_back(to_be_expanded.top());
270 casadi_assert_dev(to_be_expanded.top()->n_dep());
273 SXNode* node = to_be_expanded.top();
276 (node->op() ==
OP_MUL && (node->dep(0)->is_constant() ||
277 node->dep(1)->is_constant()))) {
279 if (indices.find(node->dep(0).get()) == indices.end()) {
280 to_be_expanded.push(node->dep(0).get());
283 if (indices.find(node->dep(1).get()) == indices.end()) {
284 to_be_expanded.push(node->dep(1).get());
289 casadi_int ind1 = indices[node->dep(0).get()];
290 casadi_int ind2 = indices[node->dep(1).get()];
293 if (node->op() ==
OP_MUL) {
296 if (node->dep(0)->is_constant()) {
297 fac = node->dep(0)->to_double();
301 fac = node->dep(1)->to_double();
305 for (casadi_int i=0; i<w.size(); ++i) w[i] *= fac;
308 if (node->op() ==
OP_ADD) {
309 f = terms[ind1]; f.insert(f.end(), terms[ind2].begin(), terms[ind2].end());
310 w = weights[ind1]; w.insert(w.end(), weights[ind2].begin(), weights[ind2].end());
312 f = terms[ind1]; f.insert(f.end(), terms[ind2].begin(), terms[ind2].end());
315 for (casadi_int i=0; i<weights[ind2].size(); ++i) w.push_back(-weights[ind2][i]);
318 std::vector<double> w_new; w_new.reserve(w.size());
319 std::vector<SXNode*> f_new; f_new.reserve(f.size());
320 std::map<SXNode*, casadi_int> f_ind;
322 for (casadi_int i=0; i<w.size(); i++) {
324 auto it = f_ind.find(f[i]);
325 if (it == f_ind.end()) {
326 w_new.push_back(w[i]);
327 f_new.push_back(f[i]);
328 f_ind[f[i]] = f_new.size()-1;
330 w_new[it->second] += w[i];
345 weights.push_back(w);
347 indices[to_be_expanded.top()] = terms.size()-1;
350 to_be_expanded.pop();
354 casadi_int thisind = indices[ex.
get()];
355 ww =
SX(weights[thisind]);
357 std::vector<SXElem> termsv(terms[thisind].
size());
358 for (casadi_int i=0; i<termsv.size(); ++i)
366 casadi_int n = val.numel();
368 casadi_assert(t.is_scalar(),
"t must be a scalar");
369 casadi_assert(tval.numel() == n-1,
"dimensions do not match");
372 for (casadi_int i=0; i<n-1; ++i) {
373 ret += (val(i+1)-val(i)) * (t>=tval(i));
382 casadi_int N = tval.numel();
383 casadi_assert(N>=2,
"pw_lin: N>=2");
384 casadi_assert(val.numel() == N,
"dimensions do not match");
388 for (casadi_int i=0; i<N-1; ++i)
389 g(i) = (val(i+1)- val(i))/(tval(i+1)-tval(i));
392 SX lseg =
SX(1, N-1);
393 for (casadi_int i=0; i<N-1; ++i)
394 lseg(i) = val(i) + g(i)*(t-tval(i));
402 const SX& b, casadi_int order,
const SX& w) {
403 casadi_assert(order == 5,
"gauss_quadrature: order must be 5");
404 casadi_assert(w.is_empty(),
"gauss_quadrature: empty weights");
411 Function fcn(
"gauss_quadrature", {x}, {f});
417 std::vector<double> xi;
418 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);
421 xi.push_back(std::sqrt(5 - 2*std::sqrt(10.0/7))/3);
422 xi.push_back(std::sqrt(5 + 2*std::sqrt(10.0/7))/3);
425 std::vector<double> wi;
426 wi.push_back((322-13*std::sqrt(70.0))/900.0);
427 wi.push_back((322+13*std::sqrt(70.0))/900.0);
428 wi.push_back(128/225.0);
429 wi.push_back((322+13*std::sqrt(70.0))/900.0);
430 wi.push_back((322-13*std::sqrt(70.0))/900.0);
433 Function fcn(
"gauss_quadrature", {x}, {f});
434 std::vector<SXElem> f_val(5);
435 for (casadi_int i=0; i<5; ++i)
436 f_val[i] = fcn(
SX(xi[i])).at(0).scalar();
440 for (casadi_int i=0; i<5; ++i)
441 sum += wi[i]*f_val[i];
448 std::vector<SX>& res,
451 for (casadi_int el=0; el<r.nnz(); ++el) {
454 expand(r.nz(el), weights, terms);
457 r.nz(el) =
mtimes(terms.T(), weights);
466 for (casadi_int el=0; el<r.nnz(); ++el) {
469 expand(r.nz(el), weights, terms);
472 r.nz(el) =
mtimes(terms.T(), weights);
479 return transform(std::vector<SX>{x}, opts).at(0);
484 const std::vector<std::vector<GenericType> >& passes,
const Dict& opts) {
485 return transform(std::vector<SX>{x}, passes, opts).at(0);
489 std::vector<SX> CASADI_EXPORT
SX::transform(
const std::vector<SX>& x,
const Dict& opts) {
492 Function f(
"transform", arg, x,
493 {{
"allow_free",
true}, {
"allow_duplicate_io_names",
true}});
494 f = f.transform(opts);
499 std::vector<SX> CASADI_EXPORT
SX::transform(
const std::vector<SX>& x,
500 const std::vector<std::vector<GenericType> >& passes,
const Dict& opts) {
503 Function f(
"transform", arg, x,
504 {{
"allow_free",
true}, {
"allow_duplicate_io_names",
true}});
505 f = f.transform(passes, opts);
510 std::vector<SX> CASADI_EXPORT
511 SX::substitute(
const std::vector<SX>& ex,
const std::vector<SX>& v,
const std::vector<SX>& vdef) {
514 if (v.size()!=vdef.size()) {
515 casadi_warning(
"subtitute: number of symbols to replace ( " +
str(v.size()) +
") "
516 "must match number of expressions (" +
str(vdef.size()) +
") "
517 "to replace them with.");
521 bool all_equal =
true;
522 for (casadi_int k=0; k<v.size(); ++k) {
528 if (all_equal)
return ex;
531 for (casadi_int k=0; k<v.size(); ++k) {
535 std::vector<SX> vdef_mod = vdef;
536 vdef_mod[k] =
SX(v[k].
sparsity(), vdef[k]->at(0),
false);
539 casadi_error(
"Sparsities of v and vdef must match. Got v: "
540 + v[k].
dim() +
" and vdef: " + vdef[k].
dim() +
".");
547 Function F(
"tmp_substitute", v, ex,
Dict{{
"max_io", 0}, {
"allow_free",
true}});
553 return substitute(std::vector<SX>{ex}, std::vector<SX>{v}, std::vector<SX>{vdef}).front();
558 std::vector<SX >& ex,
bool reverse) {
560 casadi_assert_dev(v.size()==vdef.size());
561 for (casadi_int i=0; i<v.size(); ++i) {
562 casadi_assert(v[i].
is_symbolic(),
"the variable is not symbolic");
563 casadi_assert(v[i].
sparsity() == vdef[i].
sparsity(),
"the sparsity patterns of the "
564 "expression and its defining bexpression do not match");
568 if (v.empty())
return;
571 std::vector<SX> f_in;
572 if (!
reverse) f_in.insert(f_in.end(), v.begin(), v.end());
575 std::vector<SX> f_out = vdef;
576 f_out.insert(f_out.end(), ex.begin(), ex.end());
579 Function f(
"tmp_substitute_inplace", f_in, f_out,
Dict{{
"max_io", 0}, {
"allow_free",
true}});
582 SXFunction *ff = f.get<SXFunction>();
583 const std::vector<ScalarAtomic>& algorithm = ff->algorithm_;
584 std::vector<SXElem> work(f.sz_w());
587 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
590 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
593 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
596 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
600 work[it->i0] = vdef.at(it->i1)->at(it->i2);
603 if (it->i0 < v.size()) {
604 vdef.at(it->i0)->at(it->i2) = work[it->i1];
607 work[it->i1] = v.at(it->i0)->at(it->i2);
611 ex.at(it->i0 - v.size())->at(it->i2) = work[it->i1];
614 case OP_CONST: work[it->i0] = *c_it++;
break;
619 CASADI_MATH_FUN_BUILTIN(work[it->i1], work[it->i2], work[it->i0])
623 const casadi_int depth = 2;
624 work[it->i0].assignIfDuplicate(*b_it++, depth);
631 std::vector<SXElem>& symbol_v, std::vector<SXElem>& parametric_v,
632 bool extract_trivial, casadi_int v_offset,
633 const std::string& v_prefix,
const std::string& v_suffix) {
636 auto it = symbol_map.
find(node.
get());
640 if (is_trivial && !extract_trivial) {
644 if (it==symbol_map.end()) {
647 symbol_map[node.
get()] = sym;
650 symbol_v.push_back(sym);
651 parametric_v.push_back(node);
663 SX& expr_ret, std::vector<SX>& symbols, std::vector<SX>& parametric,
const Dict& opts) {
664 std::string v_prefix =
"e_";
665 std::string v_suffix =
"";
666 bool extract_trivial =
false;
667 casadi_int v_offset = 0;
668 for (
auto&&
op : opts) {
669 if (
op.first ==
"prefix") {
670 v_prefix = std::string(
op.second);
671 }
else if (
op.first ==
"suffix") {
672 v_suffix = std::string(
op.second);
673 }
else if (
op.first ==
"offset") {
674 v_offset =
op.second;
675 }
else if (
op.first ==
"extract_trivial") {
676 extract_trivial =
op.second;
678 casadi_error(
"No such option: " + std::string(
op.first));
681 Function f(
"f", std::vector<SX>{par},
682 std::vector<SX>{expr}, {{
"live_variables",
false},
683 {
"max_io", 0}, {
"allow_free",
true}});
684 SXFunction *ff = f.get<SXFunction>();
687 std::vector< SXElem > w(ff->worksize_);
693 std::vector< char > expr_status(ff->worksize_, 0);
696 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
699 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
702 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
705 const SXElem* arg =
get_ptr(par.nonzeros());
709 std::vector<SXElem>& ret = expr_ret.nonzeros();
712 std::map<SXNode*, SXElem> symbol_map;
715 std::vector<SXElem> symbol_v, parametric_v;
718 for (
auto&& a : ff->algorithm_) {
722 expr_status[a.i0] = 1;
725 casadi_assert_dev(a.i0==0);
727 SXElem arg = w[a.i1];
728 if (expr_status[a.i1]==1) {
730 extract_trivial, v_offset, v_prefix, v_suffix);
737 expr_status[a.i0] = 0;
741 expr_status[a.i0] = 2;
745 const auto& m = ff->call_.el.at(a.i1);
746 const SXElem& orig = *b_it++;
747 std::vector<SXElem> deps(m.n_dep);
749 bool identical =
true;
750 for (casadi_int i=0;i<m.n_dep;++i) {
756 for (casadi_int i=0;i<m.n_dep;++i) {
757 max_status = std::max(max_status, expr_status[m.dep[i]]);
760 bool any_tainted = max_status==2;
764 for (casadi_int i=0;i<m.n_dep;++i) {
766 if (expr_status[m.dep[i]]==2)
continue;
768 if (expr_status[m.dep[i]]==0)
continue;
770 w[m.dep[i]] =
register_symbol(w[m.dep[i]], symbol_map, symbol_v, parametric_v,
771 extract_trivial, v_offset, v_prefix, v_suffix);
777 std::vector<SXElem> ret;
780 for (casadi_int i=0;i<m.n_res;++i) {
781 ret.push_back(orig.get_output(i));
784 for (casadi_int i=0;i<m.n_dep;++i) deps[i] = w[m.dep[i]];
789 for (casadi_int i=0;i<m.n_res;++i) {
790 if (m.res[i]>=0) expr_status[m.res[i]] = max_status;
793 for (casadi_int i=0;i<m.n_res;++i) {
794 if (m.res[i]>=0) w[m.res[i]] = ret[i];
803 SXElem w2 = is_binary ? w[a.i2] : 0;
805 char max_status = expr_status[a.i1];
807 max_status = std::max(max_status, expr_status[a.i2]);
809 bool any_tainted = max_status==2;
813 for (
int k=0;k<1+is_binary;++k) {
815 casadi_int el = k==0 ? a.i1 : a.i2;
816 if (expr_status[el]==2)
continue;
818 if (expr_status[el]==0)
continue;
820 SXElem& arg = k==0 ? w1 : w2;
823 extract_trivial, v_offset, v_prefix, v_suffix);
831 CASADI_MATH_FUN_BUILTIN(w1, w2, f)
837 const casadi_int depth = 2;
838 w[a.i0].assignIfDuplicate(*b_it++, depth);
841 expr_status[a.i0] = max_status;
846 symbols.resize(symbol_v.size());
847 parametric.resize(parametric_v.size());
849 for (casadi_int i=0;i<symbol_v.size();++i) {
850 symbols[i] = symbol_v[i];
851 parametric[i] = parametric_v[i];
857 const SX &sym_lin,
const SX &sym_const,
858 SX& expr_const,
SX& expr_lin,
SX& expr_nonlin) {
860 Function f(
"f", std::vector<SX>{sym_const, sym_lin},
861 std::vector<SX>{expr}, {{
"live_variables",
false},
863 SXFunction *ff = f.get<SXFunction>();
868 expr_nonlin =
SX::zeros(expr.sparsity());
870 std::vector<SXElem*> ret = {
871 get_ptr(expr_const.nonzeros()),
873 get_ptr(expr_nonlin.nonzeros())};
876 std::vector< std::array<SXElem, 3> > w(ff->worksize_,
877 std::array<SXElem, 3>{{0, 0, 0}});
879 std::vector<const SXElem*> arg(f.sz_arg());
880 arg[0] =
get_ptr(sym_const.nonzeros());
881 arg[1] =
get_ptr(sym_lin.nonzeros());
884 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
887 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
890 for (
auto&& a : ff->algorithm_) {
893 w[a.i0][a.i1] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
896 casadi_assert_dev(a.i0==0);
897 ret[0][a.i2] = w[a.i1][0];
898 ret[1][a.i2] = w[a.i1][1];
899 ret[2][a.i2] = w[a.i1][2];
902 w[a.i0][0] = *c_it++;
905 w[a.i0][2] = *p_it++;
908 casadi_error(
"Not implemented");
917 bool CASADI_EXPORT SX::depends_on(
const SX &x,
const SX &arg) {
918 if (x.
nnz()==0)
return false;
921 Function temp(
"tmp_depends_on", {arg}, {x},
Dict{{
"max_io", 0}, {
"allow_free",
true}});
924 std::vector<bvec_t> t_in(arg.
nnz(), 1), t_out(x.
nnz());
928 for (casadi_int i=0; i<t_out.size(); ++i) {
929 if (t_out[i])
return true;
936 bool CASADI_EXPORT SX::contains_all(
const std::vector<SX>& v,
const std::vector<SX> &n) {
937 if (n.empty())
return true;
941 for (
const SX& e : v) l.insert(e.scalar().get());
943 size_t l_unique = l.size();
945 for (
const SX& e : n) l.insert(e.scalar().get());
947 return l.size()==l_unique;
951 bool CASADI_EXPORT SX::contains_any(
const std::vector<SX>& v,
const std::vector<SX> &n) {
952 if (n.empty())
return true;
956 for (
const SX& e : v) l.insert(e.scalar().get());
958 size_t l_unique = l.size();
961 for (
const SX& e : n) r.insert(e.scalar().get());
963 size_t r_unique = r.size();
964 for (
const SX& e : n) l.insert(e.scalar().get());
966 return l.size()<l_unique+r_unique;
969 class IncrementalSerializer {
977 IncrementalSerializer() : serializer(ss) {
980 std::string pack(
const SXElem& a) {
983 a.serialize(serializer);
986 a.serialize(serializer);
987 std::string ret = ss.str();
994 std::stringstream ss;
996 std::vector<SXElem> ref;
997 SerializingStream serializer;
1002 std::vector<SX> CASADI_EXPORT SX::cse(
const std::vector<SX>& e) {
1006 Function f(
"f", std::vector<SX>{}, e, {{
"live_variables",
false},
1007 {
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}});
1008 SXFunction *ff = f.get<SXFunction>();
1010 std::vector<SX> ret;
1011 for (casadi_int i=0;i<e.size();++i) {
1012 ret.push_back(SX::zeros(e.at(i).sparsity()));
1016 std::vector<SXElem> w(ff->worksize_);
1018 std::vector<const SXElem*> arg(f.sz_arg());
1023 std::vector<SXElem*> res(f.sz_res());
1024 for (casadi_int i=0;i<e.size();++i) {
1025 res[i] =
get_ptr(ret.at(i).nonzeros());
1028 std::unordered_map<std::string, SXElem > cache;
1029 IncrementalSerializer s;
1032 std::vector<SXElem>::const_iterator b_it = ff->operations_.begin();
1036 for (
auto&& a : ff->algorithm_) {
1046 const SXElem &f = *b_it++;
1047 std::string key = s.pack(f);
1049 auto itk = cache.find(key);
1050 if (itk==cache.end()) {
1058 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
1061 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
1063 std::unordered_map<std::string, Function> function_cache;
1066 for (
auto&& a : ff->algorithm_) {
1069 w[a.i0] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
1070 if (arg[a.i1]!=
nullptr) cache[s.pack(w[a.i0])] = w[a.i0];
1073 if (res[a.i0]!=
nullptr) res[a.i0][a.i2] = w[a.i1];
1077 cache[s.pack(w[a.i0])] = w[a.i0];
1081 cache[s.pack(w[a.i0])] = w[a.i0];
1085 const auto& m = ff->call_.el.at(a.i1);
1088 std::vector<SXElem> deps(m.n_dep);
1089 for (casadi_int i=0;i<m.n_dep;++i) deps[i] = w[m.dep[i]];
1092 std::string key = m.f.serialize();
1093 auto itk = function_cache.find(key);
1094 if (itk==function_cache.end()) {
1095 function_cache[key] = m.f;
1099 std::vector<SXElem> ret = SXElem::call(function_cache[key], deps);
1104 key = s.pack(call_node);
1105 auto it = cache.find(key);
1106 if (it==cache.end()) {
1108 cache[key] = call_node;
1111 call_node = it->second;
1113 for (casadi_int i=0; i<ret.size(); ++i) {
1115 ret[i] = call_node.
get_output(ret[i].which_output());
1120 for (casadi_int i=0;i<m.n_res;++i) {
1121 if (m.res[i]>=0) w[m.res[i]] = ret[i];
1133 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1135 casadi_error("Not implemented");
1138 std::
string key = s.pack(f);
1140 auto itk = cache.find(key);
1141 if (itk==cache.end()) {
1156 SX CASADI_EXPORT SX::jacobian(
const SX &f,
const SX &x,
const Dict& opts) {
1160 h_opts[
"allow_free"] =
true;
1161 Function h(
"jac_helper", {x}, {f}, h_opts);
1162 return h.
get<SXFunction>()->jac(opts_remainder).at(0);
1166 SX CASADI_EXPORT SX::hessian(
const SX &ex,
const SX &arg,
SX &g,
const Dict& opts) {
1167 Dict all_opts = opts;
1168 if (!opts.count(
"symmetric")) all_opts[
"symmetric"] =
true;
1169 g = gradient(ex, arg);
1170 return jacobian(g, arg, all_opts);
1174 SX CASADI_EXPORT SX::hessian(
const SX &ex,
const SX &arg,
const Dict& opts) {
1176 return hessian(ex, arg, g, opts);
1180 std::vector<std::vector<SX> > CASADI_EXPORT
1181 SX::forward(
const std::vector<SX> &ex,
const std::vector<SX> &arg,
1182 const std::vector<std::vector<SX> > &v,
const Dict& opts) {
1186 h_opts[
"allow_free"] =
true;
1188 bool always_inline =
false;
1189 bool never_inline =
false;
1190 for (
auto&& op : opts_remainder) {
1191 if (op.first==
"always_inline") {
1192 always_inline = op.second;
1193 }
else if (op.first==
"never_inline") {
1194 never_inline = op.second;
1196 casadi_error(
"No such option: " + std::string(op.first));
1200 Function temp(
"forward_temp", arg, ex, h_opts);
1201 std::vector<std::vector<SX> > ret;
1202 temp->call_forward(arg, ex, v, ret, always_inline, never_inline);
1207 std::vector<std::vector<SX> > CASADI_EXPORT
1208 SX::reverse(
const std::vector<SX> &ex,
const std::vector<SX> &arg,
1209 const std::vector<std::vector<SX> > &v,
const Dict& opts) {
1213 h_opts[
"allow_free"] =
true;
1215 bool always_inline =
false;
1216 bool never_inline =
false;
1217 for (
auto&& op : opts_remainder) {
1218 if (op.first==
"always_inline") {
1219 always_inline = op.second;
1220 }
else if (op.first==
"never_inline") {
1221 never_inline = op.second;
1223 casadi_error(
"No such option: " + std::string(op.first));
1227 Function temp(
"reverse_temp", arg, ex, h_opts);
1228 std::vector<std::vector<SX> > ret;
1229 temp->call_reverse(arg, ex, v, ret, always_inline, never_inline);
1234 std::vector<bool> CASADI_EXPORT SX::which_depends(
const SX &expr,
1235 const SX &var, casadi_int order,
bool tr) {
1240 Sparsity CASADI_EXPORT SX::jacobian_sparsity(
const SX &f,
const SX &x) {
1245 SX CASADI_EXPORT SX::taylor(
const SX& f,
const SX& x,
1246 const SX& a, casadi_int order) {
1247 casadi_assert_dev(x.is_scalar() && a.is_scalar());
1248 if (f.nnz()!=f.numel())
1249 throw CasadiException(
"taylor: not implemented for sparse matrices");
1252 SX result = substitute(ff, x, a);
1256 for (casadi_int i=1; i<=order; i++) {
1257 ff = jacobian(ff, x);
1258 nf*=
static_cast<double>(i);
1259 result+=1/nf * substitute(ff, x, a) * dxa;
1262 return reshape(result, f.size2(), f.size1()).
T();
1266 const std::vector<casadi_int>&order_contributions,
1268 double current_denom=1, casadi_int current_order=1) {
1269 SX result = substitute(ex, x, a)*current_dx/current_denom;
1270 for (casadi_int i=0;i<x.
nnz();i++) {
1271 if (order_contributions[i]<=order) {
1274 order-order_contributions[i],
1275 order_contributions,
1276 current_dx*(x->at(i)-a->at(i)),
1277 current_denom*
static_cast<double>(current_order),
1285 SX CASADI_EXPORT SX::mtaylor(
const SX& f,
const SX& x,
const SX& a, casadi_int order,
1286 const std::vector<casadi_int>& order_contributions) {
1287 casadi_assert(f.nnz()==f.numel() && x.nnz()==x.numel(),
1288 "mtaylor: not implemented for sparse matrices");
1290 casadi_assert(x.nnz()==order_contributions.size(),
1291 "mtaylor: number of non-zero elements in x (" + str(x.nnz())
1292 +
") must match size of order_contributions ("
1293 + str(order_contributions.size()) +
")");
1295 return reshape(mtaylor_recursive(vec(f), x, a, order,
1296 order_contributions),
1297 f.
size2(), f.size1()).T();
1301 SX CASADI_EXPORT SX::mtaylor(
const SX& f,
const SX& x,
const SX& a, casadi_int order) {
1302 return mtaylor(f, x, a, order, std::vector<casadi_int>(x.nnz(), 1));
1306 casadi_int CASADI_EXPORT SX::n_nodes(
const SX& x) {
1307 Dict opts{{
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}};
1308 Function f(
"tmp_n_nodes", {
SX()}, {x}, opts);
1313 std::string CASADI_EXPORT
1314 SX::print_operator(
const SX& X,
const std::vector<std::string>& args) {
1317 casadi_assert(ndeps==1 || ndeps==2,
"Not a unary or binary operator");
1318 casadi_assert(args.size()==ndeps,
"Wrong number of arguments");
1327 std::vector<SX> CASADI_EXPORT SX::symvar(
const SX& x) {
1328 Dict opts{{
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}};
1329 Function f(
"tmp_symvar", std::vector<SX>{}, {x}, opts);
1334 void CASADI_EXPORT SX::extract(std::vector<SX>& ex, std::vector<SX>& v_sx,
1335 std::vector<SX>& vdef_sx,
const Dict& opts) {
1337 std::string v_prefix =
"v_", v_suffix =
"";
1338 bool lift_shared =
true, lift_calls =
false;
1339 casadi_int v_ind = 0;
1340 for (
auto&& op : opts) {
1341 if (op.first ==
"prefix") {
1342 v_prefix = std::string(op.second);
1343 }
else if (op.first ==
"suffix") {
1344 v_suffix = std::string(op.second);
1345 }
else if (op.first ==
"lift_shared") {
1346 lift_shared = op.second;
1347 }
else if (op.first ==
"lift_calls") {
1348 lift_calls = op.second;
1349 }
else if (op.first ==
"offset") {
1352 casadi_error(
"No such option: " + std::string(op.first));
1356 casadi_assert(lift_shared,
"Not implemented");
1357 casadi_assert(!lift_calls,
"Not implemented");
1359 Function f(
"tmp_extract", std::vector<SX>(), ex, Dict{{
"max_io", 0}, {
"allow_free",
true}});
1360 SXFunction *ff = f.get<SXFunction>();
1362 const std::vector<ScalarAtomic>& algorithm = ff->algorithm_;
1363 std::vector<SXElem> work(f.sz_w());
1364 std::vector<SXElem> work2 = work;
1366 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
1368 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
1370 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
1372 std::vector<casadi_int> usecount(work.size(), 0);
1374 std::vector<SXElem> v, vdef;
1375 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
1381 CASADI_MATH_BINARY_BUILTIN
1383 if (usecount[it->i2]==0) {
1385 }
else if (usecount[it->i2]==1) {
1387 vdef.push_back(work[it->i2]);
1388 usecount[it->i2]=-1;
1393 if (usecount[it->i1]==0) {
1395 }
else if (usecount[it->i1]==1) {
1396 vdef.push_back(work[it->i1]);
1397 usecount[it->i1]=-1;
1406 usecount[it->i0] = -1;
1409 work[it->i0] = *b_it++;
1410 usecount[it->i0] = 0;
1415 std::stringstream v_name;
1416 for (casadi_int i=0; i<vdef.size(); ++i) {
1417 v_name.str(std::string());
1418 v_name << v_prefix << (v_ind++) << v_suffix;
1419 v.push_back(SXElem::sym(v_name.str()));
1422 casadi_assert(vdef.size() < std::numeric_limits<int>::max(),
"Integer overflow");
1424 for (casadi_int i=0; i<vdef.size(); ++i) {
1425 vdef[i].set_temp(
static_cast<int>(i)+1);
1428 std::vector<SXElem> marked = vdef;
1430 b_it=ff->operations_.begin();
1432 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
1434 case OP_OUTPUT: ex.at(it->i0)->at(it->i2) = work[it->i1];
break;
1435 case OP_CONST: work2[it->i0] = work[it->i0] = *c_it++;
break;
1436 case OP_PARAMETER: work2[it->i0] = work[it->i0] = *p_it++;
break;
1440 CASADI_MATH_FUN_BUILTIN(work[it->i1], work[it->i2], work[it->i0])
1442 work2[it->i0] = *b_it++;
1444 casadi_int ind = work2[it->i0].get_temp()-1;
1446 vdef.at(ind) = work[it->i0];
1447 work[it->i0] = v.at(ind);
1453 for (std::vector<SXElem>::iterator it=marked.begin(); it!=marked.end(); ++it) {
1457 v_sx.resize(v.size());
1458 std::copy(v.begin(), v.end(), v_sx.begin());
1459 vdef_sx.resize(vdef.size());
1460 std::copy(vdef.begin(), vdef.end(), vdef_sx.begin());
1464 void CASADI_EXPORT SX::shared(std::vector<SX >& ex,
1465 std::vector<SX >& v,
1466 std::vector<SX >& vdef,
1467 const std::string& v_prefix,
1468 const std::string& v_suffix) {
1470 extract(ex, v, vdef, Dict{{
"lift_shared",
true}, {
"lift_calls",
false},
1471 {
"prefix", v_prefix}, {
"suffix", v_suffix}});
1475 SX CASADI_EXPORT SX::poly_coeff(
const SX& ex,
const SX& x) {
1476 casadi_assert_dev(ex.is_scalar());
1477 casadi_assert_dev(x.is_scalar());
1478 casadi_assert_dev(x.is_symbolic());
1480 std::vector<SXElem> r;
1483 casadi_int mult = 1;
1484 bool success =
false;
1485 for (casadi_int i=0; i<1000; ++i) {
1486 r.push_back((substitute(j, x, 0)/
static_cast<double>(mult)).scalar());
1495 if (!success) casadi_error(
"poly: supplied expression does not appear to be polynomial.");
1497 std::reverse(r.begin(), r.end());
1503 SX CASADI_EXPORT SX::poly_roots(
const SX& p) {
1504 casadi_assert(p.size2()==1,
1505 "poly_root(): supplied parameter must be column vector but got "
1507 casadi_assert_dev(p.is_dense());
1512 }
else if (p.size1()==3) {
1516 SX ds = sqrt(b*b-4*a*c);
1519 SX ret = SX::vertcat({(bm-ds)/a2, (bm+ds)/a2});
1521 }
else if (p.size1()==4) {
1532 SX b = r + 2.0/27*pp*p_-p_*q/3;
1536 SX phi = acos(-b/2/sqrt(-a3*a3*a3));
1538 SX ret = SX::vertcat({cos(phi/3), cos((phi+2*pi)/3), cos((phi+4*pi)/3)});
1543 }
else if (p.size1()==5) {
1551 SX f = c - (3*bb/8);
1552 SX g = d + (bb*b / 8) - b*c/2;
1553 SX h = e - (3*bb*bb/256) + (bb * c/16) - (b*d/4);
1554 SX poly = SX::vertcat({1, f/2, ((f*f -4*h)/16), -g*g/64});
1555 SX y = poly_roots(poly);
1567 SX ret = SX::vertcat({
1573 }
else if (
is_equal(p(p.nnz()-1)->at(0), 0)) {
1574 SX ret = SX::vertcat({poly_roots(p(
range(p.nnz()-1))), 0});
1577 casadi_error(
"poly_root(): can only solve cases for first or second order polynomial. "
1578 "Got order " +
str(p.size1()-1) +
".");
1584 SX CASADI_EXPORT SX::det(
const SX& A,
const std::string& lsolver,
const Dict& opts) {
1585 auto& plugin = LinsolInternal::getPlugin(lsolver);
1586 casadi_assert(plugin.exposed.det,
1587 "Linsol plugin '" + lsolver +
"' does not provide a symbolic determinant. "
1588 "Try the 'symbolicqr' plugin.");
1589 return plugin.exposed.det(A, opts);
1593 SX CASADI_EXPORT SX::eig_symbolic(
const SX& m) {
1594 casadi_assert(m.size1()==m.size2(),
"eig(): supplied matrix must be square");
1596 std::vector<SX> ret;
1599 std::vector<casadi_int> offset;
1600 std::vector<casadi_int> index;
1601 casadi_int nb = m.sparsity().scc(offset, index);
1603 SX m_perm = m(offset, offset);
1605 SX l = SX::sym(
"l");
1607 for (casadi_int k=0; k<nb; ++k) {
1608 std::vector<casadi_int> r =
range(index.at(k), index.at(k+1));
1610 ret.push_back(poly_roots(poly_coeff(det(SX::eye(r.size())*l-m_perm(r, r)), l)));
1613 return vertcat(ret);
1617 std::vector<SXElem> CASADI_EXPORT SX::call(
const Function& f,
const std::vector<SXElem>& dep) {
1618 return SXElem::call(f, dep);
1622 void CASADI_EXPORT SX::print_split(casadi_int nnz,
const SXElem* nonzeros,
1623 std::vector<std::string>& nz,
1624 std::vector<std::string>& inter) {
1626 std::map<const SXNode*, casadi_int> nodeind;
1627 for (casadi_int i=0; i<nnz; ++i) nonzeros[i]->can_inline(nodeind);
1633 for (casadi_int i=0; i<nnz; ++i) nz.push_back(nonzeros[i]->print_compact(nodeind, inter));
1636 template<> std::vector<SX> CASADI_EXPORT SX::get_input(
const Function& f) {
1640 template<> std::vector<SX> CASADI_EXPORT SX::get_free(
const Function& f) {
1645 Dict CASADI_EXPORT SX::info()
const {
1646 return {{
"function",
Function(
"f", std::vector<SX>{}, std::vector<SX>{*
this})}};
1650 void CASADI_EXPORT SX::to_file(
const std::string& filename,
1652 const std::string& format_hint) {
1653 casadi_error(
"Not implemented");
1657 bool CASADI_EXPORT SX::simplify_const_folding(std::vector<SX>& arg,
1658 std::vector<SX>& res,
1664 bool CASADI_EXPORT SX::simplify_ref_count(std::vector<SX>& arg,
1665 std::vector<SX>& res,
1667 Dict temp_opts = {{
"live_variables",
false},
1670 {
"allow_free",
true}};
1671 Function f(
"temp", arg, res, temp_opts);
1672 SXFunction *ff = f.get<SXFunction>();
1673 const auto& algorithm_ = ff->algorithm_;
1675 std::vector<casadi_int> rwork(ff->worksize_);
1676 for (
auto&& a : algorithm_) {
1688 const auto& m = ff->call_.el.at(a.i1);
1689 for (casadi_int i=0;i<m.n_dep;++i) {
1696 bool is_binary = casadi_math<SXElem>::is_binary(a.op);
1707 std::vector<const SXElem*> argp(f.sz_arg());
1708 for (casadi_int i=0;i<arg.size();++i) {
1709 argp[i] =
get_ptr(arg.at(i).nonzeros());
1712 std::vector<SXElem*> resp(f.sz_res());
1713 for (casadi_int i=0;i<res.size();++i) {
1714 resp[i] =
get_ptr(res.at(i).nonzeros());
1717 std::vector<SXElem> w(ff->worksize_);
1720 std::vector<SXElem>::const_iterator b_it = ff->operations_.begin();
1723 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
1726 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
1728 for (
auto&& a : algorithm_) {
1731 w[a.i0] = argp[a.i1]==
nullptr ? 0 : argp[a.i1][a.i2];
1734 if (resp[a.i0]!=
nullptr) resp[a.i0][a.i2] = w[a.i1];
1740 w[a.i0] = *p_it++;
break;
1743 const auto& m = ff->call_.el.at(a.i1);
1744 const SXElem& orig = *b_it++;
1745 std::vector<SXElem> deps(m.n_dep);
1746 bool identical =
true;
1748 std::vector<SXElem> ret;
1749 for (casadi_int i=0;i<m.n_dep;++i) {
1750 identical &= SXElem::is_equal(w[m.dep.at(i)], orig->dep(i), 2);
1753 ret = OutputSX::split(orig, m.n_res);
1755 for (casadi_int i=0;i<m.n_dep;++i) deps[i] = w[m.dep[i]];
1756 ret = SXElem::call(m.f, deps);
1758 for (casadi_int i=0;i<m.n_res;++i) {
1759 if (m.res[i]>=0) w[m.res[i]] = ret[i];
1768 if (casadi_math<MX>::is_binary(a.op)) {
1769 f = SXElem::binary(a.op, w[a.i1], w[a.i2], rwork[a.i1]==1, rwork[a.i2]==1);
1770 }
else if (casadi_math<MX>::is_unary(a.op)) {
1771 f = SXElem::unary(a.op, w[a.i1], rwork[a.i1]==1);
1774 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1780 const casadi_int depth = 2;
1781 f.assignIfDuplicate(*b_it++, depth);
1791 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
1793 CASADI_EXPORT std::mutex& SX::get_mutex_temp() {
1794 return SXElem::mutex_temp;
1799 #pragma GCC diagnostic push
1800 #pragma GCC diagnostic ignored "-Wattributes"
1804 #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)
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)
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.
static Matrix< Scalar > transform(const Matrix< Scalar > &x, const Dict &opts=Dict())
static std::vector< Matrix< Scalar > > symvar(const Matrix< Scalar > &x)
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 > mtimes(const Matrix< Scalar > &x, const Matrix< Scalar > &y, const std::string &blas="reference")
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 bool simplify_combine_terms(std::vector< Matrix< Scalar > > &arg, std::vector< Matrix< Scalar > > &res, const Dict &opts=Dict())
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_
static MatType veccat(const std::vector< MatType > &x)
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.