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_) {
237 "expand requires a scalar expression. Got " + ex2.
dim() +
" instead.");
241 std::vector<std::vector<SXNode*> > terms;
242 std::vector<std::vector<double> > weights;
243 std::map<SXNode*, casadi_int> indices;
246 std::stack<SXNode*> to_be_expanded;
247 to_be_expanded.push(ex.
get());
249 while (!to_be_expanded.empty()) {
252 if (indices.find(to_be_expanded.top()) != indices.end()) {
254 to_be_expanded.pop();
259 std::vector<double> w;
260 std::vector<SXNode*> f;
262 if (to_be_expanded.top()->is_constant()) {
263 w.push_back(to_be_expanded.top()->to_double());
265 }
else if (to_be_expanded.top()->is_symbolic()) {
268 f.push_back(to_be_expanded.top());
271 casadi_assert_dev(to_be_expanded.top()->n_dep());
274 SXNode* node = to_be_expanded.top();
277 (node->op() ==
OP_MUL && (node->dep(0)->is_constant() ||
278 node->dep(1)->is_constant()))) {
280 if (indices.find(node->dep(0).get()) == indices.end()) {
281 to_be_expanded.push(node->dep(0).get());
284 if (indices.find(node->dep(1).get()) == indices.end()) {
285 to_be_expanded.push(node->dep(1).get());
290 casadi_int ind1 = indices[node->dep(0).get()];
291 casadi_int ind2 = indices[node->dep(1).get()];
294 if (node->op() ==
OP_MUL) {
297 if (node->dep(0)->is_constant()) {
298 fac = node->dep(0)->to_double();
302 fac = node->dep(1)->to_double();
306 for (casadi_int i=0; i<w.size(); ++i) w[i] *= fac;
309 if (node->op() ==
OP_ADD) {
310 f = terms[ind1]; f.insert(f.end(), terms[ind2].begin(), terms[ind2].end());
311 w = weights[ind1]; w.insert(w.end(), weights[ind2].begin(), weights[ind2].end());
313 f = terms[ind1]; f.insert(f.end(), terms[ind2].begin(), terms[ind2].end());
316 for (casadi_int i=0; i<weights[ind2].size(); ++i) w.push_back(-weights[ind2][i]);
319 std::vector<double> w_new; w_new.reserve(w.size());
320 std::vector<SXNode*> f_new; f_new.reserve(f.size());
321 std::map<SXNode*, casadi_int> f_ind;
323 for (casadi_int i=0; i<w.size(); i++) {
325 auto it = f_ind.find(f[i]);
326 if (it == f_ind.end()) {
327 w_new.push_back(w[i]);
328 f_new.push_back(f[i]);
329 f_ind[f[i]] = f_new.size()-1;
331 w_new[it->second] += w[i];
346 weights.push_back(w);
348 indices[to_be_expanded.top()] = terms.size()-1;
351 to_be_expanded.pop();
355 casadi_int thisind = indices[ex.
get()];
356 ww =
SX(weights[thisind]);
358 std::vector<SXElem> termsv(terms[thisind].
size());
359 for (casadi_int i=0; i<termsv.size(); ++i)
367 casadi_int n = val.numel();
369 casadi_assert(t.is_scalar(),
"t must be a scalar");
370 casadi_assert(tval.numel() == n-1,
"dimensions do not match");
373 for (casadi_int i=0; i<n-1; ++i) {
374 ret += (val(i+1)-val(i)) * (t>=tval(i));
383 casadi_int N = tval.numel();
384 casadi_assert(N>=2,
"pw_lin: N>=2");
385 casadi_assert(val.numel() == N,
"dimensions do not match");
389 for (casadi_int i=0; i<N-1; ++i)
390 g(i) = (val(i+1)- val(i))/(tval(i+1)-tval(i));
393 SX lseg =
SX(1, N-1);
394 for (casadi_int i=0; i<N-1; ++i)
395 lseg(i) = val(i) + g(i)*(t-tval(i));
403 const SX& b, casadi_int order,
const SX& w) {
404 casadi_assert(order == 5,
"gauss_quadrature: order must be 5");
405 casadi_assert(w.is_empty(),
"gauss_quadrature: empty weights");
412 Function fcn(
"gauss_quadrature", {x}, {f});
418 std::vector<double> xi;
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);
422 xi.push_back(std::sqrt(5 - 2*std::sqrt(10.0/7))/3);
423 xi.push_back(std::sqrt(5 + 2*std::sqrt(10.0/7))/3);
426 std::vector<double> wi;
427 wi.push_back((322-13*std::sqrt(70.0))/900.0);
428 wi.push_back((322+13*std::sqrt(70.0))/900.0);
429 wi.push_back(128/225.0);
430 wi.push_back((322+13*std::sqrt(70.0))/900.0);
431 wi.push_back((322-13*std::sqrt(70.0))/900.0);
434 Function fcn(
"gauss_quadrature", {x}, {f});
435 std::vector<SXElem> f_val(5);
436 for (casadi_int i=0; i<5; ++i)
437 f_val[i] = fcn(
SX(xi[i])).at(0).scalar();
441 for (casadi_int i=0; i<5; ++i)
442 sum += wi[i]*f_val[i];
449 std::vector<SX>& res,
452 for (casadi_int el=0; el<r.nnz(); ++el) {
455 expand(r.nz(el), weights, terms);
458 r.nz(el) =
mtimes(terms.T(), weights);
467 for (casadi_int el=0; el<r.nnz(); ++el) {
470 expand(r.nz(el), weights, terms);
473 r.nz(el) =
mtimes(terms.T(), weights);
480 return transform(std::vector<SX>{x}, opts).at(0);
485 const std::vector<std::vector<GenericType> >& passes,
const Dict& opts) {
486 return transform(std::vector<SX>{x}, passes, opts).at(0);
490 std::vector<SX> CASADI_EXPORT
SX::transform(
const std::vector<SX>& x,
const Dict& opts) {
493 Function f(
"transform", arg, x,
494 {{
"allow_free",
true}, {
"allow_duplicate_io_names",
true}});
495 f = f.transform(opts);
500 std::vector<SX> CASADI_EXPORT
SX::transform(
const std::vector<SX>& x,
501 const std::vector<std::vector<GenericType> >& passes,
const Dict& opts) {
504 Function f(
"transform", arg, x,
505 {{
"allow_free",
true}, {
"allow_duplicate_io_names",
true}});
506 f = f.transform(passes, opts);
511 std::vector<SX> CASADI_EXPORT
512 SX::substitute(
const std::vector<SX>& ex,
const std::vector<SX>& v,
const std::vector<SX>& vdef) {
515 if (v.size()!=vdef.size()) {
516 casadi_warning(
"subtitute: number of symbols to replace ( " +
str(v.size()) +
") "
517 "must match number of expressions (" +
str(vdef.size()) +
") "
518 "to replace them with.");
522 bool all_equal =
true;
523 for (casadi_int k=0; k<v.size(); ++k) {
529 if (all_equal)
return ex;
532 for (casadi_int k=0; k<v.size(); ++k) {
536 std::vector<SX> vdef_mod = vdef;
537 vdef_mod[k] =
SX(v[k].
sparsity(), vdef[k]->at(0),
false);
540 casadi_error(
"Sparsities of v and vdef must match. Got v: "
541 + v[k].
dim() +
" and vdef: " + vdef[k].
dim() +
".");
548 Function F(
"tmp_substitute", v, ex,
Dict{{
"max_io", 0}, {
"allow_free",
true}});
554 return substitute(std::vector<SX>{ex}, std::vector<SX>{v}, std::vector<SX>{vdef}).front();
559 std::vector<SX >& ex,
bool reverse) {
561 casadi_assert_dev(v.size()==vdef.size());
562 for (casadi_int i=0; i<v.size(); ++i) {
563 casadi_assert(v[i].
is_symbolic(),
"the variable is not symbolic");
564 casadi_assert(v[i].
sparsity() == vdef[i].
sparsity(),
"the sparsity patterns of the "
565 "expression and its defining bexpression do not match");
569 if (v.empty())
return;
572 std::vector<SX> f_in;
573 if (!
reverse) f_in.insert(f_in.end(), v.begin(), v.end());
576 std::vector<SX> f_out = vdef;
577 f_out.insert(f_out.end(), ex.begin(), ex.end());
580 Function f(
"tmp_substitute_inplace", f_in, f_out,
Dict{{
"max_io", 0}, {
"allow_free",
true}});
583 SXFunction *ff = f.get<SXFunction>();
584 const std::vector<ScalarAtomic>& algorithm = ff->algorithm_;
585 std::vector<SXElem> work(f.sz_w());
588 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
591 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
594 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
597 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
601 work[it->i0] = vdef.at(it->i1)->at(it->i2);
604 if (it->i0 < v.size()) {
605 vdef.at(it->i0)->at(it->i2) = work[it->i1];
608 work[it->i1] = v.at(it->i0)->at(it->i2);
612 ex.at(it->i0 - v.size())->at(it->i2) = work[it->i1];
615 case OP_CONST: work[it->i0] = *c_it++;
break;
620 CASADI_MATH_FUN_BUILTIN(work[it->i1], work[it->i2], work[it->i0])
624 const casadi_int depth = 2;
625 work[it->i0].assignIfDuplicate(*b_it++, depth);
632 std::vector<SXElem>& symbol_v, std::vector<SXElem>& parametric_v,
633 bool extract_trivial, casadi_int v_offset,
634 const std::string& v_prefix,
const std::string& v_suffix) {
637 auto it = symbol_map.
find(node.
get());
641 if (is_trivial && !extract_trivial) {
645 if (it==symbol_map.end()) {
648 symbol_map[node.
get()] = sym;
651 symbol_v.push_back(sym);
652 parametric_v.push_back(node);
664 SX& expr_ret, std::vector<SX>& symbols, std::vector<SX>& parametric,
const Dict& opts) {
665 std::string v_prefix =
"e_";
666 std::string v_suffix =
"";
667 bool extract_trivial =
false;
668 casadi_int v_offset = 0;
669 for (
auto&&
op : opts) {
670 if (
op.first ==
"prefix") {
671 v_prefix = std::string(
op.second);
672 }
else if (
op.first ==
"suffix") {
673 v_suffix = std::string(
op.second);
674 }
else if (
op.first ==
"offset") {
675 v_offset =
op.second;
676 }
else if (
op.first ==
"extract_trivial") {
677 extract_trivial =
op.second;
679 casadi_error(
"No such option: " + std::string(
op.first));
682 Function f(
"f", std::vector<SX>{par},
683 std::vector<SX>{expr}, {{
"live_variables",
false},
684 {
"max_io", 0}, {
"allow_free",
true}});
685 SXFunction *ff = f.get<SXFunction>();
688 std::vector< SXElem > w(ff->worksize_);
694 std::vector< char > expr_status(ff->worksize_, 0);
697 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
700 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
703 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
706 const SXElem* arg =
get_ptr(par.nonzeros());
710 std::vector<SXElem>& ret = expr_ret.nonzeros();
713 std::map<SXNode*, SXElem> symbol_map;
716 std::vector<SXElem> symbol_v, parametric_v;
719 for (
auto&& a : ff->algorithm_) {
723 expr_status[a.i0] = 1;
726 casadi_assert_dev(a.i0==0);
728 SXElem arg = w[a.i1];
729 if (expr_status[a.i1]==1) {
731 extract_trivial, v_offset, v_prefix, v_suffix);
738 expr_status[a.i0] = 0;
742 expr_status[a.i0] = 2;
746 const auto& m = ff->call_.el.at(a.i1);
747 const SXElem& orig = *b_it++;
748 std::vector<SXElem> deps(m.n_dep);
750 bool identical =
true;
751 for (casadi_int i=0;i<m.n_dep;++i) {
757 for (casadi_int i=0;i<m.n_dep;++i) {
758 max_status = std::max(max_status, expr_status[m.dep[i]]);
761 bool any_tainted = max_status==2;
765 for (casadi_int i=0;i<m.n_dep;++i) {
767 if (expr_status[m.dep[i]]==2)
continue;
769 if (expr_status[m.dep[i]]==0)
continue;
771 w[m.dep[i]] =
register_symbol(w[m.dep[i]], symbol_map, symbol_v, parametric_v,
772 extract_trivial, v_offset, v_prefix, v_suffix);
778 std::vector<SXElem> ret;
781 for (casadi_int i=0;i<m.n_res;++i) {
782 ret.push_back(orig.get_output(i));
785 for (casadi_int i=0;i<m.n_dep;++i) deps[i] = w[m.dep[i]];
790 for (casadi_int i=0;i<m.n_res;++i) {
791 if (m.res[i]>=0) expr_status[m.res[i]] = max_status;
794 for (casadi_int i=0;i<m.n_res;++i) {
795 if (m.res[i]>=0) w[m.res[i]] = ret[i];
804 SXElem w2 = is_binary ? w[a.i2] : 0;
806 char max_status = expr_status[a.i1];
808 max_status = std::max(max_status, expr_status[a.i2]);
810 bool any_tainted = max_status==2;
814 for (
int k=0;k<1+is_binary;++k) {
816 casadi_int el = k==0 ? a.i1 : a.i2;
817 if (expr_status[el]==2)
continue;
819 if (expr_status[el]==0)
continue;
821 SXElem& arg = k==0 ? w1 : w2;
824 extract_trivial, v_offset, v_prefix, v_suffix);
832 CASADI_MATH_FUN_BUILTIN(w1, w2, f)
838 const casadi_int depth = 2;
839 w[a.i0].assignIfDuplicate(*b_it++, depth);
842 expr_status[a.i0] = max_status;
847 symbols.resize(symbol_v.size());
848 parametric.resize(parametric_v.size());
850 for (casadi_int i=0;i<symbol_v.size();++i) {
851 symbols[i] = symbol_v[i];
852 parametric[i] = parametric_v[i];
858 const SX &sym_lin,
const SX &sym_const,
859 SX& expr_const,
SX& expr_lin,
SX& expr_nonlin) {
861 Function f(
"f", std::vector<SX>{sym_const, sym_lin},
862 std::vector<SX>{expr}, {{
"live_variables",
false},
864 SXFunction *ff = f.get<SXFunction>();
869 expr_nonlin =
SX::zeros(expr.sparsity());
871 std::vector<SXElem*> ret = {
872 get_ptr(expr_const.nonzeros()),
874 get_ptr(expr_nonlin.nonzeros())};
877 std::vector< std::array<SXElem, 3> > w(ff->worksize_,
878 std::array<SXElem, 3>{{0, 0, 0}});
880 std::vector<const SXElem*> arg(f.sz_arg());
881 arg[0] =
get_ptr(sym_const.nonzeros());
882 arg[1] =
get_ptr(sym_lin.nonzeros());
885 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
888 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
891 for (
auto&& a : ff->algorithm_) {
894 w[a.i0][a.i1] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
897 casadi_assert_dev(a.i0==0);
898 ret[0][a.i2] = w[a.i1][0];
899 ret[1][a.i2] = w[a.i1][1];
900 ret[2][a.i2] = w[a.i1][2];
903 w[a.i0][0] = *c_it++;
906 w[a.i0][2] = *p_it++;
909 casadi_error(
"Not implemented");
918 bool CASADI_EXPORT SX::depends_on(
const SX &x,
const SX &arg) {
919 if (x.
nnz()==0)
return false;
922 Function temp(
"tmp_depends_on", {arg}, {x}, Dict{{
"max_io", 0}, {
"allow_free",
true}});
925 std::vector<bvec_t> t_in(arg.
nnz(), 1), t_out(x.
nnz());
929 for (casadi_int i=0; i<t_out.size(); ++i) {
930 if (t_out[i])
return true;
937 bool CASADI_EXPORT SX::contains_all(
const std::vector<SX>& v,
const std::vector<SX> &n) {
938 if (n.empty())
return true;
942 for (
const SX& e : v) l.insert(e.scalar().get());
944 size_t l_unique = l.size();
946 for (
const SX& e : n) l.insert(e.scalar().get());
948 return l.size()==l_unique;
952 bool CASADI_EXPORT SX::contains_any(
const std::vector<SX>& v,
const std::vector<SX> &n) {
953 if (n.empty())
return true;
957 for (
const SX& e : v) l.insert(e.scalar().get());
959 size_t l_unique = l.size();
962 for (
const SX& e : n) r.insert(e.scalar().get());
964 size_t r_unique = r.size();
965 for (
const SX& e : n) l.insert(e.scalar().get());
967 return l.size()<l_unique+r_unique;
970 class IncrementalSerializer {
978 IncrementalSerializer() : serializer(ss) {
981 std::string pack(
const SXElem& a) {
984 a.serialize(serializer);
987 a.serialize(serializer);
988 std::string ret = ss.str();
995 std::stringstream ss;
997 std::vector<SXElem> ref;
998 SerializingStream serializer;
1003 std::vector<SX> CASADI_EXPORT SX::cse(
const std::vector<SX>& e) {
1007 Function f(
"f", std::vector<SX>{}, e, {{
"live_variables",
false},
1008 {
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}});
1009 SXFunction *ff = f.get<SXFunction>();
1011 std::vector<SX> ret;
1012 for (casadi_int i=0;i<e.size();++i) {
1013 ret.push_back(SX::zeros(e.at(i).sparsity()));
1017 std::vector<SXElem> w(ff->worksize_);
1019 std::vector<const SXElem*> arg(f.sz_arg());
1024 std::vector<SXElem*> res(f.sz_res());
1025 for (casadi_int i=0;i<e.size();++i) {
1026 res[i] =
get_ptr(ret.at(i).nonzeros());
1029 std::unordered_map<std::string, SXElem > cache;
1030 IncrementalSerializer s;
1033 std::vector<SXElem>::const_iterator b_it = ff->operations_.begin();
1037 for (
auto&& a : ff->algorithm_) {
1047 const SXElem &f = *b_it++;
1048 std::string key = s.pack(f);
1050 auto itk = cache.find(key);
1051 if (itk==cache.end()) {
1059 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
1062 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
1064 std::unordered_map<std::string, Function> function_cache;
1067 for (
auto&& a : ff->algorithm_) {
1070 w[a.i0] = arg[a.i1]==
nullptr ? 0 : arg[a.i1][a.i2];
1071 if (arg[a.i1]!=
nullptr) cache[s.pack(w[a.i0])] = w[a.i0];
1074 if (res[a.i0]!=
nullptr) res[a.i0][a.i2] = w[a.i1];
1078 cache[s.pack(w[a.i0])] = w[a.i0];
1082 cache[s.pack(w[a.i0])] = w[a.i0];
1086 const auto& m = ff->call_.el.at(a.i1);
1089 std::vector<SXElem> deps(m.n_dep);
1090 for (casadi_int i=0;i<m.n_dep;++i) deps[i] = w[m.dep[i]];
1093 std::string key = m.f.serialize();
1094 auto itk = function_cache.find(key);
1095 if (itk==function_cache.end()) {
1096 function_cache[key] = m.f;
1100 std::vector<SXElem> ret = SXElem::call(function_cache[key], deps);
1105 key = s.pack(call_node);
1106 auto it = cache.find(key);
1107 if (it==cache.end()) {
1109 cache[key] = call_node;
1112 call_node = it->second;
1114 for (casadi_int i=0; i<ret.size(); ++i) {
1116 ret[i] = call_node.
get_output(ret[i].which_output());
1121 for (casadi_int i=0;i<m.n_res;++i) {
1122 if (m.res[i]>=0) w[m.res[i]] = ret[i];
1134 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1136 casadi_error(
"Not implemented");
1139 std::string key = s.pack(f);
1141 auto itk = cache.find(key);
1142 if (itk==cache.end()) {
1157 SX CASADI_EXPORT SX::jacobian(
const SX &f,
const SX &x,
const Dict& opts) {
1161 h_opts[
"allow_free"] =
true;
1162 Function h(
"jac_helper", {x}, {f}, h_opts);
1167 SX CASADI_EXPORT SX::hessian(
const SX &ex,
const SX &arg,
SX &g,
const Dict& opts) {
1168 Dict all_opts = opts;
1169 if (!opts.count(
"symmetric")) all_opts[
"symmetric"] =
true;
1170 g = gradient(ex, arg);
1171 return jacobian(g, arg, all_opts);
1175 SX CASADI_EXPORT SX::hessian(
const SX &ex,
const SX &arg,
const Dict& opts) {
1177 return hessian(ex, arg, g, opts);
1181 std::vector<std::vector<SX> > CASADI_EXPORT
1182 SX::forward(
const std::vector<SX> &ex,
const std::vector<SX> &arg,
1183 const std::vector<std::vector<SX> > &v,
const Dict& opts) {
1187 h_opts[
"allow_free"] =
true;
1189 bool always_inline =
false;
1190 bool never_inline =
false;
1191 for (
auto&& op : opts_remainder) {
1192 if (op.first==
"always_inline") {
1193 always_inline = op.second;
1194 }
else if (op.first==
"never_inline") {
1195 never_inline = op.second;
1197 casadi_error(
"No such option: " + std::string(op.first));
1201 Function temp(
"forward_temp", arg, ex, h_opts);
1202 std::vector<std::vector<SX> > ret;
1203 temp->call_forward(arg, ex, v, ret, always_inline, never_inline);
1208 std::vector<std::vector<SX> > CASADI_EXPORT
1209 SX::reverse(
const std::vector<SX> &ex,
const std::vector<SX> &arg,
1210 const std::vector<std::vector<SX> > &v,
const Dict& opts) {
1214 h_opts[
"allow_free"] =
true;
1216 bool always_inline =
false;
1217 bool never_inline =
false;
1218 for (
auto&& op : opts_remainder) {
1219 if (op.first==
"always_inline") {
1220 always_inline = op.second;
1221 }
else if (op.first==
"never_inline") {
1222 never_inline = op.second;
1224 casadi_error(
"No such option: " + std::string(op.first));
1228 Function temp(
"reverse_temp", arg, ex, h_opts);
1229 std::vector<std::vector<SX> > ret;
1230 temp->call_reverse(arg, ex, v, ret, always_inline, never_inline);
1235 std::vector<bool> CASADI_EXPORT SX::which_depends(
const SX &expr,
1236 const SX &var, casadi_int order,
bool tr) {
1241 Sparsity CASADI_EXPORT SX::jacobian_sparsity(
const SX &f,
const SX &x) {
1246 SX CASADI_EXPORT SX::taylor(
const SX& f,
const SX& x,
1247 const SX& a, casadi_int order) {
1248 casadi_assert_dev(x.is_scalar() && a.is_scalar());
1249 if (f.nnz()!=f.numel())
1250 throw CasadiException(
"taylor: not implemented for sparse matrices");
1253 SX result = substitute(ff, x, a);
1257 for (casadi_int i=1; i<=order; i++) {
1258 ff = jacobian(ff, x);
1259 nf*=
static_cast<double>(i);
1260 result+=1/nf * substitute(ff, x, a) * dxa;
1263 return reshape(result, f.size2(), f.size1()).
T();
1267 const std::vector<casadi_int>&order_contributions,
1269 double current_denom=1, casadi_int current_order=1) {
1270 SX result = substitute(ex, x, a)*current_dx/current_denom;
1271 for (casadi_int i=0;i<x.
nnz();i++) {
1272 if (order_contributions[i]<=order) {
1275 order-order_contributions[i],
1276 order_contributions,
1277 current_dx*(x->at(i)-a->at(i)),
1278 current_denom*
static_cast<double>(current_order),
1286 SX CASADI_EXPORT SX::mtaylor(
const SX& f,
const SX& x,
const SX& a, casadi_int order,
1287 const std::vector<casadi_int>& order_contributions) {
1288 casadi_assert(f.nnz()==f.numel() && x.nnz()==x.numel(),
1289 "mtaylor: not implemented for sparse matrices");
1291 casadi_assert(x.nnz()==order_contributions.size(),
1292 "mtaylor: number of non-zero elements in x (" + str(x.nnz())
1293 +
") must match size of order_contributions ("
1294 + str(order_contributions.size()) +
")");
1296 return reshape(mtaylor_recursive(vec(f), x, a, order,
1297 order_contributions),
1298 f.
size2(), f.size1()).T();
1302 SX CASADI_EXPORT SX::mtaylor(
const SX& f,
const SX& x,
const SX& a, casadi_int order) {
1303 return mtaylor(f, x, a, order, std::vector<casadi_int>(x.
nnz(), 1));
1307 casadi_int CASADI_EXPORT SX::n_nodes(
const SX& x) {
1308 Dict opts{{
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}};
1309 Function f(
"tmp_n_nodes", {
SX()}, {x}, opts);
1314 std::string CASADI_EXPORT
1315 SX::print_operator(
const SX& X,
const std::vector<std::string>& args) {
1318 casadi_assert(ndeps==1 || ndeps==2,
"Not a unary or binary operator");
1319 casadi_assert(args.size()==ndeps,
"Wrong number of arguments");
1328 std::vector<SX> CASADI_EXPORT SX::symvar(
const SX& x) {
1329 Dict opts{{
"max_io", 0}, {
"cse",
false}, {
"allow_free",
true}};
1330 Function f(
"tmp_symvar", std::vector<SX>{}, {x}, opts);
1335 void CASADI_EXPORT SX::extract(std::vector<SX>& ex, std::vector<SX>& v_sx,
1336 std::vector<SX>& vdef_sx,
const Dict& opts) {
1338 std::string v_prefix =
"v_", v_suffix =
"";
1339 bool lift_shared =
true, lift_calls =
false;
1340 casadi_int v_ind = 0;
1341 for (
auto&& op : opts) {
1342 if (op.first ==
"prefix") {
1343 v_prefix = std::string(op.second);
1344 }
else if (op.first ==
"suffix") {
1345 v_suffix = std::string(op.second);
1346 }
else if (op.first ==
"lift_shared") {
1347 lift_shared = op.second;
1348 }
else if (op.first ==
"lift_calls") {
1349 lift_calls = op.second;
1350 }
else if (op.first ==
"offset") {
1353 casadi_error(
"No such option: " + std::string(op.first));
1357 casadi_assert(lift_shared,
"Not implemented");
1358 casadi_assert(!lift_calls,
"Not implemented");
1360 Function f(
"tmp_extract", std::vector<SX>(), ex, Dict{{
"max_io", 0}, {
"allow_free",
true}});
1361 SXFunction *ff = f.get<SXFunction>();
1363 const std::vector<ScalarAtomic>& algorithm = ff->algorithm_;
1364 std::vector<SXElem> work(f.sz_w());
1365 std::vector<SXElem> work2 = work;
1367 std::vector<SXElem>::const_iterator b_it=ff->operations_.begin();
1369 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
1371 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
1373 std::vector<casadi_int> usecount(work.size(), 0);
1375 std::vector<SXElem> v, vdef;
1376 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
1382 CASADI_MATH_BINARY_BUILTIN
1384 if (usecount[it->i2]==0) {
1386 }
else if (usecount[it->i2]==1) {
1388 vdef.push_back(work[it->i2]);
1389 usecount[it->i2]=-1;
1394 if (usecount[it->i1]==0) {
1396 }
else if (usecount[it->i1]==1) {
1397 vdef.push_back(work[it->i1]);
1398 usecount[it->i1]=-1;
1407 usecount[it->i0] = -1;
1410 work[it->i0] = *b_it++;
1411 usecount[it->i0] = 0;
1416 std::stringstream v_name;
1417 for (casadi_int i=0; i<vdef.size(); ++i) {
1418 v_name.str(std::string());
1419 v_name << v_prefix << (v_ind++) << v_suffix;
1420 v.push_back(SXElem::sym(v_name.str()));
1423 casadi_assert(vdef.size() < std::numeric_limits<int>::max(),
"Integer overflow");
1425 for (casadi_int i=0; i<vdef.size(); ++i) {
1426 vdef[i].set_temp(
static_cast<int>(i)+1);
1429 std::vector<SXElem> marked = vdef;
1431 b_it=ff->operations_.begin();
1433 for (std::vector<ScalarAtomic>::const_iterator it=algorithm.begin(); it<algorithm.end(); ++it) {
1435 case OP_OUTPUT: ex.at(it->i0)->at(it->i2) = work[it->i1];
break;
1436 case OP_CONST: work2[it->i0] = work[it->i0] = *c_it++;
break;
1437 case OP_PARAMETER: work2[it->i0] = work[it->i0] = *p_it++;
break;
1441 CASADI_MATH_FUN_BUILTIN(work[it->i1], work[it->i2], work[it->i0])
1443 work2[it->i0] = *b_it++;
1445 casadi_int ind = work2[it->i0].get_temp()-1;
1447 vdef.at(ind) = work[it->i0];
1448 work[it->i0] = v.at(ind);
1454 for (std::vector<SXElem>::iterator it=marked.begin(); it!=marked.end(); ++it) {
1458 v_sx.resize(v.size());
1459 std::copy(v.begin(), v.end(), v_sx.begin());
1460 vdef_sx.resize(vdef.size());
1461 std::copy(vdef.begin(), vdef.end(), vdef_sx.begin());
1465 void CASADI_EXPORT SX::shared(std::vector<SX >& ex,
1466 std::vector<SX >& v,
1467 std::vector<SX >& vdef,
1468 const std::string& v_prefix,
1469 const std::string& v_suffix) {
1471 extract(ex, v, vdef, Dict{{
"lift_shared",
true}, {
"lift_calls",
false},
1472 {
"prefix", v_prefix}, {
"suffix", v_suffix}});
1476 SX CASADI_EXPORT SX::poly_coeff(
const SX& ex,
const SX& x) {
1477 casadi_assert_dev(ex.is_scalar());
1478 casadi_assert_dev(x.is_scalar());
1479 casadi_assert_dev(x.is_symbolic());
1481 std::vector<SXElem> r;
1484 casadi_int mult = 1;
1485 bool success =
false;
1486 for (casadi_int i=0; i<1000; ++i) {
1487 r.push_back((substitute(j, x, 0)/
static_cast<double>(mult)).scalar());
1496 if (!success) casadi_error(
"poly: supplied expression does not appear to be polynomial.");
1498 std::reverse(r.begin(), r.end());
1504 SX CASADI_EXPORT SX::poly_roots(
const SX& p) {
1505 casadi_assert(p.size2()==1,
1506 "poly_root(): supplied parameter must be column vector but got "
1508 casadi_assert_dev(p.is_dense());
1513 }
else if (p.size1()==3) {
1517 SX ds = sqrt(b*b-4*a*c);
1520 SX ret = SX::vertcat({(bm-ds)/a2, (bm+ds)/a2});
1522 }
else if (p.size1()==4) {
1533 SX b = r + 2.0/27*pp*p_-p_*q/3;
1537 SX phi = acos(-b/2/sqrt(-a3*a3*a3));
1539 SX ret = SX::vertcat({cos(phi/3), cos((phi+2*pi)/3), cos((phi+4*pi)/3)});
1544 }
else if (p.size1()==5) {
1552 SX f = c - (3*bb/8);
1553 SX g = d + (bb*b / 8) - b*c/2;
1554 SX h = e - (3*bb*bb/256) + (bb * c/16) - (b*d/4);
1555 SX poly = SX::vertcat({1, f/2, ((f*f -4*h)/16), -g*g/64});
1556 SX y = poly_roots(poly);
1568 SX ret = SX::vertcat({
1574 }
else if (
is_equal(p(p.nnz()-1)->at(0), 0)) {
1575 SX ret = SX::vertcat({poly_roots(p(
range(p.nnz()-1))), 0});
1578 casadi_error(
"poly_root(): can only solve cases for first or second order polynomial. "
1579 "Got order " +
str(p.size1()-1) +
".");
1585 SX CASADI_EXPORT SX::det(
const SX& A,
const std::string& lsolver,
const Dict& opts) {
1586 auto& plugin = LinsolInternal::getPlugin(lsolver);
1587 casadi_assert(plugin.exposed.det,
1588 "Linsol plugin '" + lsolver +
"' does not provide a symbolic determinant. "
1589 "Try the 'symbolicqr' plugin.");
1590 return plugin.exposed.det(A, opts);
1594 SX CASADI_EXPORT SX::eig_symbolic(
const SX& m) {
1595 casadi_assert(m.size1()==m.size2(),
"eig(): supplied matrix must be square");
1597 std::vector<SX> ret;
1600 std::vector<casadi_int> offset;
1601 std::vector<casadi_int> index;
1602 casadi_int nb = m.sparsity().scc(offset, index);
1604 SX m_perm = m(offset, offset);
1606 SX l = SX::sym(
"l");
1608 for (casadi_int k=0; k<nb; ++k) {
1609 std::vector<casadi_int> r =
range(index.at(k), index.at(k+1));
1611 ret.push_back(poly_roots(poly_coeff(det(SX::eye(r.size())*l-m_perm(r, r)), l)));
1614 return vertcat(ret);
1618 std::vector<SXElem> CASADI_EXPORT SX::call(
const Function& f,
const std::vector<SXElem>& dep) {
1619 return SXElem::call(f, dep);
1623 void CASADI_EXPORT SX::print_split(casadi_int nnz,
const SXElem* nonzeros,
1624 std::vector<std::string>& nz,
1625 std::vector<std::string>& inter) {
1627 std::map<const SXNode*, casadi_int> nodeind;
1628 for (casadi_int i=0; i<nnz; ++i) nonzeros[i]->can_inline(nodeind);
1634 for (casadi_int i=0; i<nnz; ++i) nz.push_back(nonzeros[i]->print_compact(nodeind, inter));
1637 template<> std::vector<SX> CASADI_EXPORT SX::get_input(
const Function& f) {
1641 template<> std::vector<SX> CASADI_EXPORT SX::get_free(
const Function& f) {
1646 Dict CASADI_EXPORT SX::info()
const {
1647 return {{
"function",
Function(
"f", std::vector<SX>{}, std::vector<SX>{*
this})}};
1651 void CASADI_EXPORT SX::to_file(
const std::string& filename,
1653 const std::string& format_hint) {
1654 casadi_error(
"Not implemented");
1658 bool CASADI_EXPORT SX::simplify_const_folding(std::vector<SX>& arg,
1659 std::vector<SX>& res,
1665 bool CASADI_EXPORT SX::simplify_ref_count(std::vector<SX>& arg,
1666 std::vector<SX>& res,
1668 Dict temp_opts = {{
"live_variables",
false},
1671 {
"allow_free",
true}};
1672 Function f(
"temp", arg, res, temp_opts);
1673 SXFunction *ff = f.get<SXFunction>();
1674 const auto& algorithm_ = ff->algorithm_;
1676 std::vector<casadi_int> rwork(ff->worksize_);
1677 for (
auto&& a : algorithm_) {
1689 const auto& m = ff->call_.el.at(a.i1);
1690 for (casadi_int i=0;i<m.n_dep;++i) {
1697 bool is_binary = casadi_math<SXElem>::is_binary(a.op);
1708 std::vector<const SXElem*> argp(f.sz_arg());
1709 for (casadi_int i=0;i<arg.size();++i) {
1710 argp[i] =
get_ptr(arg.at(i).nonzeros());
1713 std::vector<SXElem*> resp(f.sz_res());
1714 for (casadi_int i=0;i<res.size();++i) {
1715 resp[i] =
get_ptr(res.at(i).nonzeros());
1718 std::vector<SXElem> w(ff->worksize_);
1721 std::vector<SXElem>::const_iterator b_it = ff->operations_.begin();
1724 std::vector<SXElem>::const_iterator c_it = ff->constants_.begin();
1727 std::vector<SXElem>::const_iterator p_it = ff->free_vars_.begin();
1729 for (
auto&& a : algorithm_) {
1732 w[a.i0] = argp[a.i1]==
nullptr ? 0 : argp[a.i1][a.i2];
1735 if (resp[a.i0]!=
nullptr) resp[a.i0][a.i2] = w[a.i1];
1741 w[a.i0] = *p_it++;
break;
1744 const auto& m = ff->call_.el.at(a.i1);
1745 const SXElem& orig = *b_it++;
1746 std::vector<SXElem> deps(m.n_dep);
1747 bool identical =
true;
1749 std::vector<SXElem> ret;
1750 for (casadi_int i=0;i<m.n_dep;++i) {
1751 identical &= SXElem::is_equal(w[m.dep.at(i)], orig->dep(i), 2);
1754 ret = OutputSX::split(orig, m.n_res);
1756 for (casadi_int i=0;i<m.n_dep;++i) deps[i] = w[m.dep[i]];
1757 ret = SXElem::call(m.f, deps);
1759 for (casadi_int i=0;i<m.n_res;++i) {
1760 if (m.res[i]>=0) w[m.res[i]] = ret[i];
1769 if (casadi_math<MX>::is_binary(a.op)) {
1770 f = SXElem::binary(a.op, w[a.i1], w[a.i2], rwork[a.i1]==1, rwork[a.i2]==1);
1771 }
else if (casadi_math<MX>::is_unary(a.op)) {
1772 f = SXElem::unary(a.op, w[a.i1], rwork[a.i1]==1);
1775 CASADI_MATH_FUN_BUILTIN(w[a.i1], w[a.i2], f)
1781 const casadi_int depth = 2;
1782 f.assignIfDuplicate(*b_it++, depth);
1792 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
1794 CASADI_EXPORT std::mutex& SX::get_mutex_temp() {
1795 return SXElem::mutex_temp;
1800 #pragma GCC diagnostic push
1801 #pragma GCC diagnostic ignored "-Wattributes"
1805 #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.