mx.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "mx_node.hpp"
27 #include "dump.hpp"
28 #include "symbolic_mx.hpp"
29 #include "constant_mx.hpp"
30 #include "multiple_output.hpp"
31 #include "casadi_misc.hpp"
32 #include "norm.hpp"
33 #include "calculus.hpp"
34 #include "mx_function.hpp"
35 #include "linsol.hpp"
36 #include "expm.hpp"
37 #include "serializing_stream.hpp"
38 #include "im.hpp"
39 #include "bspline.hpp"
40 #include "kron.hpp"
41 #include "casadi_call.hpp"
42 #include <array>
43 
44 // Throw informative error message
45 #define CASADI_THROW_ERROR(FNAME, WHAT) \
46 throw CasadiException("Error in MX::" FNAME " at " + CASADI_WHERE + ":\n"\
47  + std::string(WHAT));
48 
49 // Throw informative error message
50 #define CASADI_THROW_ERROR_OBJ(FNAME, WHAT) \
51 throw CasadiException("Error in MX::" FNAME " for node of type " \
52  + this->class_name() + " at " + CASADI_WHERE + ":\n" + std::string(WHAT));
53 
54 namespace casadi {
55 
56  template class GenericMatrix< MX >;
57 
58  MX::~MX() {
59  }
60 
61  MX::MX() {
63  }
64 
65  MX::MX(MXNode* node, bool dummy1, bool dummy2, bool dummy3, bool dummy4) {
66  own(node);
67  }
68 
69  MX MX::create(MXNode* node) {
70  return MX(node, false, false, false, false);
71  }
72 
73  MX::MX(double x) {
75  }
76 
77  MX::MX(const DM& x) {
79  }
80 
81  MX::MX(const std::vector<double>& x) {
83  }
84 
85  MX::MX(const Sparsity& sp, const MX& val) {
86  if (sp.is_reshape(val.sparsity())) {
87  *this = reshape(val, sp);
88  } else if (val.is_scalar()) {
89  // Dense matrix if val dense
90  if (val.is_dense()) {
91  if (val.is_constant()) {
92  own(ConstantMX::create(sp, static_cast<double>(val)));
93  } else {
94  *this = val->get_nzref(sp, std::vector<casadi_int>(sp.nnz(), 0));
95  }
96  } else {
97  // Empty matrix
99  }
100  } else {
101  casadi_assert_dev(val.is_column() && sp.nnz()==val.size1());
102  *this = densify(val)->get_nzref(sp, range(sp.nnz()));
103  }
104  }
105 
106  MX::MX(const Sparsity& sp) {
107  own(ConstantMX::create(sp, 1));
108  }
109 
110  MX::MX(casadi_int nrow, casadi_int ncol) {
111  own(ConstantMX::create(Sparsity(nrow, ncol), 0));
112  }
113 
114  MX::MX(const std::pair<casadi_int, casadi_int>& rc) {
116  }
117 
118  MX::MX(const Sparsity& sp, double val, bool dummy) {
119  own(ConstantMX::create(sp, val));
120  }
121 
122  MX::MX(const Sparsity& sp, const std::string& fname) {
123  own(ConstantMX::create(sp, fname));
124  }
125 
126  MX::MX(const DM& val, const std::string& name) {
127  own(ConstantMX::create(val, name));
128  }
129 
130  std::vector<MX> MX::createMultipleOutput(MXNode* node) {
131  casadi_assert_dev(dynamic_cast<MultipleOutput*>(node) != nullptr);
132  MX x = MX::create(node);
133  std::vector<MX> ret(x->nout());
134  for (casadi_int i=0; i<ret.size(); ++i) {
135  ret[i] = x.get_output(i);
136  if (ret[i].is_empty(true)) {
137  ret[i] = MX(0, 0);
138  } else if (ret[i].nnz()==0) {
139  ret[i] = MX(ret[i].size());
140  }
141  }
142  return ret;
143  }
144 
145  bool MX::__nonzero__() const {
146  return (*this)->__nonzero__();
147  }
148 
149  MX MX::nzref(const Sparsity& sp, const std::vector<casadi_int>& nz) const {
150  return (*this)->get_nzref(sp, nz);
151  }
152 
153  void MX::get(MX& m, bool ind1, const Slice& rr, const Slice& cc) const {
154  // Fall back on (IM, IM)
155  get(m, ind1, rr.all(size1(), ind1), cc.all(size2(), ind1));
156  }
157 
158  void MX::get(MX& m, bool ind1, const Slice& rr, const Matrix<casadi_int>& cc) const {
159  // Fall back on (IM, IM)
160  get(m, ind1, rr.all(size1(), ind1), cc);
161  }
162 
163  void MX::get(MX& m, bool ind1, const Matrix<casadi_int>& rr, const Slice& cc) const {
164  // Fall back on (IM, IM)
165  get(m, ind1, rr, cc.all(size2(), ind1));
166  }
167 
168  void MX::get(MX& m, bool ind1, const Matrix<casadi_int>& rr, const Matrix<casadi_int>& cc) const {
169  // Make sure dense vectors
170  casadi_assert(rr.is_dense() && rr.is_vector(),
171  "Marix::get: First index must be a dense vector");
172  casadi_assert(cc.is_dense() && cc.is_vector(),
173  "Marix::get: Second index must be a dense vector");
174 
175  // Get the sparsity pattern - does bounds checking
176  std::vector<casadi_int> mapping;
177  Sparsity sp = sparsity().sub(rr.nonzeros(), cc.nonzeros(), mapping, ind1);
178 
179  // Create return MX
180  m = (*this)->get_nzref(sp, mapping);
181  }
182 
183  void MX::get(MX& m, bool ind1, const Slice& rr) const {
184  // Fall back on IM
185  get(m, ind1, rr.all(numel(), ind1));
186  }
187 
188  void MX::get(MX& m, bool ind1, const Matrix<casadi_int>& rr) const {
189  // If the indexed matrix is dense, use nonzero indexing
190  if (is_dense()) {
191  get_nz(m, ind1, rr);
192  return;
193  }
194 
195  // If indexed matrix was a row/column vector, make sure that the result is too
196  bool tr = (is_column() && rr.is_row()) || (is_row() && rr.is_column());
197 
198  // Get the sparsity pattern - does bounds checking
199  std::vector<casadi_int> mapping;
200  Sparsity sp = sparsity().sub(rr.nonzeros(), tr ? rr.sparsity().T() : rr.sparsity(),
201  mapping, ind1);
202 
203  // Create return MX
204  m = (*this)->get_nzref(sp, mapping);
205  }
206 
207  void MX::get(MX& m, bool ind1, const Sparsity& sp) const {
208  casadi_assert(size()==sp.size(),
209  "get(Sparsity sp): shape mismatch. This matrix has shape "
210  + str(size()) + ", but supplied sparsity index has shape "
211  + str(sp.size()) + ".");
212  m = project(*this, sp);
213  }
214 
215  void MX::get(MX& m, bool ind1, const MX& rr) const {
216  casadi_assert(is_dense(), "Parametric slicing only supported for dense matrices."
217  "Got " + dim(true) + " instead.");
218  get_nz(m, ind1, rr);
219  }
220 
221  void MX::get(MX& m, bool ind1, const Slice& rr, const MX& cc) const {
222  casadi_assert(is_dense(), "Parametric slicing only supported for dense matrices. ");
223  m = (*this)->get_nz_ref(rr.apply(size1()), floor(ind1 ? cc-1 : cc)*size1());
224  }
225 
226  void MX::get(MX& m, bool ind1, const MX& rr, const Slice& cc) const {
227  casadi_assert(is_dense(), "Parametric slicing only supported for dense matrices.");
228  m = (*this)->get_nz_ref(ind1 ? rr-1 : rr, cc.apply(size2())*size1());
229  }
230 
231  void MX::get(MX& m, bool ind1, const MX& rr, const MX& cc) const {
232  casadi_assert(is_dense(), "Parametric slicing only supported for dense matrices.");
233  m = (*this)->get_nz_ref(ind1 ? rr-1 : rr, floor(ind1 ? cc-1 : cc)*size1());
234  }
235 
236  void MX::set(const MX& m, bool ind1, const Slice& rr, const Slice& cc) {
237  // Fall back on (IM, IM)
238  set(m, ind1, rr.all(size1(), ind1), cc.all(size2(), ind1));
239  }
240 
241  void MX::set(const MX& m, bool ind1, const Slice& rr, const Matrix<casadi_int>& cc) {
242  // Fall back on (IM, IM)
243  set(m, ind1, rr.all(size1(), ind1), cc);
244  }
245 
246  void MX::set(const MX& m, bool ind1, const Matrix<casadi_int>& rr, const Slice& cc) {
247  // Fall back on (IM, IM)
248  set(m, ind1, rr, cc.all(size2(), ind1));
249  }
250 
251  void MX::set(const MX& m, bool ind1, const Matrix<casadi_int>& rr, const Matrix<casadi_int>& cc) {
252  // Row vector rr (e.g. in MATLAB) is transposed to column vector
253  if (rr.size1()==1 && rr.size2()>1) {
254  set(m, ind1, rr.T(), cc);
255  return;
256  }
257 
258  // Row vector cc (e.g. in MATLAB) is transposed to column vector
259  if (cc.size1()==1 && cc.size2()>1) {
260  set(m, ind1, rr, cc.T());
261  return;
262  }
263 
264  // Make sure rr and cc are dense vectors
265  casadi_assert(rr.is_dense() && rr.is_column(),
266  "MX::set: First index not dense vector");
267  casadi_assert(cc.is_dense() && cc.is_column(),
268  "MX::set: Second index not dense vector");
269 
270  // Assert dimensions of assigning matrix
271  if (rr.size1() != m.size1() || cc.size1() != m.size2()) {
272  if (m.is_scalar()) {
273  // m scalar means "set all"
274  set(repmat(m, rr.size1(), cc.size1()), ind1, rr, cc);
275  return;
276  } else if (rr.size1() == m.size2() && cc.size1() == m.size1()
277  && std::min(m.size1(), m.size2()) == 1) {
278  // m is transposed if necessary
279  set(m.T(), ind1, rr, cc);
280  return;
281  } else {
282  // Error otherwise
283  casadi_error("Dimension mismatch. lhs is " + str(rr.size1()) + "-by-"
284  + str(cc.size1()) + ", while rhs is " + str(m.size()));
285  }
286  }
287 
288  // Dimensions
289  casadi_int sz1 = size1(), sz2 = size2();
290 
291  // Report out-of-bounds
292  casadi_assert_in_range(rr.nonzeros(), -sz1+ind1, sz1+ind1);
293  casadi_assert_in_range(cc.nonzeros(), -sz2+ind1, sz2+ind1);
294 
295  // If we are assigning with something sparse, first remove existing entries
296  if (!m.is_dense()) {
297  erase(rr.nonzeros(), cc.nonzeros(), ind1);
298  }
299 
300  // Collect all assignments
301  IM el = IM::zeros(m.sparsity());
302  for (casadi_int j=0; j<el.size2(); ++j) { // Loop over columns of m
303  casadi_int this_j = cc->at(j) - ind1; // Corresponding column in this
304  if (this_j<0) this_j += sz2;
305  for (casadi_int k=el.colind(j); k<el.colind(j+1); ++k) { // Loop over rows of m
306  casadi_int i = m.row(k);
307  casadi_int this_i = rr->at(i) - ind1; // Corresponding row in this
308  if (this_i<0) this_i += sz1;
309  el->at(k) = this_i + this_j*sz1;
310  }
311  }
312  set(m, false, el);
313  }
314 
315  void MX::set(const MX& m, bool ind1, const Slice& rr) {
316  // Fall back on IM
317  set(m, ind1, rr.all(size1(), ind1));
318  }
319 
320  void MX::set(const MX& m, bool ind1, const Matrix<casadi_int>& rr) {
321  // Assert dimensions of assigning matrix
322  if (rr.sparsity() != m.sparsity()) {
323  if (rr.size() == m.size()) {
324  // Remove submatrix to be replaced
325  erase(rr.nonzeros(), ind1);
326 
327  // Find the intersection between rr's and m's sparsity patterns
328  Sparsity sp = rr.sparsity() * m.sparsity();
329 
330  // Project both matrices to this sparsity
331  set(project(m, sp), ind1, Matrix<casadi_int>::project(rr, sp));
332  return;
333  } else if (m.is_scalar()) {
334  // m scalar means "set all"
335  if (m.is_dense()) {
336  set(MX(rr.sparsity(), m), ind1, rr);
337  } else {
338  set(MX(rr.size()), ind1, rr);
339  }
340  return;
341  } else if (rr.size1() == m.size2() && rr.size2() == m.size1()
342  && std::min(m.size1(), m.size2()) == 1) {
343  // m is transposed if necessary
344  set(m.T(), ind1, rr);
345  return;
346  } else {
347  // Error otherwise
348  casadi_error("Dimension mismatch. lhs is " + str(rr.size())
349  + ", while rhs is " + str(m.size()));
350  }
351  }
352 
353  // Dimensions of this
354  casadi_int sz1 = size1(), sz2 = size2(), sz = nnz(), nel = numel(), rrsz = rr.nnz();
355 
356  // Quick return if nothing to set
357  if (rrsz==0) return;
358 
359  // Check bounds
360  casadi_assert_in_range(rr.nonzeros(), -nel+ind1, nel+ind1);
361 
362  // Dense mode
363  if (is_dense() && m.is_dense()) {
364  set_nz(m, ind1, rr);
365  return;
366  }
367 
368  // Construct new sparsity pattern
369  std::vector<casadi_int> new_row=sparsity().get_row(), new_col=sparsity().get_col();
370  std::vector<casadi_int> nz(rr.nonzeros());
371  new_row.reserve(sz+rrsz);
372  new_col.reserve(sz+rrsz);
373  nz.reserve(rrsz);
374  for (std::vector<casadi_int>::iterator i=nz.begin(); i!=nz.end(); ++i) {
375  if (ind1) (*i)--;
376  if (*i<0) *i += nel;
377  new_row.push_back(*i % sz1);
378  new_col.push_back(*i / sz1);
379  }
380  Sparsity sp = Sparsity::triplet(sz1, sz2, new_row, new_col);
381 
382  // If needed, update pattern
383  if (sp != sparsity()) *this = project(*this, sp);
384 
385  // Find the nonzeros corresponding to rr
386  sparsity().get_nz(nz);
387 
388  // Create a nonzero assignment node
389  *this = m->get_nzassign(*this, nz);
390  }
391 
392  void MX::set(const MX& m, bool ind1, const Sparsity& sp) {
393  casadi_assert(size()==sp.size(),
394  "set(Sparsity sp): shape mismatch. This matrix has shape "
395  + str(size()) + ", but supplied sparsity index has shape "
396  + str(sp.size()) + ".");
397  std::vector<casadi_int> ii = sp.find();
398  if (m.is_scalar()) {
399  (*this)(ii) = densify(m);
400  } else {
401  (*this)(ii) = densify(m(ii));
402  }
403  }
404 
405  void MX::get_nz(MX& m, bool ind1, const Slice& kk) const {
406  // Fallback on IM
407  get_nz(m, ind1, kk.all(nnz(), ind1));
408  }
409 
410  void MX::get_nz(MX& m, bool ind1, const Matrix<casadi_int>& kk) const {
411  // If indexed matrix was a row/column vector, make sure that the result is too
412  bool tr = (is_column() && kk.is_row()) || (is_row() && kk.is_column());
413 
414  // Quick return if no entries
415  if (kk.nnz()==0) {
416  m = MX::zeros(tr ? kk.sparsity().T() : kk.sparsity());
417  return;
418  }
419 
420  // Check bounds
421  casadi_int sz = nnz();
422  casadi_assert_in_range(kk.nonzeros(), -sz+ind1, sz+ind1);
423 
424  // Handle index-1, negative indices
425  if (ind1 || *std::min_element(kk->begin(), kk->end())<0) {
426  Matrix<casadi_int> kk_mod = kk;
427  for (auto&& i : kk_mod.nonzeros()) {
428  casadi_assert(!(ind1 && i<=0),
429  "Matlab is 1-based, but requested index " + str(i) + ". "
430  "Note that negative slices are disabled in the Matlab interface. "
431  "Possibly you may want to use 'end'.");
432  if (ind1) i--;
433  if (i<0) i += sz;
434  }
435  get_nz(m, false, kk_mod); // Call recursively
436  return;
437  }
438 
439  // Return reference to the nonzeros
440  m = (*this)->get_nzref(tr ? kk.sparsity().T() : kk.sparsity(), kk.nonzeros());
441  }
442 
443  void MX::get_nz(MX& m, bool ind1, const MX& kk) const {
444  // Create return MX
445  m = (*this)->get_nz_ref(ind1 ? kk-1.0 : kk);
446  }
447 
448  void MX::get_nz(MX& m, bool ind1, const MX& inner, const MX& outer) const {
449  // Create return MX
450  m = (*this)->get_nz_ref(ind1 ? inner-1.0: inner, ind1 ? outer-1.0: outer);
451  }
452 
453  void MX::get_nz(MX& m, bool ind1, const Slice& inner, const MX& outer) const {
454  // Create return MX
455  m = (*this)->get_nz_ref(ind1 ? inner-1: inner, ind1 ? outer-1.0: outer);
456  }
457 
458  void MX::get_nz(MX& m, bool ind1, const MX& inner, const Slice& outer) const {
459  // Create return MX
460  m = (*this)->get_nz_ref(ind1 ? inner-1.0: inner, ind1 ? outer-1: outer);
461  }
462 
463  void MX::set_nz(const MX& m, bool ind1, const Slice& kk) {
464  // Fallback on IM
465  set_nz(m, ind1, kk.all(nnz(), ind1));
466  }
467 
468  void MX::set_nz(const MX& m, bool ind1, const Matrix<casadi_int>& kk) {
469  casadi_assert(kk.nnz()==m.nnz() || m.nnz()==1,
470  "MX::set_nz: length of non-zero indices (" + str(kk.nnz()) + ") " +
471  "must match size of rhs (" + str(m.nnz()) + ").");
472 
473  // Assert dimensions of assigning matrix
474  if (kk.sparsity() != m.sparsity()) {
475  if (m.is_scalar()) {
476  // m scalar means "set all"
477  if (!m.is_dense()) return; // Nothing to set
478  set_nz(MX(kk.sparsity(), m), ind1, kk);
479  return;
480  } else if (kk.size() == m.size()) {
481  // Project sparsity if needed
482  set_nz(project(m, kk.sparsity()), ind1, kk);
483  return;
484  } else if (kk.size1() == m.size2() && kk.size2() == m.size1()
485  && std::min(m.size1(), m.size2()) == 1) {
486  // m is transposed if necessary
487  set_nz(m.T(), ind1, kk);
488  return;
489  } else {
490  // Error otherwise
491  casadi_error("Dimension mismatch. lhs is " + str(kk.size())
492  + ", while rhs is " + str(m.size()));
493  }
494  }
495 
496  // Call recursively if points both objects point to the same node
497  if (this==&m) {
498  MX m_copy = m;
499  set_nz(m_copy, ind1, kk);
500  return;
501  }
502 
503  // Check bounds
504  casadi_int sz = nnz();
505  casadi_assert_in_range(kk.nonzeros(), -sz+ind1, sz+ind1);
506 
507  // Quick return if no assignments to be made
508  if (kk.nnz()==0) return;
509 
510  // Handle index-1, negative indices
511  if (ind1 || *std::min_element(kk->begin(), kk->end())<0) {
512  Matrix<casadi_int> kk_mod = kk;
513  for (auto&& i : kk_mod.nonzeros()) {
514  casadi_assert(!(ind1 && i<=0),
515  "Matlab is 1-based, but requested index " + str(i) + ". "
516  "Note that negative slices are disabled in the Matlab interface. "
517  "Possibly you may want to use 'end'.");
518  if (ind1) i--;
519  if (i<0) i += sz;
520  }
521  set_nz(m, false, kk_mod); // Call recursively
522  return;
523  }
524 
525  // Create a nonzero assignment node
526  *this = m->get_nzassign(*this, kk.nonzeros());
527  }
528 
529  void MX::set_nz(const MX& m, bool ind1, const MX& kk) {
530  *this = m->get_nzassign(*this, ind1 ? kk-1 : kk);
531  }
532 
533  MX MX::binary(casadi_int op, const MX &x, const MX &y, bool unique_x, bool unique_y) {
534  // Check, correct dimensions
535  if (x.size()!=y.size() && !x.is_scalar() && !y.is_scalar()) {
536  // x and y are horizontal multiples of each other?
537  if (!x.is_empty() && !y.is_empty()) {
538  if (x.size1() == y.size1() && x.size2() % y.size2() == 0) {
539  return binary(op, x, repmat(y, 1, x.size2() / y.size2()), unique_x, false);
540  } else if (y.size1() == x.size1() && y.size2() % x.size2() == 0) {
541  return binary(op, repmat(x, 1, y.size2() / x.size2()), y, false, unique_y);
542  }
543  }
544  // x and y are empty horizontal multiples of each other?
545  if (x.size1()==0 && y.size1()==0 && x.size2()>0 && y.size2()>0) {
546  if (x.size2() % y.size2() == 0) {
547  return MX(0, x.size2());
548  } else if (y.size2() % x.size2() == 0) {
549  return MX(0, y.size2());
550  }
551  }
552  // Dimension mismatch
553  casadi_error("Dimension mismatch for " + casadi_math<double>::print(op, "x", "y") +
554  ", x is " + x.dim() + ", while y is " + y.dim());
555  }
556  // Call internal class
557  return x->get_binary(op, y, unique_x, unique_y);
558  }
559 
560  MX MX::unary(casadi_int op, const MX &x, bool unique) {
561  return x->get_unary(Operation(op), unique);
562  }
563 
564  MXNode* MX::get() const {
565  return static_cast<MXNode*>(SharedObject::get());
566  }
567 
569  return static_cast<MXNode*>(SharedObject::operator->());
570  }
571 
572  const MXNode* MX::operator->() const {
573  return static_cast<const MXNode*>(SharedObject::operator->());
574  }
575 
576  MX MX::inf(casadi_int nrow, casadi_int ncol) {
577  return inf(Sparsity::dense(nrow, ncol));
578  }
579 
580  MX MX::inf(const std::pair<casadi_int, casadi_int> &rc) {
581  return inf(rc.first, rc.second);
582  }
583 
584  MX MX::inf(const Sparsity& sp) {
585  return create(ConstantMX::create(sp, std::numeric_limits<double>::infinity()));
586  }
587 
588  MX MX::nan(casadi_int nrow, casadi_int ncol) {
589  return nan(Sparsity::dense(nrow, ncol));
590  }
591 
592  MX MX::nan(const std::pair<casadi_int, casadi_int>& rc) {
593  return nan(rc.first, rc.second);
594  }
595 
596  MX MX::nan(const Sparsity& sp) {
597  return create(ConstantMX::create(sp, std::numeric_limits<double>::quiet_NaN()));
598  }
599 
600  MX MX::eye(casadi_int n) {
601  return MX(DM::eye(n));
602  }
603 
604  MX MX::operator-() const {
605  if ((*this)->op()==OP_NEG) {
606  return (*this)->dep(0);
607  } else {
608  return (*this)->get_unary(OP_NEG);
609  }
610  }
611 
612  const Sparsity& MX::sparsity() const {
613  return (*this)->sparsity();
614  }
615 
616  void MX::erase(const std::vector<casadi_int>& rr, const std::vector<casadi_int>& cc, bool ind1) {
617  // Get sparsity of the new matrix
618  Sparsity sp = sparsity();
619 
620  // Erase from sparsity pattern
621  std::vector<casadi_int> mapping = sp.erase(rr, cc, ind1);
622 
623  // Create new matrix
624  if (mapping.size()!=nnz()) {
625  MX ret = (*this)->get_nzref(sp, mapping);
626  *this = ret;
627  }
628  }
629 
630  std::vector<MX> MX::get_nonzeros() const {
631  std::vector<MX> ret;
632  std::vector<MX> p = primitives();
633  for (const MX& e : p) {
634  if (e.is_scalar()) {
635  ret.push_back(e);
636  } else {
637  // Get nonzeros sparsity cast
638  MX nz;
639  e.get_nz(nz, false, Slice());
640  for (casadi_int i=0; i<nz.nnz(); ++i) {
641  ret.push_back(nz(i));
642  }
643  }
644  }
645  return ret;
646  }
647 
648  void MX::erase(const std::vector<casadi_int>& rr, bool ind1) {
649  // Get sparsity of the new matrix
650  Sparsity sp = sparsity();
651 
652  // Erase from sparsity pattern
653  std::vector<casadi_int> mapping = sp.erase(rr, ind1);
654 
655  // Create new matrix
656  if (mapping.size()!=nnz()) {
657  MX ret = (*this)->get_nzref(sp, mapping);
658  *this = ret;
659  }
660  }
661 
662  void MX::enlarge(casadi_int nrow, casadi_int ncol,
663  const std::vector<casadi_int>& rr,
664  const std::vector<casadi_int>& cc, bool ind1) {
665  Sparsity sp = sparsity();
666  sp.enlarge(nrow, ncol, rr, cc, ind1);
667 
668  MX ret = (*this)->get_nzref(sp, range(nnz())); // FIXME?
669  *this = ret;
670  }
671 
672  MX MX::mtimes(const MX& x, const MX& y, const std::string& blas) {
673  if (x.is_scalar() || y.is_scalar()) {
674  // Use element-wise multiplication if at least one factor scalar
675  return x*y;
676  } else {
678  return mac(x, y, z, blas);
679  }
680  }
681 
682  MX MX::einstein(const MX& A, const MX& B, const MX& C,
683  const std::vector<casadi_int>& dim_a, const std::vector<casadi_int>& dim_b,
684  const std::vector<casadi_int>& dim_c,
685  const std::vector<casadi_int>& a, const std::vector<casadi_int>& b,
686  const std::vector<casadi_int>& c) {
687  return C->get_einstein(A, B, dim_c, dim_a, dim_b, c, a, b);
688  }
689 
690  MX MX::einstein(const MX& A, const MX& B,
691  const std::vector<casadi_int>& dim_a, const std::vector<casadi_int>& dim_b,
692  const std::vector<casadi_int>& dim_c,
693  const std::vector<casadi_int>& a, const std::vector<casadi_int>& b,
694  const std::vector<casadi_int>& c) {
695  return MX::zeros(product(dim_c), 1)->get_einstein(A, B, dim_c, dim_a, dim_b, c, a, b);
696  }
697 
698  MX MX::cumsum(const MX &x, casadi_int axis) {
699  if (axis==-1) axis = x.is_row();
700  MX r = axis==0 ? x.T() : x;
701  Sparsity sl = r(Slice(), 0).sparsity();
702  MX acc = MX::sym("acc", sl);
703  MX u = MX::sym("u", sl);
704 
705  Function f("f", {acc, u}, {acc+u});
706  f = f.mapaccum(r.size2());
707  MX ret = f(std::vector<MX>{0, r})[0];
708 
709  return axis==0 ? ret.T() : ret;
710  }
711 
712  MX MX::mac(const MX& x, const MX& y, const MX& z, const std::string& blas) {
713  if (x.is_scalar() || y.is_scalar()) {
714  // Use element-wise multiplication if at least one factor scalar
715  return z + x*y;
716  }
717 
718  // Check matching dimensions
719  casadi_assert(x.size2()==y.size1(),
720  "Matrix product with incompatible dimensions. Lhs is "
721  + x.dim() + " and rhs is " + y.dim() + ".");
722 
723  // Check if we can simplify the product
724  if (x.is_eye()) {
725  return y + z;
726  } else if (y.is_eye()) {
727  return x + z;
728  } else if (x.is_zero() || y.is_zero()) {
729  return z;
730  } else {
731  return x->get_mac(y, z, blas);
732  }
733  }
734 
735  MX MX::dot(const MX& x, const MX& y) {
736  return x->get_dot(y);
737  }
738 
739  MX MX::printme(const MX& b) const {
740  return binary(OP_PRINTME, *this, b);
741  }
742 
743  MX MX::attachAssert(const MX& y, const std::string &fail_message) const {
744  casadi_assert(y.is_scalar(),
745  "Error in attachAssert: assertion expression y must be scalar, "
746  "but got " + y.dim());
747  return(*this)->get_assert(y, fail_message);
748  }
749 
750  MX MX::monitor(const std::string& comment) const {
751  return(*this)->get_monitor(comment);
752  }
753 
754  MX MX::dump(const std::string& base_filename, const Dict& opts) const {
755  return(*this)->get_dump(base_filename, opts);
756  }
757 
759  casadi_assert(op()==OP_DUMP, "reset_dump_count: not a dump node");
760  static_cast<Dump*>(get())->reset_dump_count();
761  }
762 
763  MX MX::lift(const MX& x, const MX& x_guess) {
764  casadi_assert_dev(x.sparsity()==x_guess.sparsity());
765  return x->_get_binary(OP_LIFT, x_guess, false, false);
766  }
767 
768  DM MX::evalf(const MX& m) {
769  Function f("f", std::vector<MX>{}, {m}, {{"allow_free", true}});
770  return f(std::vector<DM>{})[0];
771  }
772 
773  MX MX::mrdivide(const MX& b, const MX& a) {
774  if (a.is_scalar() || b.is_scalar()) return b/a;
775  return solve(a.T(), b.T()).T();
776  }
777 
778  MX MX::mldivide(const MX& a, const MX& b) {
779  if (a.is_scalar() || b.is_scalar()) return b/a;
780  return solve(a, b);
781  }
782 
783  MX MX::dep(casadi_int ch) const {
784  return (*this)->dep(ch);
785  }
786 
787  casadi_int MX::n_dep() const {
788  return (*this)->n_dep();
789  }
790 
791  std::string MX::name() const {
792  return (*this)->name();
793  }
794 
795  bool MX::is_symbolic() const {
796  return (*this)->op()==OP_PARAMETER;
797  }
798 
799  bool MX::is_constant() const {
800  return (*this)->op()==OP_CONST;
801  }
802 
803  bool MX::is_call() const {
804  return (*this)->op()==OP_CALL;
805  }
806 
808  return (*this)->which_function();
809  }
810 
811  bool MX::is_output() const {
812  return (*this)->is_output();
813  }
814 
815  bool MX::has_output() const {
816  return (*this)->has_output();
817  }
818 
819  casadi_int MX::which_output() const {
820  return (*this)->which_output();
821  }
822 
823  bool MX::is_op(casadi_int op) const {
824  return (*this)->op()==op;
825  }
826 
827  bool MX::is_multiplication() const {
828  return (*this)->op()==OP_MTIMES;
829  }
830 
831  bool MX::is_norm() const {
832  return dynamic_cast<const Norm*>(get())!=nullptr;
833  }
834 
835  MX::operator double() const {
836  return (*this)->to_double();
837  }
838 
839  MX::operator DM() const {
840  return (*this)->get_DM();
841  }
842 
843  bool MX::is_binary() const {
844  return (*this)->is_binary();
845  }
846 
847  bool MX::is_unary() const {
848  return (*this)->is_unary();
849  }
850 
851  casadi_int MX::op() const {
852  return (*this)->op();
853  }
854 
855  Dict MX::info() const {
856  return (*this)->info();
857  }
858 
860  (*this)->serialize(s);
861  }
862 
864  return MX::create(MXNode::deserialize(s));
865  }
866 
867  bool MX::is_equal(const MX& x, const MX& y, casadi_int depth) {
868  return MXNode::is_equal(x.get(), y.get(), depth);
869  }
870 
871  MX MX::mmin(const MX &x) {
872  return x->get_mmin();
873  }
874 
875  MX MX::mmax(const MX &x) {
876  return x->get_mmax();
877  }
878 
879  bool MX::is_commutative() const {
880  if (is_unary()) return true;
881  casadi_assert(is_binary() || is_unary(),
882  "MX::is_commutative: must be binary or unary operation");
883  return operation_checker<CommChecker>(op());
884  }
885 
887  return (*this)->mapping();
888  }
889 
890  casadi_int MX::get_temp() const {
891  return (*this)->temp;
892  }
893 
894  void MX::set_temp(casadi_int t) const {
895  (*this)->temp = t;
896  }
897 
898  casadi_int MX::n_out() const {
899  return (*this)->nout();
900  }
901 
902  MX MX::get_output(casadi_int oind) const {
903  return (*this)->get_output(oind);
904  }
905 
906  MX MX::project(const MX& x, const Sparsity& sp, bool intersect) {
907  try {
908  if (x.is_empty() || (sp==x.sparsity())) {
909  return x;
910  } else {
911  casadi_assert(sp.size()==x.size(), "Cannot project " + x.dim() + " to " + sp.dim());
912  if (intersect) {
913  return x->get_project(sp.intersect(x.sparsity()));
914  } else {
915  return x->get_project(sp);
916  }
917  }
918  } catch (std::exception& e) {
919  CASADI_THROW_ERROR("project", e.what());
920  }
921  }
922 
923  MX MX::densify(const MX& x, const MX& val) {
924  casadi_assert_dev(val.is_scalar());
925  if (x.is_dense()) {
926  return x; // Already ok
927  } else if (val->is_zero()) {
928  return project(x, Sparsity::dense(x.size()));
929  } else {
930  MX ret = MX::repmat(val, x.size());
931  ret(x.sparsity()) = x;
932  return ret;
933  }
934  }
935 
936  casadi_int MX::eq_depth_ = 1;
937 
938  void MX::set_max_depth(casadi_int eq_depth) {
939  eq_depth_ = eq_depth;
940  }
941 
942  casadi_int MX::get_max_depth() {
943  return eq_depth_;
944  }
945 
946  MX MX::_sym(const std::string& name, const Sparsity& sp) {
947  if (sp.nnz()==0) {
948  return MX::zeros(sp);
949  } else {
950  return MX::create(new SymbolicMX(name, sp));
951  }
952  }
953 
954  bool MX::is_valid_input() const {
955  return (*this)->is_valid_input();
956  }
957 
958  casadi_int MX::n_primitives() const {
959  return (*this)->n_primitives();
960  }
961 
962  std::vector<MX> MX::primitives() const {
963  std::vector<MX> ret(n_primitives());
964  std::vector<MX>::iterator it=ret.begin();
965  (*this)->primitives(it);
966  casadi_assert_dev(it==ret.end());
967  return ret;
968  }
969 
970  std::vector<MX> MX::split_primitives(const MX& x) const {
971  std::vector<MX> ret(n_primitives());
972  std::vector<MX>::iterator it=ret.begin();
973  (*this)->split_primitives(x, it);
974  casadi_assert_dev(it==ret.end());
975  return ret;
976  }
977 
978  std::vector<SX> MX::split_primitives(const SX& x) const {
979  std::vector<SX> ret(n_primitives());
980  std::vector<SX>::iterator it=ret.begin();
981  (*this)->split_primitives(x, it);
982  casadi_assert_dev(it==ret.end());
983  return ret;
984  }
985 
986  std::vector<DM> MX::split_primitives(const DM& x) const {
987  std::vector<DM> ret(n_primitives());
988  std::vector<DM>::iterator it=ret.begin();
989  (*this)->split_primitives(x, it);
990  casadi_assert_dev(it==ret.end());
991  return ret;
992  }
993 
994  MX MX::join_primitives(const std::vector<MX>& v) const {
995  casadi_assert(v.size()==n_primitives(), "Wrong number of primitives supplied");
996  std::vector<MX>::const_iterator it=v.begin();
997  MX ret = (*this)->join_primitives(it);
998  casadi_assert_dev(it==v.end());
999  return ret;
1000  }
1001 
1002  SX MX::join_primitives(const std::vector<SX>& v) const {
1003  casadi_assert(v.size()==n_primitives(), "Wrong number of primitives supplied");
1004  std::vector<SX>::const_iterator it=v.begin();
1005  SX ret = (*this)->join_primitives(it);
1006  casadi_assert_dev(it==v.end());
1007  return ret;
1008  }
1009 
1010  DM MX::join_primitives(const std::vector<DM>& v) const {
1011  casadi_assert(v.size()==n_primitives(), "Wrong number of primitives supplied");
1012  std::vector<DM>::const_iterator it=v.begin();
1013  DM ret = (*this)->join_primitives(it);
1014  casadi_assert_dev(it==v.end());
1015  return ret;
1016  }
1017 
1018  bool MX::has_duplicates() const {
1019  return (*this)->has_duplicates();
1020  }
1021 
1022  void MX::reset_input() const {
1023  (*this)->reset_input();
1024  }
1025 
1026  bool MX::is_eye() const {
1027  return (*this)->is_eye();
1028  }
1029 
1030  bool MX::is_zero() const {
1031  if (nnz()==0) {
1032  return true;
1033  } else {
1034  return (*this)->is_zero();
1035  }
1036  }
1037 
1038  bool MX::is_one() const {
1039  return (*this)->is_one();
1040  }
1041 
1042  bool MX::is_minus_one() const {
1043  return (*this)->is_value(-1);
1044  }
1045 
1046  bool MX::is_half() const {
1047  return (*this)->is_half();
1048  }
1049 
1050  bool MX::is_value(double val) const {
1051  return (*this)->is_value(val);
1052  }
1053 
1054  bool MX::is_nonnegative() const {
1055  return (*this)->is_nonnegative();
1056  }
1057 
1058  bool MX::is_transpose() const {
1059  return op()==OP_TRANSPOSE;
1060  }
1061 
1062  bool MX::is_regular() const {
1063  if (is_constant()) {
1064  return static_cast<DM>(*this).is_regular();
1065  } else {
1066  casadi_error("Cannot check regularity for symbolic MX");
1067  }
1068  }
1069 
1070  bool MX::is_inf() const {
1071  return (*this)->is_inf();
1072  }
1073 
1074  bool MX::is_minus_inf() const {
1075  return (*this)->is_minus_inf();
1076  }
1077 
1078  bool MX::is_integer() const {
1079  return (*this)->is_integer();
1080  }
1081 
1082  bool MX::is_doubled() const {
1083  return (op()==OP_ADD && is_equal(dep(0), dep(1), get_max_depth())) ||
1084  (op()==OP_TWICE);
1085  }
1086 
1087  MX MX::inv() const {
1088  if (is_op(OP_INV)) {
1089  return dep(0);
1090  } else {
1091  return (*this)->get_unary(OP_INV);
1092  }
1093  }
1094 
1095  MX MX::T() const {
1096  return (*this)->get_transpose();
1097  }
1098 
1100  return dynamic_cast<const MXNode*>(ptr)!=nullptr;
1101  }
1102 
1103  // Helper function
1104  bool has_empty(const std::vector<MX>& x, bool both=false) {
1105  for (auto&& i : x) {
1106  if (i.is_empty(both)) return true;
1107  }
1108  return false;
1109  }
1110 
1111  std::vector<MX> trim_empty(const std::vector<MX>& x, bool both=false) {
1112  std::vector<MX> ret;
1113  for (auto&& i : x) {
1114  if (!i.is_empty(both)) ret.push_back(i);
1115  }
1116  return ret;
1117  }
1118 
1119  MX MX::horzcat(const std::vector<MX>& x) {
1120  // Check dimensions
1121  if (x.size()>1) {
1122  std::vector<MX> ne = trim_empty(x, true);
1123  for (casadi_int i=0;i<ne.size();i++) {
1124  casadi_assert(ne[i].size1()==ne[0].size1(),
1125  "horzcat dimension mismatch x[" + str(i) + "]:" + ne[i].dim() +
1126  " and x[0]: " + ne[0].dim() + ".");
1127  }
1128  }
1129 
1130  if (x.empty()) {
1131  return MX(1, 0);
1132  } else if (x.size()==1) {
1133  return x.front();
1134  } else if (has_empty(x)) {
1135  std::vector<MX> ret = trim_empty(x);
1136  if (ret.empty()) {
1137  // We still want horzcat(zeros(0,5),zeros(0,5)) -> zeros(0,10)
1138  ret = trim_empty(x, true);
1139  casadi_int s = 0;
1140  casadi_int nrow = 0;
1141  for (casadi_int i=0;i<ret.size();++i) {
1142  s+= ret[i].size2();
1143  casadi_assert_dev(nrow==0 || nrow==ret[i].size1());
1144  nrow = ret[i].size1();
1145  }
1146  return MX::zeros(nrow, s);
1147  } else {
1148  return horzcat(ret);
1149  }
1150  } else {
1151  return x.front()->get_horzcat(x);
1152  }
1153  }
1154 
1155  MX MX::diagcat(const std::vector<MX>& x) {
1156  // Quick return if empty or single element
1157  if (x.empty()) return MX();
1158  if (x.size()==1) return x.front();
1159  // Call recursively if any 0-by-0 matrices
1160  if (has_empty(x, true)) return diagcat(trim_empty(x, true));
1161  // Create diagcat node
1162  return x.front()->get_diagcat(x);
1163  }
1164 
1165  MX MX::vertcat(const std::vector<MX>& x) {
1166  // Check dimensions
1167  if (x.size()>1) {
1168  std::vector<MX> ne = trim_empty(x, true);
1169  for (casadi_int i=0;i<ne.size();i++) {
1170  casadi_assert(ne[i].size2()==ne[0].size2(),
1171  "vertcat dimension mismatch x[" + str(i) + "]:" + ne[i].dim() +
1172  " and x[0]: " + ne[0].dim() + ".");
1173  }
1174  }
1175 
1176  if (x.empty()) {
1177  return MX(0, 1);
1178  } else if (x.size()==1) {
1179  return x.front();
1180  } else if (has_empty(x)) {
1181  std::vector<MX> ret = trim_empty(x);
1182  if (ret.empty()) {
1183  // We still want vertcat(zeros(5,0),zeros(5,0)) -> zeros(10,0)
1184  ret = trim_empty(x, true);
1185  casadi_int s = 0;
1186  casadi_int ncol = 0;
1187  for (casadi_int i=0;i<ret.size();++i) {
1188  s+= ret[i].size1();
1189  casadi_assert_dev(ncol==0 || ret[i].size2()==ncol);
1190  ncol = ret[i].size2();
1191  }
1192  return MX::zeros(s, ncol);
1193  } else {
1194  return vertcat(ret);
1195  }
1196  } else if (!x.front().is_column()) {
1197  // Vertcat operation only supports vectors, rewrite using horzcat
1198  std::vector<MX> xT = x;
1199  for (std::vector<MX>::iterator i=xT.begin(); i!=xT.end(); ++i) *i = i->T();
1200  return horzcat(xT).T();
1201  } else {
1202  return x.front()->get_vertcat(x);
1203  }
1204  }
1205 
1206  std::vector<MX> MX::horzsplit(const MX& x, const std::vector<casadi_int>& offset) {
1207  // Consistency check
1208  casadi_assert_dev(!offset.empty());
1209  casadi_assert_dev(offset.front()==0);
1210  casadi_assert_dev(offset.back()==x.size2());
1211  casadi_assert_dev(is_monotone(offset));
1212 
1213  // Trivial return if possible
1214  if (offset.size()==1) {
1215  return std::vector<MX>(0);
1216  } else if (offset.size()==2) {
1217  return std::vector<MX>(1, x);
1218  } else {
1219  return x->get_horzsplit(offset);
1220  }
1221  }
1222 
1223  std::vector<MX> MX::diagsplit(const MX& x, const std::vector<casadi_int>& offset1,
1224  const std::vector<casadi_int>& offset2) {
1225  // Consistency check
1226  casadi_assert_dev(!offset1.empty());
1227  casadi_assert_dev(offset1.front()==0);
1228  casadi_assert_dev(offset1.back()==x.size1());
1229  casadi_assert_dev(is_monotone(offset1));
1230 
1231  // Consistency check
1232  casadi_assert_dev(!offset2.empty());
1233  casadi_assert_dev(offset2.front()==0);
1234  casadi_assert_dev(offset2.back()==x.size2());
1235  casadi_assert_dev(is_monotone(offset2));
1236 
1237  return x->get_diagsplit(offset1, offset2);
1238  }
1239 
1240  std::vector<MX> MX::vertsplit(const MX& x, const std::vector<casadi_int>& offset) {
1241  if (x.is_column()) {
1242  // Consistency check
1243  casadi_assert_dev(!offset.empty());
1244  casadi_assert_dev(offset.front()==0);
1245  casadi_assert_dev(offset.back()==x.size1());
1246  casadi_assert_dev(is_monotone(offset));
1247 
1248  // Trivial return if possible
1249  if (offset.size()==1) {
1250  return std::vector<MX>();
1251  } else if (offset.size()==2) {
1252  return std::vector<MX>(1, x);
1253  } else {
1254  return x->get_vertsplit(offset);
1255  }
1256  } else {
1257  std::vector<MX> ret = horzsplit(x.T(), offset);
1258  for (auto&& e : ret) e = e.T();
1259  return ret;
1260  }
1261  }
1262 
1263  MX MX::blockcat(const std::vector< std::vector<MX > > &v) {
1264  // Quick return if no block rows
1265  if (v.empty()) return MX(0, 0);
1266 
1267  // Make sure same number of block columns
1268  casadi_int ncols = v.front().size();
1269  for (auto&& e : v) {
1270  casadi_assert(e.size()==ncols, "blockcat: Inconsistent number of block columns");
1271  }
1272 
1273  // Quick return if no block columns
1274  if (v.front().empty()) return MX(0, 0);
1275 
1276  // Horizontally concatenate all columns for each row, then vertically concatenate rows
1277  std::vector<MX> rows;
1278  for (auto&& e : v) {
1279  rows.push_back(horzcat(e));
1280  }
1281  return vertcat(rows);
1282  }
1283 
1284  MX MX::norm_2(const MX& x) {
1285  if (x.is_vector()) {
1286  return norm_fro(x);
1287  } else {
1288  return x->get_norm_2();
1289  }
1290  }
1291 
1292  MX MX::norm_fro(const MX& x) {
1293  return x->get_norm_fro();
1294  }
1295 
1296  MX MX::norm_1(const MX& x) {
1297  return x->get_norm_1();
1298  }
1299 
1300  MX MX::norm_inf(const MX& x) {
1301  return x->get_norm_inf();
1302  }
1303 
1304  bool MX::simplify_combine_terms(std::vector<MX>& arg,
1305  std::vector<MX>& res,
1306  const Dict& opts) {
1307  // No term-combining available for MX; leave the graph untouched
1308  return false;
1309  }
1310 
1311  MX MX::simplify(const MX& x) {
1312  return x;
1313  }
1314 
1315  MX MX::transform(const MX& x, const Dict& opts) {
1316  return transform(std::vector<MX>{x}, opts).at(0);
1317  }
1318 
1319  MX MX::transform(const MX& x,
1320  const std::vector<std::vector<GenericType> >& passes, const Dict& opts) {
1321  return transform(std::vector<MX>{x}, passes, opts).at(0);
1322  }
1323 
1324  std::vector<MX> MX::transform(const std::vector<MX>& x, const Dict& opts) {
1325  // Route through Function::transform; inputs are the free variables across all of x
1326  std::vector<MX> arg = symvar(veccat(x));
1327  Function f("transform", arg, x,
1328  {{"allow_free", true}, {"allow_duplicate_io_names", true}});
1329  f = f.transform(opts);
1330  return f(arg);
1331  }
1332 
1333  std::vector<MX> MX::transform(const std::vector<MX>& x,
1334  const std::vector<std::vector<GenericType> >& passes, const Dict& opts) {
1335  // Route through Function::transform; inputs are the free variables across all of x
1336  std::vector<MX> arg = symvar(veccat(x));
1337  Function f("transform", arg, x,
1338  {{"allow_free", true}, {"allow_duplicate_io_names", true}});
1339  f = f.transform(passes, opts);
1340  return f(arg);
1341  }
1342 
1343  MX MX::reshape(const MX& x, casadi_int nrow, casadi_int ncol) {
1344  // Quick return if trivial
1345  if (nrow==x.size1() && ncol==x.size2()) return x;
1346 
1347  // Reshape the sparsity pattern
1348  return reshape(x, Sparsity::reshape(x.sparsity(), nrow, ncol));
1349  }
1350 
1351  MX MX::reshape(const MX& x, const Sparsity& sp) {
1352  casadi_assert(sp.is_reshape(x.sparsity()), "Reshape mismatch");
1353 
1354  // Quick return if trivial
1355  if (sp==x.sparsity()) return x;
1356 
1357  // Call internal method
1358  return x->get_reshape(sp);
1359  }
1360 
1361  MX MX::sparsity_cast(const MX& x, const Sparsity& sp) {
1362  casadi_assert(x.nnz()==sp.nnz(),
1363  "Mismatching nonzero count: " + str(x.nnz()) + " versus " +
1364  str(sp.nnz()) + ".");
1365 
1366  // Quick return if trivial
1367  if (sp==x.sparsity()) return x;
1368 
1369  // Call internal method
1370  return x->get_sparsity_cast(sp);
1371  }
1372 
1373  MX MX::if_else(const MX &cond, const MX &x_true, const MX &x_false, bool short_circuit) {
1374  if (short_circuit) {
1375  // Get symbolic primitives
1376  std::vector<MX> arg = symvar(veccat(std::vector<MX>{x_true, x_false}));
1377 
1378  // Form functions for cases
1379  Function f_true("f_true", arg, {x_true});
1380  Function f_false("f_false", arg, {x_false});
1381 
1382  // Form Switch
1383  Function sw = Function::if_else("switch", f_true, f_false);
1384 
1385  // Call the Switch
1386  std::vector<MX> sw_arg;
1387  sw_arg.push_back(cond);
1388  sw_arg.insert(sw_arg.end(), arg.begin(), arg.end());
1389  return sw(sw_arg).at(0);
1390  } else {
1391  return if_else_zero(cond, x_true) + if_else_zero(!cond, x_false);
1392  }
1393  }
1394 
1395  MX MX::conditional(const MX& ind, const std::vector<MX>& x,
1396  const MX& x_default, bool short_circuit) {
1397  if (short_circuit) {
1398  // Get symbolic primitives
1399  std::vector<MX> arg = x;
1400  arg.push_back(x_default);
1401  arg = symvar(veccat(arg));
1402 
1403  // Form functions for cases
1404  std::vector<Function> f(x.size());
1405  for (casadi_int k=0; k<x.size(); ++k) {
1406  std::stringstream ss;
1407  ss << "f_case" << k;
1408  f[k] = Function(ss.str(), arg, {x[k]});
1409  }
1410  Function f_default("f_default", arg, {x_default});
1411 
1412  // Form Switch
1413  Function sw = Function::conditional("switch", f, f_default);
1414 
1415  // Call the Switch
1416  std::vector<MX> sw_arg;
1417  sw_arg.push_back(ind);
1418  sw_arg.insert(sw_arg.end(), arg.begin(), arg.end());
1419  return sw(sw_arg).at(0);
1420  } else {
1421  MX ret = x_default;
1422  for (casadi_int k=0; k<x.size(); ++k) {
1423  ret = if_else(ind==static_cast<double>(k), x[k], ret);
1424  }
1425  return ret;
1426  }
1427  }
1428 
1429  MX MX::unite(const MX& A, const MX& B) {
1430  // Join the sparsity patterns
1431  std::vector<unsigned char> mapping;
1432  Sparsity sp = A.sparsity().unite(B.sparsity(), mapping);
1433 
1434  // Split up the mapping
1435  std::vector<casadi_int> nzA, nzB;
1436 
1437  // Copy sparsity
1438  for (casadi_int k=0; k<mapping.size(); ++k) {
1439  if (mapping[k]==1) {
1440  nzA.push_back(k);
1441  } else if (mapping[k]==2) {
1442  nzB.push_back(k);
1443  } else {
1444  throw CasadiException("Pattern intersection not empty");
1445  }
1446  }
1447 
1448  // Create mapping
1449  MX ret = MX::zeros(sp);
1450  ret = A->get_nzassign(ret, nzA);
1451  ret = B->get_nzassign(ret, nzB);
1452  return ret;
1453  }
1454 
1455  MX MX::trace(const MX& x) {
1456  casadi_assert(x.is_square(), "trace: must be square");
1457  MX res(0);
1458  for (casadi_int i=0; i < x.size2(); i ++) {
1459  res += x(i, i);
1460  }
1461  return res;
1462  }
1463 
1464  MX MX::diag(const MX& x) {
1465  // Nonzero mapping
1466  std::vector<casadi_int> mapping;
1467 
1468  // Get the sparsity
1469  Sparsity sp = x.sparsity().get_diag(mapping);
1470 
1471  // Create a reference to the nonzeros
1472  return x->get_nzref(sp, mapping);
1473  }
1474 
1475  casadi_int MX::n_nodes(const MX& x) {
1476  Dict opts{{"max_io", 0}, {"cse", false}, {"allow_free", true}};
1477  Function f("tmp_n_nodes", std::vector<MX>{}, {x}, opts);
1478  return f.n_nodes();
1479  }
1480 
1481  MX MX::sum2(const MX& x) {
1482  return mtimes(x, MX::ones(x.size2(), 1));
1483  }
1484 
1485  MX MX::sum1(const MX& x) {
1486  return mtimes(MX::ones(1, x.size1()), x);
1487  }
1488 
1489  MX MX::polyval(const MX& p, const MX& x) {
1490  casadi_assert(p.is_dense(), "polynomial coefficients vector must be a vector");
1491  casadi_assert(p.is_column() && p.nnz()>0, "polynomial coefficients must be a vector");
1492  MX ret = p.nz(0);
1493  for (casadi_int i=1; i<p.nnz(); ++i) {
1494  ret = ret*x + p.nz(i);
1495  }
1496  return ret;
1497  }
1498 
1499  std::string MX::print_operator(const MX& x, const std::vector<std::string>& args) {
1500  return x->disp(args);
1501  }
1502 
1503  void MX::substitute_inplace(const std::vector<MX>& v, std::vector<MX>& vdef,
1504  std::vector<MX>& ex, bool reverse) {
1505  casadi_assert(v.size()==vdef.size(),
1506  "Mismatch in the number of expression to substitute.");
1507  for (casadi_int k=0; k<v.size(); ++k) {
1508  casadi_assert(v[k].is_symbolic(),
1509  "Variable " + str(k) + " is not symbolic");
1510  casadi_assert(v[k].size() == vdef[k].size(),
1511  "Inconsistent shape for variable " + str(k) + ".");
1512  }
1513  casadi_assert(reverse==false, "Not implemented");
1514 
1515  // quick return if nothing to replace
1516  if (v.empty()) return;
1517 
1518  // implemented in MXFunction
1519  std::vector<MX> f_out = vdef;
1520  f_out.insert(f_out.end(), ex.begin(), ex.end());
1521  Function temp("tmp_substitute_inplace", {v}, f_out, Dict{{"max_io", 0}, {"allow_free", true}});
1522  temp.get<MXFunction>()->substitute_inplace(vdef, ex);
1523  }
1524 
1525  MX MX::substitute(const MX& ex, const MX& v, const MX& vdef) {
1526  return substitute(std::vector<MX>{ex}, std::vector<MX>{v}, std::vector<MX>{vdef}).front();
1527  }
1528 
1529  std::vector<MX> MX::substitute(const std::vector<MX> &ex, const std::vector<MX> &v,
1530  const std::vector<MX> &vdef) {
1531  // Assert consistent dimensions
1532  casadi_assert_dev(v.size()==vdef.size());
1533 
1534  // Quick return if all equal
1535  bool all_equal = true;
1536  for (casadi_int k=0; k<v.size(); ++k) {
1537  if (v[k].size()!=vdef[k].size() || !is_equal(v[k], vdef[k])) {
1538  all_equal = false;
1539  break;
1540  }
1541  }
1542  if (all_equal) return ex;
1543 
1544  // Otherwise, evaluate symbolically
1545  Function F("tmp_substitute", v, ex, Dict{{"max_io", 0}, {"allow_free", true}});
1546  std::vector<MX> ret;
1547  F.call(vdef, ret, true);
1548  return ret;
1549  }
1550 
1551  MX MX::graph_substitute(const MX& x, const std::vector<MX> &v,
1552  const std::vector<MX> &vdef) {
1553  return graph_substitute(std::vector<MX>{x}, v, vdef).at(0);
1554  }
1555 
1556  MX MX::graph_substitute(const MX& x, const std::vector<MX> &v,
1557  const std::vector<MX> &vdef, bool& updated) {
1558  return graph_substitute(std::vector<MX>{x}, v, vdef, updated).at(0);
1559  }
1560 
1561  std::vector<MX> MX::graph_substitute(const std::vector<MX>& ex,
1562  const std::vector<MX>& v,
1563  const std::vector<MX>& vdef) {
1564  bool updated;
1565  return graph_substitute(ex, v, vdef, updated);
1566  }
1567  std::vector<MX> MX::graph_substitute(const std::vector<MX>& ex,
1568  const std::vector<MX>& v,
1569  const std::vector<MX>& vdef,
1570  bool& updated) {
1571  casadi_assert(v.size()==vdef.size(),
1572  "Mismatch in the number of expression to substitute: "
1573  + str(v.size()) + " <-> " + str(vdef.size()) + ".");
1574 
1575  updated = false;
1576 
1577  // Quick return if all equal
1578  bool all_equal = true;
1579  for (casadi_int k=0; k<v.size(); ++k) {
1580  if (v[k].size()!=vdef[k].size() || !is_equal(v[k], vdef[k])) {
1581  all_equal = false;
1582  break;
1583  }
1584  }
1585  if (all_equal) return ex;
1586 
1587  // Validate dimensions
1588  for (casadi_int i=0;i<v.size();++i) {
1589  casadi_assert(v[i].size()==vdef[i].size(),
1590  "Inconsistent shapes for i = " + str(i) + ": v[i] " + v[i].dim() +
1591  " <-> vdef[i] " + vdef[i].dim());
1592  }
1593 
1594  // Sort the expression
1595  Dict opts({{"max_io", 0}, {"allow_free", true}});
1596  Function f("tmp_graph_substitute", std::vector<MX>{}, ex, opts);
1597  MXFunction *ff = f.get<MXFunction>();
1598 
1599  // Get references to the internal data structures
1600  const std::vector<MXAlgEl>& algorithm = ff->algorithm_;
1601  std::vector<MX> swork(ff->workloc_.size()-1);
1602 
1603  // A boolean vector indicated whoch nodes are tainted by substitutions
1604  std::vector<bool> tainted(swork.size());
1605 
1606  // Construct lookup table for expressions,
1607  // giving priority to first occurances
1608  std::map<const MXNode*, casadi_int> expr_lookup;
1609  for (casadi_int i=0;i<v.size();++i) {
1610  auto it = expr_lookup.find(v[i].operator->());
1611  if (it==expr_lookup.end()) expr_lookup[v[i].operator->()] = i;
1612  }
1613 
1614  // Construct found map
1615  std::vector<bool> expr_found(v.size(), false);
1616 
1617  // Allocate output vector
1618  std::vector<MX> f_out(f.n_out());
1619  std::vector<MX> oarg, ores;
1620 
1621  // expr_lookup iterator
1622  std::map<const MXNode*, casadi_int>::const_iterator it_lookup;
1623 
1624  // Allocate storage for split outputs
1625  std::vector<std::vector<MX>> out_split(ex.size());
1626  for (casadi_int i = 0; i < out_split.size(); ++i) out_split[i].resize(ex[i].n_primitives());
1627 
1628  for (auto it=algorithm.begin(); it!=algorithm.end(); ++it) {
1629 
1630  if (it->op != OP_OUTPUT) {
1631  // Check if it->data points to a supplied expr
1632  it_lookup = expr_lookup.find((it->data).operator->());
1633 
1634  if (it_lookup!=expr_lookup.end()) {
1635  // Fill in that expression in-place
1636  MX e = vdef[it_lookup->second];
1637 
1638  // If node is of a MultipleOutput type
1639  if (e->has_output()) {
1640  for (casadi_int i=0;i<it->res.size();++i) {
1641  casadi_int k = it->res[i];
1642  if (k!=-1) {
1643  swork[k] = e.get_output(i);
1644  tainted[k] = true;
1645  }
1646  }
1647  } else {
1648  swork[it->res.front()] = e;
1649  tainted[it->res.front()] = true;
1650  }
1651  expr_found[it_lookup->second] = true;
1652  continue;
1653  } else if (it->data->has_output()) {
1654  bool any_tainted = false;
1655  // Loop over all oputputs of MultiOutput
1656  for (casadi_int i=0;i<it->res.size();++i) {
1657  // Create Output node (cached)
1658  casadi_int k = it->res[i];
1659  if (k!=-1) {
1660  MX out = it->data.get_output(i);
1661  // Check if out points to a supplied expr
1662  it_lookup = expr_lookup.find(out.operator->());
1663  if (it_lookup!=expr_lookup.end()) {
1664  // Fill in that expression in-place
1665  MX e = vdef[it_lookup->second];
1666  swork[k] = e;
1667  tainted[k] = true;
1668  any_tainted = true;
1669  expr_found[it_lookup->second] = true;
1670  }
1671  }
1672  }
1673  if (any_tainted) continue;
1674  }
1675  }
1676 
1677  switch (it->op) {
1678  case OP_INPUT:
1679  tainted[it->res.front()] = false;
1680  break;
1681  case OP_PARAMETER:
1682  swork[it->res.front()] = it->data;
1683  tainted[it->res.front()] = false;
1684  break;
1685  case OP_OUTPUT:
1686  out_split.at(it->data->ind()).at(it->data->segment()) = swork[it->arg.front()];
1687  break;
1688  default:
1689  {
1690  bool node_tainted = false;
1691 
1692  // Arguments of the operation
1693  oarg.resize(it->arg.size());
1694  for (casadi_int i=0; i<oarg.size(); ++i) {
1695  casadi_int el = it->arg[i];
1696  if (el>=0) node_tainted = node_tainted || tainted[el];
1697  oarg[i] = el<0 ? MX(it->data->dep(i).size()) : swork.at(el);
1698  }
1699 
1700  // Perform the operation
1701  ores.resize(it->res.size());
1702  if (!node_tainted) {
1703  if (it->data.has_output()) {
1704  for (casadi_int i=0;i<it->res.size();++i) {
1705  ores.at(i) = it->data.get_output(i);
1706  }
1707  } else {
1708  ores.at(0) = it->data;
1709  }
1710  } else {
1711  it->data->eval_mx(oarg, ores);
1712  }
1713 
1714  // Get the result
1715  for (casadi_int i=0; i<ores.size(); ++i) {
1716  casadi_int el = it->res[i];
1717  if (el>=0) swork.at(el) = ores[i];
1718  if (el>=0) tainted[el] = node_tainted;
1719  }
1720  }
1721  }
1722  }
1723 
1724  // Join primitives
1725  for (size_t k = 0; k < out_split.size(); ++k) {
1726  f_out[k] = ex[k].join_primitives(out_split.at(k));
1727  }
1728 
1729  bool all_found=true;
1730  for (casadi_int i=0;i<v.size();++i) {
1731  all_found = all_found && expr_found[i];
1732  }
1733 
1734  updated = any(expr_found);
1735 
1736  return f_out;
1737 
1738  }
1739 
1740  void MX::extract(std::vector<MX>& ex, std::vector<MX>& v,
1741  std::vector<MX>& vdef, const Dict& opts) {
1742  try {
1743  // Read options
1744  std::string v_prefix = "v_", v_suffix = "";
1745  bool lift_shared = true, lift_calls = false;
1746  casadi_int v_ind = 0;
1747  for (auto&& op : opts) {
1748  if (op.first == "prefix") {
1749  v_prefix = std::string(op.second);
1750  } else if (op.first == "suffix") {
1751  v_suffix = std::string(op.second);
1752  } else if (op.first == "lift_shared") {
1753  lift_shared = op.second;
1754  } else if (op.first == "lift_calls") {
1755  lift_calls = op.second;
1756  } else if (op.first == "offset") {
1757  v_ind = op.second;
1758  } else {
1759  casadi_error("No such option: " + std::string(op.first));
1760  }
1761  }
1762  // Sort the expression
1763  Function f("tmp_extract", std::vector<MX>{}, ex, Dict{{"max_io", 0}, {"allow_free", true}});
1764  auto *ff = f.get<MXFunction>();
1765  // Get references to the internal data structures
1766  const std::vector<MXAlgEl>& algorithm = ff->algorithm_;
1767  std::vector<MX> work(ff->workloc_.size()-1);
1768  // Count how many times an expression has been used
1769  std::vector<casadi_int> usecount(work.size(), 0);
1770  // Remember the origin of every calculation
1771  std::vector<std::pair<casadi_int, casadi_int> > origin(work.size(), std::make_pair(-1, -1));
1772  // Which evaluations to replace
1773  std::vector<std::pair<casadi_int, casadi_int> > replace;
1774  // Evaluate the algorithm to identify which evaluations to replace
1775  casadi_int k=0;
1776  for (auto it=algorithm.begin(); it<algorithm.end(); ++it, ++k) {
1777  // Increase usage counters
1778  switch (it->op) {
1779  case OP_CONST:
1780  case OP_PARAMETER:
1781  break;
1782  default: // Unary operation, binary operation or output
1783  for (casadi_int c=0; c<it->arg.size(); ++c) {
1784  // Identify nodes used more than once
1785  if (lift_calls && it->op == OP_CALL) {
1786  // If not already marked for replacing
1787  if (usecount.at(it->arg[c]) >= 0) {
1788  replace.push_back(origin.at(it->arg[c]));
1789  usecount.at(it->arg[c]) = -1; // Do not replace again
1790  }
1791  } else if (lift_shared && work[it->arg[c]].op() != OP_PARAMETER
1792  && work[it->arg[c]].op() != OP_CONST) {
1793  if (usecount.at(it->arg[c]) == 0) {
1794  // First time node is used
1795  usecount.at(it->arg[c]) = 1;
1796  } else if (usecount.at(it->arg[c]) == 1) {
1797  // Second time node is used
1798  replace.push_back(origin.at(it->arg[c]));
1799  usecount.at(it->arg[c]) = -1; // Do not replace again
1800  }
1801  }
1802  }
1803  }
1804  // Perform the operation
1805  switch (it->op) {
1806  case OP_OUTPUT:
1807  break;
1808  case OP_CONST:
1809  usecount[it->res.front()] = -1; // Never extract constants
1810  break;
1811  default:
1812  for (casadi_int c=0; c<it->res.size(); ++c) {
1813  if (it->res[c]>=0) {
1814  work[it->res[c]] = it->data.get_output(c);
1815  origin[it->res[c]] = std::make_pair(k, c);
1816  if (lift_calls && it->op == OP_CALL) {
1817  // If function call, replace right away
1818  replace.push_back(origin.at(it->res[c]));
1819  usecount.at(it->res[c]) = -1; // Do not replace again
1820  } else {
1821  usecount.at(it->res[c]) = 0; // Not (yet) extracted
1822  }
1823  }
1824  }
1825  break;
1826  }
1827  }
1828  // New variables and definitions
1829  v.clear();
1830  v.reserve(replace.size());
1831  vdef.clear();
1832  vdef.reserve(replace.size());
1833  // Quick return
1834  if (replace.empty()) return;
1835  // Sort the elements to be replaced in the order of appearence in the algorithm
1836  sort(replace.begin(), replace.end());
1837  std::vector<std::pair<casadi_int, casadi_int> >::const_iterator replace_it=replace.begin();
1838  // Arguments for calling the atomic operations
1839  std::vector<MX> oarg, ores;
1840  // Evaluate the algorithm
1841  k = 0;
1842  for (auto it=algorithm.begin(); it<algorithm.end(); ++it, ++k) {
1843  switch (it->op) {
1844  case OP_OUTPUT:
1845  casadi_assert(it->data->segment()==0, "Not implemented");
1846  ex[it->data->ind()] = work[it->arg.front()];
1847  break;
1848  case OP_CONST:
1849  work[it->res.front()] = it->data;
1850  break;
1851  default:
1852  {
1853  if (it->op == OP_PARAMETER) {
1854  // Free parameter
1855  work[it->res.front()] = it->data;
1856  } else {
1857  // Arguments of the operation
1858  oarg.resize(it->arg.size());
1859  for (casadi_int i=0; i<oarg.size(); ++i) {
1860  casadi_int el = it->arg[i];
1861  oarg[i] = el<0 ? MX(it->data->dep(i).size()) : work.at(el);
1862  }
1863  // Perform the operation
1864  ores.resize(it->res.size());
1865  it->data->eval_mx(oarg, ores);
1866  // Get the result
1867  for (casadi_int i=0; i<ores.size(); ++i) {
1868  casadi_int el = it->res[i];
1869  if (el>=0) work.at(el) = ores[i];
1870  }
1871  }
1872  // Possibly replace results with new variables
1873  for (casadi_int c=0; c<it->res.size(); ++c) {
1874  // Output index
1875  casadi_int ind = it->res[c];
1876  // In the list of nodes for replacing?
1877  bool replace_node = replace_it != replace.end()
1878  && replace_it->first==k && replace_it->second==c;
1879  // Call node (introduce variable for outputs, even if unused)
1880  bool output_node = lift_calls && it->op == OP_CALL;
1881  // Skip if no reason to replace
1882  if (!replace_node && !output_node) continue;
1883  // Create a new variable
1884  Sparsity v_sp = it->op == OP_PARAMETER ? it->data.sparsity() : ores.at(c).sparsity();
1885  v.push_back(MX::sym(v_prefix + std::to_string(v_ind++) + v_suffix, v_sp));
1886  // Add definition of new variable
1887  if (ind >= 0) {
1888  // Replace existing call
1889  casadi_assert(replace_node, "Consistency check");
1890  // Store the result
1891  vdef.push_back(work[ind]);
1892  // Use in calculations
1893  work[ind] = v.back();
1894  // Go to the next element to be replaced
1895  replace_it++;
1896  } else {
1897  // New node corresponding to an output
1898  casadi_assert(output_node, "Consistency check");
1899  // Store the result
1900  vdef.push_back(ores.at(c));
1901  }
1902  }
1903  }
1904  }
1905  }
1906  // Ensure all nodes have been replaced
1907  casadi_assert(replace_it == replace.end(), "Consistency check failed");
1908  } catch (std::exception& e) {
1909  CASADI_THROW_ERROR("extract", e.what());
1910  }
1911  }
1912 
1913  void MX::shared(std::vector<MX>& ex, std::vector<MX>& v, std::vector<MX>& vdef,
1914  const std::string& v_prefix, const std::string& v_suffix) {
1915  // Call new, more generic function
1916  extract(ex, v, vdef, Dict{{"lift_shared", true}, {"lift_calls", false},
1917  {"prefix", v_prefix}, {"suffix", v_suffix}});
1918  }
1919 
1920  MX MX::jacobian(const MX &f, const MX &x, const Dict& opts) {
1921  try {
1922  Dict h_opts;
1923  Dict opts_remainder = extract_from_dict(opts, "helper_options", h_opts);
1924  h_opts["allow_free"] = true;
1925  Function h("helper_jacobian_MX", {x}, {f}, h_opts);
1926  return h.get<MXFunction>()->jac(opts_remainder).at(0);
1927  } catch (std::exception& e) {
1928  CASADI_THROW_ERROR("jacobian", e.what());
1929  }
1930  }
1931 
1932  MX MX::hessian(const MX& f, const MX& x, const Dict& opts) {
1933  MX g;
1934  return hessian(f, x, g, opts);
1935  }
1936 
1937  MX MX::hessian(const MX& f, const MX& x, MX &g, const Dict& opts) {
1938  try {
1939  Dict all_opts = opts;
1940  g = gradient(f, x, opts);
1941  if (!opts.count("symmetric")) all_opts["symmetric"] = true;
1942  return jacobian(g, x, all_opts);
1943  } catch (std::exception& e) {
1944  CASADI_THROW_ERROR("hessian", e.what());
1945  }
1946  }
1947 
1948  std::vector<std::vector<MX> >
1949  MX::forward(const std::vector<MX> &ex,
1950  const std::vector<MX> &arg,
1951  const std::vector<std::vector<MX> > &v, const Dict& opts) {
1952  try {
1953  // Read options
1954  bool always_inline = true;
1955  bool never_inline = false;
1956 
1957  Dict h_opts;
1958  Dict opts_remainder = extract_from_dict(opts, "helper_options", h_opts);
1959  h_opts["allow_free"] = true;
1960  for (auto&& op : opts_remainder) {
1961  if (op.first=="always_inline") {
1962  always_inline = op.second;
1963  } else if (op.first=="never_inline") {
1964  never_inline = op.second;
1965  } else {
1966  casadi_error("No such option: " + std::string(op.first));
1967  }
1968  }
1969  // Call internal function on a temporary object
1970  Function temp("forward_temp", arg, ex, h_opts);
1971  std::vector<std::vector<MX> > ret;
1972  temp->call_forward(arg, ex, v, ret, always_inline, never_inline);
1973  return ret;
1974  } catch (std::exception& e) {
1975  CASADI_THROW_ERROR("forward", e.what());
1976  }
1977  }
1978 
1979  std::vector<std::vector<MX> >
1980  MX::reverse(const std::vector<MX> &ex,
1981  const std::vector<MX> &arg,
1982  const std::vector<std::vector<MX> > &v, const Dict& opts) {
1983  try {
1984  // Read options
1985  bool always_inline = true;
1986  bool never_inline = false;
1987 
1988 
1989  Dict h_opts;
1990  Dict opts_remainder = extract_from_dict(opts, "helper_options", h_opts);
1991  h_opts["allow_free"] = true;
1992 
1993  for (auto&& op : opts_remainder) {
1994  if (op.first=="always_inline") {
1995  always_inline = op.second;
1996  } else if (op.first=="never_inline") {
1997  never_inline = op.second;
1998  } else {
1999  casadi_error("No such option: " + std::string(op.first));
2000  }
2001  }
2002  // Call internal function on a temporary object
2003  Function temp("reverse_temp", arg, ex, h_opts);
2004  std::vector<std::vector<MX> > ret;
2005  temp->call_reverse(arg, ex, v, ret, always_inline, never_inline);
2006  return ret;
2007  } catch (std::exception& e) {
2008  CASADI_THROW_ERROR("reverse", e.what());
2009  }
2010  }
2011 
2012  std::vector<bool> MX::which_depends(const MX &expr, const MX &var, casadi_int order, bool tr) {
2013  return _which_depends(expr, var, order, tr);
2014  }
2015 
2016  Sparsity MX::jacobian_sparsity(const MX &f, const MX &x) {
2017  return _jacobian_sparsity(f, x);
2018  }
2019 
2020  MX MX::det(const MX& x) {
2021  return det(x, "qr");
2022  }
2023 
2024  MX MX::det(const MX& x, const std::string& lsolver, const Dict& opts) {
2025  Linsol mysolver("det", lsolver, x.sparsity(), opts);
2026  return mysolver.det(x);
2027  }
2028 
2029  MX MX::inv_node(const MX& x) {
2030  return x->get_inv();
2031  }
2032 
2033  MX MX::inv_minor(const MX& A) {
2034  casadi_error("Not implemented");
2035  }
2036 
2037  MX MX::inv(const MX& x, const std::string& lsolver, const Dict& dict) {
2038  return solve(x, MX::eye(x.size1()), lsolver, dict);
2039  }
2040 
2041  std::vector<MX> MX::symvar(const MX& x) {
2042  Function f("f", std::vector<MX>{}, {x}, {{"allow_free", true}});
2043  return f.free_mx();
2044  }
2045 
2046  MX MX::matrix_expand(const MX& e, const std::vector<MX> &boundary, const Dict &options) {
2047  return matrix_expand(std::vector<MX>{e}, boundary, options).at(0);
2048  }
2049 
2050  std::vector<MX> MX::matrix_expand(const std::vector<MX>& e,
2051  const std::vector<MX> &boundary,
2052  const Dict &options) {
2053 
2054  // Create symbols for boundary nodes
2055  std::vector<MX> syms(boundary.size());
2056 
2057  for (casadi_int i=0;i<syms.size();++i) {
2058  syms[i] = MX::sym("x", boundary[i].sparsity());
2059  }
2060 
2061  // Substitute symbols for boundary nodes
2062  std::vector<MX> ret = graph_substitute(e, boundary, syms);
2063 
2064  // Obtain list of dependents
2065  std::vector<MX> v = symvar(veccat(ret));
2066 
2067  // Construct an MXFunction with it
2068  Function f("tmp_matrix_expand", v, ret, Dict{{"max_io", 0}, {"allow_free", true}});
2069 
2070  // Expand to SXFunction
2071  Function s = f.expand("expand_" + f.name(), options);
2072  std::vector<MX> r;
2073  s.call(graph_substitute(v, syms, boundary), r);
2074  return r;
2075  }
2076 
2077  MX MX::kron(const MX& a, const MX& b) {
2078  return a->get_kron(b);
2079  }
2080 
2081  MX MX::kron_contract(const MX& m, const MX& x, bool inner) {
2082  return m->get_kron_contract(x, inner);
2083  }
2084 
2085  MX MX::repmat(const MX& x, casadi_int n, casadi_int m) {
2086  if (n==0 && m==0) {
2087  return MX();
2088  } else if (n==0) {
2089  return MX(0, x.size2()*m);
2090  } else if (m==0) {
2091  return MX(x.size1()*n, 0);
2092  } else if (n==1 && m==1) {
2093  return x;
2094  } else {
2095  return x->get_repmat(n, m);
2096  }
2097  }
2098 
2099  MX MX::repsum(const MX& x, casadi_int n, casadi_int m) {
2100  return x->get_repsum(n, m);
2101  }
2102 
2103  MX MX::linspace(const MX& a, const MX& b, casadi_int nsteps) {
2104  // Specialized over GenericMatrix<MX>::linspace to keep the MX graph
2105  // O(1) in nsteps. The FP recipe (a + i*step interior, literal b at
2106  // the endpoint) matches the generic implementation and numpy.linspace
2107  // bit-for-bit; see test_linspace in test/python/matrix.py.
2108  if (nsteps < 2) return b;
2109  MX step = (b - a) / static_cast<double>(nsteps - 1);
2110  std::vector<double> idx(nsteps - 1);
2111  for (casadi_int i = 0; i < nsteps - 1; ++i) idx[i] = static_cast<double>(i);
2112  return vertcat(std::vector<MX>{a + DM(idx) * step, b});
2113  }
2114 
2115  MX MX::solve(const MX& a, const MX& b) {
2116  if (a.is_triu()) {
2117  // A is upper triangular
2118  return a->get_solve_triu(b, false);
2119  } else if (a.is_tril()) {
2120  // A is lower triangular
2121  return a->get_solve_tril(b, false);
2122  } else if (a.sparsity().is_orthonormal()) {
2123  // A is orthonormal -> inv(A)==A.T
2124  MX nz = sparsity_cast(a, Sparsity::dense(a.nnz()));
2125  const Sparsity& Q = a.sparsity();
2126  return mtimes(MX(Q, 1/nz).T(), b);
2127  } else {
2128  // Fall-back to QR factorization
2129  return solve(a, b, "qr");
2130  }
2131  }
2132 
2133  MX MX::solve(const MX& a, const MX& b, const std::string& lsolver, const Dict& dict) {
2134  if (a.sparsity().is_orthonormal()) return solve(a, b);
2135  Linsol mysolver("tmp_solve", lsolver, a.sparsity(), dict);
2136  return mysolver.solve(a, b, false);
2137  }
2138 
2139  MX MX::pinv(const MX& A, const std::string& lsolver, const Dict& dict) {
2140  if (A.size1()>=A.size2()) {
2141  return solve(mtimes(A.T(), A), A.T(), lsolver, dict);
2142  } else {
2143  return solve(mtimes(A, A.T()), A, lsolver, dict).T();
2144  }
2145  }
2146 
2147  MX MX::expm_const(const MX& A, const MX& t) {
2148  Dict opts;
2149  opts["const_A"] = true;
2150  Function ret = expmsol("mysolver", "slicot", A.sparsity(), opts);
2151  return ret(std::vector<MX>{A, t})[0];
2152  }
2153 
2154  MX MX::expm(const MX& A) {
2155  Function ret = expmsol("mysolver", "slicot", A.sparsity());
2156  return ret(std::vector<MX>{A, 1})[0];
2157  }
2158 
2159  MX MX::nullspace(const MX& A) {
2160  SX A_sx = SX::sym("A", A.sparsity());
2161  Function f("nullspace", {A_sx}, {SX::nullspace(A_sx)});
2162  return f(A).at(0);
2163  }
2164 
2165  bool MX::depends_on(const MX &x, const MX &arg) {
2166  if (x.nnz()==0) return false;
2167 
2168  // Construct a temporary algorithm
2169  Function temp("tmp_depends_on", {arg}, {x}, Dict{{"max_io", 0}, {"allow_free", true}});
2170 
2171  // Perform a single dependency sweep
2172  std::vector<bvec_t> t_in(arg.nnz(), 1), t_out(x.nnz());
2173  temp({get_ptr(t_in)}, {get_ptr(t_out)});
2174 
2175  // Loop over results
2176  for (casadi_int i=0; i<t_out.size(); ++i) {
2177  if (t_out[i]) return true;
2178  }
2179 
2180  return false;
2181  }
2182 
2183 
2184  bool MX::contains_all(const std::vector<MX>& v, const std::vector<MX> &n) {
2185  if (n.empty()) return true;
2186 
2187  // Set to contain all nodes
2188  std::set<MXNode*> l;
2189  for (const MX& e : v) l.insert(e.get());
2190 
2191  size_t l_unique = l.size();
2192 
2193  for (const MX& e : n) l.insert(e.get());
2194 
2195  return l.size()==l_unique;
2196  }
2197 
2198  bool MX::contains_any(const std::vector<MX>& v, const std::vector<MX> &n) {
2199  if (n.empty()) return true;
2200 
2201  // Set to contain all nodes
2202  std::set<MXNode*> l;
2203  for (const MX& e : v) l.insert(e.get());
2204 
2205  size_t l_unique = l.size();
2206 
2207  std::set<MXNode*> r;
2208  for (const MX& e : n) r.insert(e.get());
2209 
2210  size_t r_unique = r.size();
2211  for (const MX& e : n) l.insert(e.get());
2212 
2213  return l.size()<l_unique+r_unique;
2214  }
2215 
2216  MX MX::find(const MX& x) {
2217  return x->get_find();
2218  }
2219 
2220  MX MX::low(const MX& v, const MX& p, const Dict& options) {
2221  return p->get_low(v, options);
2222  }
2223 
2224  MX MX::bspline(const MX& x,
2225  const DM& coeffs,
2226  const std::vector< std::vector<double> >& knots,
2227  const std::vector<casadi_int>& degree,
2228  casadi_int m,
2229  const Dict& opts) {
2230  return BSpline::create(x, knots, coeffs.nonzeros(), degree, m, opts);
2231  }
2232 
2233  MX MX::bspline(const MX& x, const MX& coeffs,
2234  const std::vector< std::vector<double> >& knots,
2235  const std::vector<casadi_int>& degree,
2236  casadi_int m,
2237  const Dict& opts) {
2238  return BSplineParametric::create(x, coeffs, knots, degree, m, opts);
2239  }
2240 
2241  MX MX::bspline(const MX& x, const MX& coeffs,
2242  const std::vector<MX>& knots,
2243  const std::vector<casadi_int>& degree,
2244  casadi_int m,
2245  const Dict& opts) {
2246  return BSplineParametric::create(x, coeffs, knots, degree, m, opts);
2247  }
2248 
2249  DM MX::bspline_dual(const std::vector<double>& x,
2250  const std::vector< std::vector<double> >& knots,
2251  const std::vector<casadi_int>& degree,
2252  const Dict& opts) {
2253  return BSpline::dual(x, knots, degree, opts);
2254  }
2255 
2256  MX MX::convexify(const MX& H,
2257  const Dict& opts) {
2258  return H->get_convexify(opts);
2259  }
2260 
2261  bool simplify_const_folding_order(std::vector<MX>& arg,
2262  std::vector<MX>& res,
2263  const Dict& opts) {
2264  Dict temp_opts = {{"live_variables", false},
2265  {"max_io", 0},
2266  {"cse", false},
2267  {"allow_free", true}};
2268  Function f("temp", arg, res, temp_opts);
2269  MXFunction *ff = f.get<MXFunction>();
2270  const std::vector<casadi_int>& workloc_ = ff->workloc_;
2271  const auto& algorithm_ = ff->algorithm_;
2272 
2273  // Is the work vector entry numeric?
2274  std::vector<bool> is_numeric(workloc_.size()-1);
2275  // Symbolic work, non-differentiated
2276  std::vector<MX> swork(workloc_.size()-1);
2277 
2278  // Split up inputs analogous to symbolic primitives
2279  std::vector<std::vector<MX> > arg_split(arg.size());
2280  for (casadi_int i=0; i<arg.size(); ++i) arg_split[i] = arg[i].split_primitives(arg[i]);
2281 
2282  // Allocate storage for split outputs
2283  std::vector<std::vector<MX> > res_split(res.size());
2284  for (casadi_int i=0; i<res.size(); ++i) res_split[i].resize(res[i].n_primitives());
2285 
2286  std::vector<MX> arg1, res1;
2287 
2288  std::unordered_map<const MXNode*, bool> numeric_node;
2289  // Loop over computational nodes in forward order
2290  for (auto it=algorithm_.begin(); it!=algorithm_.end(); ++it) {
2291  if (it->op == OP_INPUT) {
2292  swork[it->res.front()] = project(arg_split.at(it->data->ind()).at(it->data->segment()),
2293  it->data.sparsity(), true);
2294  is_numeric[it->res.front()] = false;
2295  } else if (it->op==OP_OUTPUT) {
2296  // Collect the results
2297  res_split.at(it->data->ind()).at(it->data->segment()) = swork[it->arg.front()];
2298  } else if (it->op==OP_PARAMETER) {
2299  // Fetch parameter
2300  swork[it->res.front()] = it->data;
2301  is_numeric[it->res.front()] = false;
2302  } else {
2303  // Arguments of the operation
2304  arg1.resize(it->arg.size());
2305 
2306 
2307  bool numeric = true;
2308 
2309  for (casadi_int i=0; i<arg1.size(); ++i) {
2310  casadi_int el = it->arg[i];
2311  if (el<0) {
2312  arg1[i] = MX(it->data->dep(i).size());
2313  } else {
2314  arg1[i] = swork[el];
2315  numeric = numeric && is_numeric[el];
2316  }
2317  }
2318 
2319  numeric_node[it->data.get()] = numeric;
2320 
2321  // Perform the operation
2322  res1.resize(it->res.size());
2323 
2324  bool matched = false;
2325  // Rules to promote constant folding
2326  // A*(B*X)
2327  if (it->op == OP_MUL && is_numeric[it->arg[0]] &&
2328  !is_numeric[it->arg[1]] && arg1[1].is_op(OP_MUL)) {
2329  if (numeric_node[arg1[1].dep(0).get()]) {
2330  matched = true;
2331  res1[0] = (arg1[0]*arg1[1].dep(0))*arg1[1].dep(1);
2332  }
2333  }
2334 
2335  if (!matched) it->data->eval_mx(arg1, res1);
2336 
2337  for (casadi_int i=0; i<res1.size(); ++i) {
2338  casadi_int el = it->res[i]; // index of the output
2339  if (el>=0) {
2340  is_numeric[el] = numeric;
2341  }
2342  }
2343 
2344  // Get the result
2345  for (casadi_int i=0; i<res1.size(); ++i) {
2346  casadi_int el = it->res[i]; // index of the output
2347  if (el>=0) {
2348  swork[el] = res1[i];
2349  }
2350  }
2351  }
2352  }
2353 
2354  // Join split outputs
2355  for (casadi_int i=0; i<res.size(); ++i) res[i] = res[i].join_primitives(res_split[i]);
2356 
2357  return true;
2358  }
2359 
2360  MX get_const(const Sparsity& sp, const double *v,
2361  std::unordered_multimap< std::size_t, std::pair<MX, DM> >& cache) {
2362  // Compute hash from sparsity and double values
2363  std::size_t h = sp.hash();
2364  hash_combine(h, v, sp.nnz());
2365 
2366  // Loop over tentative matches
2367  auto r = cache.equal_range(h);
2368  for (auto it = r.first; it != r.second; ++it) {
2369  const DM& d = it->second.second;
2370  if (d.sparsity()==sp && std::equal(d.ptr(), d.ptr()+sp.nnz(), v)) {
2371  // Found match
2372  return it->second.first;
2373  }
2374  }
2375 
2376  // fallthrough: failed to find a match
2377 
2378  // Create a <MX,DM> pair and store in cache
2379  std::vector<double> vec(v, v+sp.nnz());
2380  DM m(sp, vec);
2381  MX ret = m;
2382  cache.emplace(h, std::make_pair(ret, m));
2383 
2384  // Return the MX
2385  return ret;
2386  }
2387 
2388  bool MX::simplify_const_folding(std::vector<MX>& arg,
2389  std::vector<MX>& res,
2390  const Dict& opts) {
2391  simplify_const_folding_order(arg, res, opts);
2392  Dict temp_opts = {{"live_variables", false},
2393  {"max_io", 0},
2394  {"cse", false},
2395  {"allow_free", true}};
2396  Function f("temp", arg, res, temp_opts);
2397  MXFunction *ff = f.get<MXFunction>();
2398  const std::vector<casadi_int>& workloc_ = ff->workloc_;
2399  const auto& algorithm_ = ff->algorithm_;
2400 
2401  // Data structures for numeric evaluation
2402  std::vector<double> w_vec(f.sz_w());
2403  double* w = get_ptr(w_vec);
2404  std::vector<casadi_int> iw_vec(f.sz_iw());
2405  casadi_int* iw = get_ptr(iw_vec);
2406  std::vector<const double*> arg_num_vec(f.sz_arg());
2407  const double** arg_num = get_ptr(arg_num_vec);
2408  std::vector<double*> res_num_vec(f.sz_res());
2409  double** res_num = get_ptr(res_num_vec);
2410 
2411  // Is the work vector entry numeric?
2412  std::vector<bool> is_numeric(workloc_.size()-1);
2413 
2414  // Data structures for symbolic evaluation
2415 
2416  // Symbolic work, non-differentiated
2417  std::vector<MX> swork(workloc_.size()-1);
2418 
2419  // Split up inputs analogous to symbolic primitives
2420  std::vector<std::vector<MX> > arg_split(arg.size());
2421  for (casadi_int i=0; i<arg.size(); ++i) arg_split[i] = arg[i].split_primitives(arg[i]);
2422 
2423  // Allocate storage for split outputs
2424  std::vector<std::vector<MX> > res_split(res.size());
2425  for (casadi_int i=0; i<res.size(); ++i) res_split[i].resize(res[i].n_primitives());
2426 
2427  std::vector<MX> arg1, res1;
2428 
2429  std::unordered_multimap< std::size_t, std::pair<MX, DM> > cache;
2430 
2431  bool performed_folding = false;
2432 
2433  // Loop over computational nodes in forward order
2434  for (auto it=algorithm_.begin(); it!=algorithm_.end(); ++it) {
2435  if (it->op == OP_INPUT) {
2436  swork[it->res.front()] = project(arg_split.at(it->data->ind()).at(it->data->segment()),
2437  it->data.sparsity(), true);
2438  is_numeric[it->res.front()] = false;
2439  } else if (it->op==OP_OUTPUT) {
2440  // Collect the results
2441  MX& target = res_split.at(it->data->ind()).at(it->data->segment());
2442  casadi_int el = it->arg.front();
2443  if (is_numeric[el] && !it->data->dep().is_constant()) {
2444  target = get_const(it->data->dep().sparsity(), w + workloc_[el], cache);
2445  } else {
2446  target = swork[el];
2447  }
2448  } else if (it->op==OP_PARAMETER) {
2449  // Fetch parameter
2450  swork[it->res.front()] = it->data;
2451  is_numeric[it->res.front()] = false;
2452  } else {
2453  // Arguments of the operation
2454  arg1.resize(it->arg.size());
2455 
2456  // Is current algel numeric?
2457  bool numeric = true;
2458 
2459  // Loop over algel inputs
2460  for (casadi_int i=0; i<arg1.size(); ++i) {
2461  casadi_int el = it->arg[i];
2462  if (el<0) {
2463  // Populate arg1 vector
2464  arg1[i] = MX(it->data->dep(i).size());
2465  } else {
2466  // Populate arg1 vector
2467  arg1[i] = swork[el];
2468  // Can only be numeric if arguments are
2469  numeric = numeric && is_numeric[el];
2470  }
2471  }
2472 
2473  if (numeric) {
2474  // Set up arg_num and res_num for numerical evaluation
2475  for (casadi_int i=0; i<it->arg.size(); ++i)
2476  arg_num[i] = it->arg[i]>=0 ? w+workloc_[it->arg[i]] : nullptr;
2477  for (casadi_int i=0; i<it->res.size(); ++i)
2478  res_num[i] = it->res[i]>=0 ? w+workloc_[it->res[i]] : nullptr;
2479 
2480  if (it->data->eval(arg_num, res_num, iw, w)) casadi_error("Evaluation error");
2481  performed_folding = true;
2482  } else {
2483  // Prepare for symbolic evaluation
2484  for (casadi_int i=0; i<arg1.size(); ++i) {
2485  casadi_int el = it->arg[i];
2486  if (el>=0) {
2487  MX& target = arg1[i];
2488  if (is_numeric[el] && !it->data->dep(i).is_constant()) {
2489  target = get_const(it->data->dep(i).sparsity(), w + workloc_[el], cache);
2490  } else {
2491  target = swork[el];
2492  }
2493  }
2494  }
2495  }
2496 
2497  // Perform the operation
2498  res1.resize(it->res.size());
2499  it->data->eval_mx(arg1, res1);
2500 
2501  // Process results
2502  for (casadi_int i=0; i<res1.size(); ++i) {
2503  casadi_int el = it->res[i]; // index of the output
2504  if (el>=0) {
2505  swork[el] = res1[i]; // store symbolic result
2506  is_numeric[el] = numeric; // store flag
2507  }
2508  }
2509  }
2510  }
2511 
2512  // Join split outputs
2513  for (casadi_int i=0; i<res.size(); ++i) res[i] = res[i].join_primitives(res_split[i]);
2514 
2515  return performed_folding;
2516  }
2517 
2518  bool MX::simplify_ref_count(std::vector<MX>& arg,
2519  std::vector<MX>& res,
2520  const Dict& opts) {
2521  Dict temp_opts = {{"live_variables", false},
2522  {"max_io", 0},
2523  {"cse", false},
2524  {"allow_free", true}};
2525  Function f("temp", arg, res, temp_opts);
2526  MXFunction *ff = f.get<MXFunction>();
2527  const std::vector<casadi_int>& workloc_ = ff->workloc_;
2528  const auto& algorithm_ = ff->algorithm_;
2529 
2530  std::vector<casadi_int> rwork(workloc_.size()-1);
2531  for (auto it=algorithm_.begin(); it!=algorithm_.end(); ++it) {
2532  if (it->op == OP_INPUT) {
2533  } else if (it->op==OP_OUTPUT) {
2534  rwork[it->arg.front()]++;
2535  } else if (it->op==OP_PARAMETER) {
2536  rwork[it->res.front()]++;
2537  } else {
2538  for (casadi_int i=0; i<it->arg.size(); ++i) {
2539  casadi_int el = it->arg[i];
2540  if (el>=0) {
2541  rwork[el]++;
2542  }
2543  }
2544  }
2545  }
2546 
2547  // Forward pass
2548  {
2549 
2550  // Symbolic work, non-differentiated
2551  std::vector<MX> swork(workloc_.size()-1);
2552 
2553  // Split up inputs analogous to symbolic primitives
2554  std::vector<std::vector<MX> > arg_split(arg.size());
2555  for (casadi_int i=0; i<arg.size(); ++i) arg_split[i] = arg[i].split_primitives(arg[i]);
2556 
2557  // Allocate storage for split outputs
2558  std::vector<std::vector<MX> > res_split(res.size());
2559  for (casadi_int i=0; i<res.size(); ++i) res_split[i].resize(res[i].n_primitives());
2560 
2561  std::vector<MX> arg1, res1;
2562 
2563  // Loop over computational nodes in forward order
2564  for (auto it=algorithm_.begin(); it!=algorithm_.end(); ++it) {
2565  if (it->op == OP_INPUT) {
2566  swork[it->res.front()] = project(arg_split.at(it->data->ind()).at(it->data->segment()),
2567  it->data.sparsity(), true);
2568  } else if (it->op==OP_OUTPUT) {
2569  // Collect the results
2570  res_split.at(it->data->ind()).at(it->data->segment()) = swork[it->arg.front()];
2571  } else if (it->op==OP_PARAMETER) {
2572  // Fetch parameter
2573  swork[it->res.front()] = it->data;
2574  } else {
2575  // Arguments of the operation
2576  arg1.resize(it->arg.size());
2577 
2578  std::vector<bool> unique(it->arg.size(), true);
2579  for (casadi_int i=0; i<arg1.size(); ++i) {
2580  casadi_int el = it->arg[i];
2581  if (el<0) {
2582  arg1[i] = MX(it->data->dep(i).size());
2583  } else {
2584  arg1[i] = swork[el];
2585  if (rwork[el]>1) unique[i] = false;
2586  }
2587  }
2588 
2589  // Perform the operation
2590  res1.resize(it->res.size());
2591  it->data->eval_mx(arg1, res1, unique);
2592 
2593  // Get the result
2594  for (casadi_int i=0; i<res1.size(); ++i) {
2595  casadi_int el = it->res[i]; // index of the output
2596  if (el>=0) {
2597  swork[el] = res1[i];
2598  }
2599  }
2600  }
2601  }
2602 
2603  // Join split outputs
2604  for (casadi_int i=0; i<res.size(); ++i) res[i] = res[i].join_primitives(res_split[i]);
2605  }
2606  return true;
2607  }
2608 
2609  class IncrementalSerializerMX {
2610  public:
2611 
2612  IncrementalSerializerMX() : serializer(ss) {
2613  }
2614 
2615  std::string pack(const MX& a) {
2616  // Serialization goes wrong if serialized SXNodes get destroyed
2617  ref.push_back(a);
2618  if (a.is_empty()) return "";
2619  // First serialize may introduce unknown dependencies (e.g. sparsity)
2620  // and hence definitions
2621  // Subsequent serialization will have references instead.
2622  // In order to still get a match with a later common subexpression,
2623  // make sure that all dependencies are already defined.
2624  a.serialize(serializer);
2625  ss.str("");
2626  ss.clear();
2627  a.serialize(serializer);
2628  std::string ret = ss.str();
2629  ss.str("");
2630  ss.clear();
2631  return ret;
2632  }
2633 
2634  private:
2635  std::stringstream ss;
2636  // List of references to keep alive
2637  std::vector<MX> ref;
2638  SerializingStream serializer;
2639  };
2640 
2641 
2642  std::vector<MX> MX::cse(const std::vector<MX>& e) {
2643  std::vector<MX> orig = e;
2644  bool updated = true;
2645  while (updated) {
2646  Function f("f", std::vector<MX>{}, orig,
2647  {{"live_variables", false}, {"max_io", 0}, {"cse", false}, {"allow_free", true}});
2648  MXFunction *ff = f.get<MXFunction>();
2649 
2650  // Symbolic work, non-differentiated
2651  std::vector<MX> swork(ff->workloc_.size()-1);
2652 
2653  // Allocate storage for split outputs
2654  std::vector<std::vector<MX> > res_split(orig.size());
2655  for (casadi_int i=0; i<orig.size(); ++i) res_split[i].resize(orig[i].n_primitives());
2656 
2657  std::vector<MX> arg1, res1;
2658  std::vector<MX> res(orig.size());
2659 
2660  std::unordered_map<std::string, MX > cache;
2661  IncrementalSerializerMX s;
2662 
2663  SimpleCache<FunctionInternal*, std::string> function_serialize_cache;
2664  SimpleCache<std::string, Function> function_cache;
2665 
2666  // Pre-cache the original nodes
2667  // This makes sure we recycle old nodes when possible
2668  for (auto it=ff->algorithm_.begin(); it!=ff->algorithm_.end(); ++it) {
2669  if (it->op == OP_INPUT || it->op==OP_OUTPUT || it->op==OP_PARAMETER) continue;
2670 
2671  std::string key = s.pack(it->data);
2672 
2673  auto itk = cache.find(key);
2674  if (itk==cache.end()) {
2675  cache[key] = it->data;
2676  }
2677  }
2678 
2679  // Loop over computational nodes in forward order
2680  casadi_int alg_counter = 0;
2681  for (auto it=ff->algorithm_.begin(); it!=ff->algorithm_.end(); ++it, ++alg_counter) {
2682  if (it->op == OP_INPUT) {
2683  // pass
2684  } else if (it->op==OP_OUTPUT) {
2685  // Collect the results
2686  res_split.at(it->data->ind()).at(it->data->segment()) = swork[it->arg.front()];
2687  } else if (it->op==OP_PARAMETER) {
2688  // Fetch parameter
2689  MX& target = swork[it->res.front()];
2690  target = it->data;
2691  cache[s.pack(target)] = target;
2692  } else {
2693 
2694  // Arguments of the operation
2695  arg1.resize(it->arg.size());
2696  for (casadi_int i=0; i<arg1.size(); ++i) {
2697  casadi_int el = it->arg[i]; // index of the argument
2698  arg1[i] = el<0 ? MX(it->data->dep(i).size()) : swork[el];
2699  }
2700 
2701  // Perform the operation
2702  res1.resize(it->res.size());
2703  it->data->eval_mx(arg1, res1);
2704 
2705  // Get the result
2706  for (casadi_int i=0; i<res1.size(); ++i) {
2707  casadi_int el = it->res[i]; // index of the output
2708 
2709  MX& out_i = res1[i];
2710 
2711  // Default assumption is that out_i is not an output node
2712  casadi_int output_node = -1;
2713 
2714  if (out_i.is_output()) {
2715  output_node = out_i.which_output();
2716  // First pack/cache the parent (MultipleOutput node e.g. Call, Horzsplit)
2717  out_i = out_i.dep(0);
2718 
2719  // If we are a call node,
2720  if (out_i.op()==OP_CALL) {
2721  FunctionInternal* fptr = out_i.which_function().get();
2722 
2723  // Get or compute serialization (cached)
2724  std::string key_s;
2725  if (!function_serialize_cache.incache(fptr, key_s)) {
2726  key_s = out_i.which_function().serialize();
2727  function_serialize_cache.tocache(fptr, key_s);
2728  }
2729 
2730  // Get or store canonical function (cached)
2731  Function canonical;
2732  if (!function_cache.incache(key_s, canonical)) {
2733  function_cache.tocache(key_s, out_i.which_function());
2734  } else {
2735  out_i = Call::create_call(canonical, out_i->dep_);
2736  }
2737  }
2738  }
2739 
2740  while (true) {
2741  // Replace out_i by a cached variant if possible
2742  std::string key = s.pack(out_i);
2743 
2744  auto itk = cache.find(key);
2745  if (itk==cache.end()) {
2746  cache[key] = out_i;
2747  } else {
2748  out_i = itk->second;
2749  }
2750 
2751  if (output_node==-1) {
2752  break; // Job is done
2753  } else {
2754  // Recreate the output node on top of the parent
2755  out_i = out_i.get_output(output_node);
2756  output_node = -1;
2757  // Loop once more
2758  }
2759  }
2760 
2761  if (el>=0) swork[el] = out_i;
2762  }
2763  }
2764  }
2765 
2766  // Join split outputs
2767  for (casadi_int i=0; i<res.size(); ++i) res[i] = orig[i].join_primitives(res_split[i]);
2768 
2769  std::vector<MX> subs_from;
2770  std::vector<MX> subs_to;
2771  for (const auto& e : function_cache.cache_map()) {
2772  e.second->merge(res, subs_from, subs_to);
2773  }
2774  orig = graph_substitute(res, subs_from, subs_to, updated);
2775  }
2776 
2777  return orig;
2778  }
2779 
2780  MX register_symbol(const MX& node, std::map<MXNode*, MX>& symbol_map,
2781  std::vector<MX>& symbol_v, std::vector<MX>& parametric_v,
2782  bool extract_trivial, casadi_int v_offset,
2783  const std::string& v_prefix, const std::string& v_suffix) {
2784  // Check if a symbol is already registered
2785  auto it = symbol_map.find(node.get());
2786 
2787  // Ignore trivial expressions if applicable
2788  bool is_trivial = node.is_symbolic();
2789  if (is_trivial && !extract_trivial) {
2790  return node;
2791  }
2792 
2793  if (it==symbol_map.end()) {
2794  // Create a symbol and register
2795  MX sym = MX::sym(v_prefix + str(symbol_map.size()+v_offset) + v_suffix, node.sparsity());
2796  symbol_map[node.get()] = sym;
2797 
2798  // Make the (symbol,parametric expression) pair available
2799  symbol_v.push_back(sym);
2800  parametric_v.push_back(node);
2801 
2802  // Use the new symbol
2803  return sym;
2804  } else {
2805  // Just use the registered symbol
2806  return it->second;
2807  }
2808  }
2809 
2810  void MX::extract_parametric(const MX &expr, const MX& par,
2811  MX& expr_ret, std::vector<MX>& symbols, std::vector<MX>& parametric,
2812  const Dict& opts) {
2813  std::string v_prefix = "e_";
2814  std::string v_suffix = "";
2815  bool extract_trivial = false;
2816  casadi_int v_offset = 0;
2817  for (auto&& op : opts) {
2818  if (op.first == "prefix") {
2819  v_prefix = std::string(op.second);
2820  } else if (op.first == "suffix") {
2821  v_suffix = std::string(op.second);
2822  } else if (op.first == "offset") {
2823  v_offset = op.second;
2824  } else if (op.first == "extract_trivial") {
2825  extract_trivial = op.second;
2826  } else {
2827  casadi_error("No such option: " + std::string(op.first));
2828  }
2829  }
2830  Function f("f", {par}, {expr}, {{"live_variables", false},
2831  {"max_io", 0}, {"allow_free", true}});
2832  MXFunction *ff = f.get<MXFunction>();
2833 
2834  // Work vector
2835  std::vector< MX > w(ff->workloc_.size()-1);
2836 
2837  // Status of the expression:
2838  // 0: dependant on constants only
2839  // 1: dependant on parameters/constants only
2840  // 2: dependant on non-parameters
2841  std::vector< char > expr_status(ff->workloc_.size()-1, 0);
2842 
2843  // Split up inputs analogous to symbolic primitives
2844  std::vector<MX> arg_split = par.split_primitives(par);
2845 
2846  // Allocate storage for split outputs
2847  std::vector<MX> res_split;
2848  res_split.resize(expr.n_primitives());
2849 
2850  // Scratch space for node inputs/outputs
2851  std::vector<MX > arg1, res1;
2852 
2853  // Map of registered symbols
2854  std::map<MXNode*, MX> symbol_map;
2855 
2856  // Flat list of registerd symbols and parametric expressions
2857  std::vector<MX> symbol_v, parametric_v;
2858 
2859  // Loop over computational nodes in forward order
2860  casadi_int alg_counter = 0;
2861  for (auto it=ff->algorithm_.begin(); it!=ff->algorithm_.end(); ++it, ++alg_counter) {
2862  if (it->op == OP_INPUT) {
2863  w[it->res.front()] = arg_split.at(it->data->segment());
2864  expr_status[it->res.front()] = 1;
2865  } else if (it->op==OP_OUTPUT) {
2866  MX arg = w[it->arg.front()];
2867  if (expr_status[it->arg.front()]==1) {
2868  arg = register_symbol(arg, symbol_map, symbol_v, parametric_v,
2869  extract_trivial, v_offset, v_prefix, v_suffix);
2870  }
2871  // Collect the results
2872  res_split.at(it->data->segment()) = arg;
2873  } else if (it->op==OP_CONST) {
2874  // Fetch constant
2875  w[it->res.front()] = it->data;
2876  expr_status[it->res.front()] = 0;
2877  } else if (it->op==OP_PARAMETER) {
2878  // Free variables
2879  w[it->res.front()] = it->data;
2880  expr_status[it->res.front()] = 2;
2881  } else {
2882  // Arguments of the operation
2883  arg1.resize(it->arg.size());
2884  for (casadi_int i=0; i<arg1.size(); ++i) {
2885  casadi_int el = it->arg[i]; // index of the argument
2886  arg1[i] = el<0 ? MX(it->data->dep(i).size()) : w[el];
2887  }
2888 
2889  // Check worst case status of inputs
2890  char max_status = 0;
2891  for (casadi_int i=0; i<arg1.size(); ++i) {
2892  casadi_int el = it->arg[i]; // index of the argument
2893  if (el>=0) {
2894  max_status = std::max(max_status, expr_status[it->arg[i]]);
2895  }
2896  }
2897  bool any_tainted = max_status==2;
2898 
2899  if (any_tainted) {
2900  // Loop over all inputs
2901  for (casadi_int i=0; i<arg1.size(); ++i) {
2902  casadi_int el = it->arg[i]; // index of the argument
2903 
2904  // For each parametric input being mixed into a non-parametric expression
2905  if (el>=0 && expr_status[el]==1) {
2906 
2907  arg1[i] = register_symbol(w[el], symbol_map, symbol_v, parametric_v,
2908  extract_trivial, v_offset, v_prefix, v_suffix);
2909  }
2910  }
2911  }
2912 
2913  // Perform the operation
2914  res1.resize(it->res.size());
2915  it->data->eval_mx(arg1, res1);
2916 
2917  // Get the result
2918  for (casadi_int i=0; i<res1.size(); ++i) {
2919  casadi_int el = it->res[i]; // index of the output
2920  if (el>=0) {
2921  w[el] = res1[i];
2922  // Update expression status
2923  expr_status[el] = max_status;
2924  }
2925  }
2926  }
2927  }
2928 
2929  // Join split outputs
2930  expr_ret = expr.join_primitives(res_split);
2931 
2932  symbols = symbol_v;
2933  parametric = parametric_v;
2934  }
2935 
2936  void MX::separate_linear(const MX &expr,
2937  const MX &sym_lin, const MX &sym_const,
2938  MX& expr_const, MX& expr_lin, MX& expr_nonlin) {
2939 
2940  std::vector<MX> in = {sym_const, sym_lin};
2941  std::vector<MX> out = {expr};
2942 
2943  Function f("f", in, out, {{"live_variables", false},
2944  {"max_io", 0}, {"allow_free", true}});
2945  MXFunction *ff = f.get<MXFunction>();
2946 
2947  // Each work vector element has (const, lin, nonlin) part
2948  std::vector< std::array<MX, 3> > w(ff->workloc_.size()-1);
2949 
2950  // Split up inputs analogous to symbolic primitives
2951  std::vector<std::vector<MX> > arg_split(in.size());
2952  for (casadi_int i=0; i<in.size(); ++i) arg_split[i] = in[i].split_primitives(in[i]);
2953 
2954  // Allocate storage for split outputs
2955  std::array<std::vector<MX>, 3> res_split;
2956  for (int k=0;k<3;++k) {
2957  res_split[k].resize(expr.n_primitives());
2958  }
2959 
2960  std::vector<std::array<MX, 3> > arg1, res1;
2961 
2962  std::array<MX, 3> res;
2963 
2964  // Loop over computational nodes in forward order
2965  casadi_int alg_counter = 0;
2966  for (auto it=ff->algorithm_.begin(); it!=ff->algorithm_.end(); ++it, ++alg_counter) {
2967  if (it->op == OP_INPUT) {
2968  MX null = MX::zeros(arg_split.at(it->data->ind()).at(it->data->segment()).sparsity());
2969  w[it->res.front()][0] = null;
2970  w[it->res.front()][1] = null;
2971  w[it->res.front()][2] = null;
2972  w[it->res.front()][it->data->ind()] = arg_split.at(it->data->ind()).at(it->data->segment());
2973  } else if (it->op==OP_OUTPUT) {
2974  // Collect the results
2975  for (int i=0;i<3;++i) {
2976  res_split.at(i).at(it->data->segment()) = w[it->arg.front()][i];
2977  }
2978  } else if (it->op==OP_CONST) {
2979  // Fetch constant
2980  w[it->res.front()][0] = it->data;
2981  w[it->res.front()][1] = MX::zeros(it->data->sparsity());
2982  w[it->res.front()][2] = MX::zeros(it->data->sparsity());
2983  } else if (it->op==OP_PARAMETER) {
2984  // Fetch parameter
2985  w[it->res.front()][0] = MX::zeros(it->data->sparsity());
2986  w[it->res.front()][1] = MX::zeros(it->data->sparsity());
2987  w[it->res.front()][2] = it->data;
2988  } else {
2989  // Arguments of the operation
2990  arg1.resize(it->arg.size());
2991  for (casadi_int i=0; i<arg1.size(); ++i) {
2992  casadi_int el = it->arg[i]; // index of the argument
2993  for (int k=0;k<3;++k) {
2994  arg1[i][k] = el<0 ? MX(it->data->dep(i).size()) : w[el][k];
2995  }
2996  }
2997 
2998  // Perform the operation
2999  res1.clear();
3000  res1.resize(it->res.size());
3001  for (casadi_int i=0;i<it->res.size();++i) {
3002  for (int k=0;k<3;++k) {
3003  res1[i][k] = MX::zeros(it->data->sparsity());
3004  }
3005  }
3006  it->data->eval_linear(arg1, res1);
3007 
3008  // Get the result
3009  for (casadi_int i=0; i<res1.size(); ++i) {
3010  casadi_int el = it->res[i]; // index of the output
3011  for (int k=0;k<3;++k) {
3012  if (el>=0) w[el][k] = res1[i][k];
3013  }
3014  }
3015  }
3016  }
3017 
3018  // Join split outputs
3019  for (int k=0;k<3;++k) {
3020  res[k] = expr.join_primitives(res_split[k]);
3021  }
3022  expr_const = res[0];
3023  expr_lin = res[1];
3024  expr_nonlin = res[2];
3025  }
3026 
3027  MX MX::stop_diff(const MX& expr, casadi_int order) {
3028  std::vector<MX> s = symvar(expr);
3029  MX x = veccat(s);
3030  Dict options;
3031  options["never_inline"] = true;
3032 
3033  Dict inline_options;
3034  inline_options["never_inline"] = false;
3035  inline_options["always_inline"] = true;
3036  Dict der_options = Dict{{"forward_options", inline_options},
3037  {"reverse_options", inline_options},
3038  {"jacobian_options", inline_options}};
3039  if (order==1) {
3040  options["is_diff_in"] = std::vector<bool>{false};
3041  options["is_diff_out"] = std::vector<bool>{true};
3042  options = combine(options, der_options);
3043  } else if (order==2) {
3044  options["der_options"] = der_options;
3045  options["forward_options"] = Dict{{"is_diff_in", std::vector<bool>{false, true, true} },
3046  {"is_diff_out", std::vector<bool>{true}}};
3047  options["reverse_options"] = Dict{{"is_diff_in", std::vector<bool>{false, true, true} },
3048  {"is_diff_out", std::vector<bool>{true}}};
3049  options["jacobian_options"] = Dict{{"is_diff_in", std::vector<bool>{false, true} },
3050  {"is_diff_out", std::vector<bool>{false}}};
3051  } else {
3052  casadi_error("stop_diff: order must be 1 or 2, got " + str(order) + ".");
3053  }
3054 
3055  Function FS("FS", {x}, {expr}, {"x"}, {"z"}, options);
3056  return FS(std::vector<MX>{x})[0];
3057  }
3058 
3059  MX MX::stop_diff(const MX& expr, const MX& var, casadi_int order) {
3060  casadi_warning("stop_diff(expr, var, order) is not well tested.");
3061  std::vector<MX> xv = symvar(var);
3062  std::vector<MX> s = symvar(expr);
3063  std::vector<MX> yv = difference(s, xv);
3064 
3065  MX x = veccat(xv);
3066  MX y = veccat(yv);
3067 
3068  Dict options;
3069  options["never_inline"] = true;
3070 
3071  Dict inline_options;
3072  inline_options["never_inline"] = false;
3073  inline_options["always_inline"] = true;
3074  Dict der_options = Dict{{"forward_options", inline_options},
3075  {"reverse_options", inline_options},
3076  {"jacobian_options", inline_options}};
3077  if (order==1) {
3078  options["is_diff_in"] = std::vector<bool>{false, true};
3079  options["is_diff_out"] = std::vector<bool>{true};
3080  options = combine(options, der_options);
3081  } else if (order==2) {
3082  options["der_options"] = der_options;
3083  options["forward_options"] = Dict{{"is_diff_in",
3084  std::vector<bool>{false, true, false, true, true} },
3085  {"is_diff_out", std::vector<bool>{true}}};
3086  options["reverse_options"] = Dict{{"is_diff_in",
3087  std::vector<bool>{false, true, false, true}},
3088  {"is_diff_out", std::vector<bool>{false, true}}};
3089  options["jacobian_options"] = Dict{{"is_diff_in", std::vector<bool>{false, true, true}},
3090  {"is_diff_out", std::vector<bool>{true}}};
3091  } else {
3092  casadi_error("stop_diff: order must be 1 or 2, got " + str(order) + ".");
3093  }
3094 
3095  Function FS("FS", {x, y}, {expr}, {"x", "y"}, {"z"}, options);
3096  return FS(std::vector<MX>{x, y})[0];
3097  }
3098 
3099  std::vector<MX> MX::difference(const std::vector<MX>& a, const std::vector<MX>& b) {
3100  // Create a set of MXNodes from b
3101  std::set<MXNode*> bs;
3102  for (const auto& e : b) {
3103  if (!e.is_null()) bs.insert(e.get());
3104  }
3105  std::vector<MX> ret;
3106  for (auto&& e : a) {
3107  // If the element is not in the set, add it to the return vector
3108  if (bs.find(e.get())==bs.end()) {
3109  ret.push_back(e);
3110  }
3111  }
3112  return ret;
3113  }
3114 
3115  MX interpn_G(casadi_int i, // Dimension to interpolate along
3116  const MX& v, // Coefficients
3117  const std::vector<MX>& xis, // Normalised coordinates
3118  const std::vector<MX>& L, const std::vector<MX>& Lp, // Lower indices
3119  const std::vector<casadi_int>& strides,
3120  const Slice& I,
3121  const MX& offset=0 // Offset into coefficients vector
3122  ) {
3123  if (i==0) {
3124  MX ret;
3125  v.get_nz(ret, false, offset, I);
3126  return ret;
3127  } else {
3128  casadi_int j = xis.size()-i;
3129  MX offsetL, offsetR;
3130  if (strides[j]==1) {
3131  offsetL = offset+L[j];
3132  offsetR = offset+Lp[j];
3133  } else {
3134  offsetL = offset+L[j]*strides[j];
3135  offsetR = offsetL+strides[j];
3136  }
3137  MX vl = interpn_G(i-1, v, xis, L, Lp, strides, I, offsetL);
3138  MX vu = interpn_G(i-1, v, xis, L, Lp, strides, I, offsetR);
3139 
3140  // Perform interpolation between vl and vu
3141  return vl + xis[j]*(vu-vl);
3142  }
3143  }
3144 
3145  MX MX::interpn_linear(const std::vector<MX>& x, const MX& v, const std::vector<MX>& xq,
3146  const Dict& opts) {
3147 
3148  casadi_int n_dim = x.size();
3149  std::vector<std::string> lookup_mode(n_dim, "auto");
3150  for (auto&& op : opts) {
3151  if (op.first=="lookup_mode") {
3152  lookup_mode = op.second;
3153  } else {
3154  casadi_error("Unknown option '" + op.first + "'.");
3155  }
3156  }
3157 
3158  casadi_assert_dev(xq.size()==n_dim);
3159  casadi_assert_dev(v.is_vector());
3160 
3161  // Extract grid dimensions
3162  std::vector<casadi_int> x_dims;
3163  for (auto e : x) x_dims.push_back(e.numel());
3164 
3165  // Determine multipicity of output
3166  casadi_int n_out = v.numel()/product(x_dims);
3167  casadi_assert(n_out*product(x_dims)==v.numel(),
3168  "Dimension mismatch: coefficients (" + str(v.numel()) + ") should be "
3169  "an integer multiple of product-of-dimensions (" + str(product(x_dims)) + ").");
3170 
3171  // Dimension check xq
3172  casadi_int nq = xq[0].numel();
3173  for (auto e : xq) {
3174  casadi_assert_dev(e.is_vector() && e.numel()==nq);
3175  }
3176 
3177  // Compute stride vector
3178  std::vector<casadi_int> strides;
3179  strides.push_back(n_out);
3180  for (auto d : x_dims) strides.push_back(strides.back()*d);
3181 
3182  // Pre-compute lower index and normalized coordinate
3183  // (Allows for more sub-expression sharing)
3184  std::vector<MX> xis, Ls, Lps;
3185  for (casadi_int i=0;i<n_dim;++i) {
3186  MX L = low(x[i], xq[i], {{"lookup_mode", lookup_mode[i]}});
3187  MX Lp = L+1;
3188  MX xl, xu;
3189  x[i].get_nz(xl, false, L);
3190  x[i].get_nz(xu, false, Lp);
3191  xis.push_back((xq[i]-xl)/(xu-xl));
3192  Ls.push_back(L);
3193  Lps.push_back(Lp);
3194  }
3195 
3196  Slice I(0, n_out);
3197 
3198  return interpn_G(n_dim, v, xis, Ls, Lps, strides, I);
3199  }
3200 
3201  std::vector<MX> MX::get_input(const Function& f) {
3202  return f.mx_in();
3203  }
3204 
3205  std::vector<MX> MX::get_free(const Function& f) {
3206  return f.free_mx();
3207  }
3208 
3209  MX MX::_bilin(const MX& A, const MX& x, const MX& y) {
3210  return A->get_bilin(x, y);
3211  }
3212 
3213  MX MX::_rank1(const MX& A, const MX& alpha, const MX& x, const MX& y) {
3214  return A->get_rank1(alpha, x, y);
3215  }
3216 
3217  MX MX::_logsumexp(const MX& x) {
3218  return x->get_logsumexp();
3219  }
3220 
3221 
3222  void MX::eval_mx(const std::vector<MX>& arg, std::vector<MX>& res,
3223  const std::vector<bool>& unique) const {
3224  try {
3225  res.resize((*this)->nout());
3226  (*this)->eval_mx(arg, res, unique);
3227  } catch (std::exception& e) {
3228  CASADI_THROW_ERROR_OBJ("eval_mx", e.what());
3229  }
3230  }
3231 
3232  void MX::ad_forward(const std::vector<std::vector<MX> >& fseed,
3233  std::vector<std::vector<MX> >& fsens) const {
3234  try {
3235  (*this)->ad_forward(fseed, fsens);
3236  } catch (std::exception& e) {
3237  CASADI_THROW_ERROR_OBJ("ad_forward", e.what());
3238  }
3239  }
3240 
3241  void MX::ad_reverse(const std::vector<std::vector<MX> >& aseed,
3242  std::vector<std::vector<MX> >& asens) const {
3243  try {
3244  (*this)->ad_reverse(aseed, asens);
3245  } catch (std::exception& e) {
3246  CASADI_THROW_ERROR_OBJ("ad_reverse", e.what());
3247  }
3248  }
3249 
3250 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
3251  std::mutex MX::mutex_temp;
3252 #endif //CASADI_WITH_THREADSAFE_SYMBOLICS
3253 
3254 #undef CASADI_THROW_ERROR
3255 } // namespace casadi
static MX create(const MX &x, const MX &coeffs, const std::vector< std::vector< double > > &knots, const std::vector< casadi_int > &degree, casadi_int m, const Dict &opts)
Definition: bspline.cpp:310
static MX create(const MX &x, const std::vector< std::vector< double > > &knots, const std::vector< double > &coeffs, const std::vector< casadi_int > &degree, casadi_int m, const Dict &opts)
Definition: bspline.cpp:273
static DM dual(const std::vector< double > &x, const std::vector< std::vector< double > > &knots, const std::vector< casadi_int > &degree, const Dict &opts)
Definition: bspline.cpp:487
static MX create_call(const Function &fcn, const std::vector< MX > &arg)
Create function call node.
Casadi exception class.
Definition: exception.hpp:77
static ConstantMX * create(const Sparsity &sp, casadi_int val)
Helper class for Serialization.
Dump.
Definition: dump.hpp:39
Internal class for Function.
virtual void call_forward(const std::vector< MX > &arg, const std::vector< MX > &res, const std::vector< std::vector< MX > > &fseed, std::vector< std::vector< MX > > &fsens, bool always_inline, bool never_inline) const
Forward mode AD, virtual functions overloaded in derived classes.
virtual void call_reverse(const std::vector< MX > &arg, const std::vector< MX > &res, const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens, bool always_inline, bool never_inline) const
Reverse mode, virtual functions overloaded in derived classes.
Function object.
Definition: function.hpp:60
static Function if_else(const std::string &name, const Function &f_true, const Function &f_false, const Dict &opts=Dict())
Constructor (if-else)
Definition: function.cpp:962
size_t sz_res() const
Get required length of res field.
Definition: function.cpp:1237
static Function conditional(const std::string &name, const std::vector< Function > &f, const Function &f_def, const Dict &opts=Dict())
Constuct a switch function.
Definition: function.cpp:917
const MX mx_in(casadi_int ind) const
Get symbolic primitives equivalent to the input expressions.
Definition: function.cpp:1781
FunctionInternal * get() const
Definition: function.cpp:505
Function mapaccum(const std::string &name, casadi_int N, const Dict &opts=Dict()) const
Create a mapaccumulated version of this function.
Definition: function.cpp:671
Function expand() const
Expand a function to SX.
Definition: function.cpp:312
std::vector< MX > free_mx() const
Get all the free variables of the function.
Definition: function.cpp:1878
casadi_int n_nodes() const
Number of nodes in the algorithm.
Definition: function.cpp:1962
size_t sz_iw() const
Get required length of iw field.
Definition: function.cpp:1239
size_t sz_w() const
Get required length of w field.
Definition: function.cpp:1241
size_t sz_arg() const
Get required length of arg field.
Definition: function.cpp:1235
Function transform(const Dict &opts=Dict()) const
Apply transformation passes.
Definition: function.cpp:359
void call(const std::vector< DM > &arg, std::vector< DM > &res, bool always_inline=false, bool never_inline=false) const
Evaluate the function symbolically or numerically.
Definition: function.cpp:509
void serialize(std::ostream &stream, const Dict &opts=Dict()) const
Serialize.
Definition: function.cpp:1477
Sparsity sparsity() const
Get the sparsity pattern.
casadi_int numel() const
Get the number of elements.
bool is_dense() const
Check if the matrix expression is dense.
bool is_column() const
Check if the matrix is a column vector (i.e. size2()==1)
bool is_empty(bool both=false) const
Check if the sparsity is empty, i.e. if one of the dimensions is zero.
std::pair< casadi_int, casadi_int > size() const
Get the shape.
bool is_vector() const
Check if the matrix is a row or column vector.
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 rows() const
Get the number of rows, Octave-style syntax.
const MX nz(const K &k) const
Get vector nonzero or slice of nonzeros.
bool is_tril() const
Check if the matrix is lower triangular.
bool is_row() const
Check if the matrix is a row vector (i.e. size1()==1)
bool is_triu() const
Check if the matrix is upper triangular.
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 MX ones(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries one.
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
const casadi_int * colind() const
Get the sparsity pattern. See the Sparsity class for details.
const casadi_int * row() const
Get the sparsity pattern. See the Sparsity class for details.
bool is_square() const
Check if the matrix expression is square.
static MatType 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.
SharedObjectInternal * get() const
Get a const pointer to the node.
SharedObjectInternal * operator->() const
Access a member function or object.
Linear solver.
Definition: linsol.hpp:55
double det(const DM &A) const
Matrix determinant.
Definition: linsol.cpp:195
DM solve(const DM &A, const DM &B, bool tr=false) const
Definition: linsol.cpp:73
Internal node class for MXFunction.
Definition: mx_function.hpp:67
std::vector< casadi_int > workloc_
Offsets for elements in the w_ vector.
Definition: mx_function.hpp:82
std::vector< AlgEl > algorithm_
All the runtime elements in the order of evaluation.
Definition: mx_function.hpp:77
Node class for MX objects.
Definition: mx_node.hpp:51
virtual MX get_nzref(const Sparsity &sp, const std::vector< casadi_int > &nz, bool unique=false) const
Get the nonzeros of matrix.
Definition: mx_node.cpp:660
virtual void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res, const std::vector< bool > &unique={}) const
Evaluate symbolically (MX)
Definition: mx_node.cpp:350
virtual MX get_logsumexp() const
Logsumexp.
Definition: mx_node.cpp:616
virtual bool has_output() const
Check if a multiple output node.
Definition: mx_node.hpp:325
virtual MX get_nzassign(const MX &y, const std::vector< casadi_int > &nz) const
Assign the nonzeros of a matrix to another matrix.
Definition: mx_node.cpp:691
virtual MX get_norm_2() const
Spectral norm.
Definition: mx_node.cpp:1122
virtual MX get_output(casadi_int oind) const
Get an output.
Definition: mx_node.cpp:444
virtual bool is_zero() const
Check if identically zero.
Definition: mx_node.hpp:71
virtual MX get_sparsity_cast(const Sparsity &sp) const
Sparsity cast.
Definition: mx_node.cpp:512
virtual MX get_mmax() const
Max.
Definition: mx_node.cpp:1139
static bool is_equal(const MXNode *x, const MXNode *y, casadi_int depth)
Check if two nodes are equivalent up to a given depth.
Definition: mx_node.cpp:1317
virtual MX get_unary(casadi_int op, bool unique=false) const
Get a unary operation.
Definition: mx_node.cpp:781
virtual MX get_einstein(const MX &A, const MX &B, const std::vector< casadi_int > &dim_c, const std::vector< casadi_int > &dim_a, const std::vector< casadi_int > &dim_b, const std::vector< casadi_int > &c, const std::vector< casadi_int > &a, const std::vector< casadi_int > &b) const
Einstein product and addition.
Definition: mx_node.cpp:585
virtual MX get_solve_triu(const MX &r, bool tr) const
Solve a system of linear equations, upper triangular A.
Definition: mx_node.cpp:620
MX get_find() const
Find.
Definition: mx_node.cpp:1046
virtual MX get_kron(const MX &b) const
Create a Kronecker-product node.
Definition: mx_node.cpp:1240
virtual MX join_primitives(std::vector< MX >::const_iterator &it) const
Join an expression along symbolic primitives.
Definition: mx_node.cpp:183
virtual MX get_dot(const MX &y) const
Inner product.
Definition: mx_node.cpp:1093
virtual MX get_repmat(casadi_int m, casadi_int n) const
Create a repeated matrix node.
Definition: mx_node.cpp:1222
virtual MX _get_binary(casadi_int op, const MX &y, bool scX, bool scY, bool unique_x=false, bool unique_y=false) const
Get a binary operation operation (matrix-matrix)
Definition: mx_node.cpp:852
virtual MX get_solve_tril(const MX &r, bool tr) const
Solve a system of linear equations, lower triangular A.
Definition: mx_node.cpp:628
static MXNode * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: mx_node.cpp:547
virtual casadi_int nout() const
Number of outputs.
Definition: mx_node.hpp:402
const MX & dep(casadi_int ind=0) const
dependencies - functions that have to be evaluated before this one
Definition: mx_node.hpp:392
std::vector< MX > dep_
dependencies - functions that have to be evaluated before this one
Definition: mx_node.hpp:824
MX get_binary(casadi_int op, const MX &y, bool unique_x=false, bool unique_y=false) const
Get a binary operation operation.
Definition: mx_node.cpp:797
MX get_dump(const std::string &base_filename, const Dict &opts) const
Dump.
Definition: mx_node.cpp:1022
virtual MX get_norm_1() const
1-norm
Definition: mx_node.cpp:1130
virtual MX get_nz_ref(const MX &nz) const
Get the nonzeros of matrix, parametrically.
Definition: mx_node.cpp:667
MX get_monitor(const std::string &comment) const
Monitor.
Definition: mx_node.cpp:1014
virtual MX get_reshape(const Sparsity &sp) const
Reshape.
Definition: mx_node.cpp:503
MX get_convexify(const Dict &opts) const
Convexify.
Definition: mx_node.cpp:1080
virtual MX get_project(const Sparsity &sp, bool unique=false) const
Create set sparse.
Definition: mx_node.cpp:759
virtual MX get_mac(const MX &y, const MX &z, const std::string &blas="reference") const
Matrix multiplication and addition.
Definition: mx_node.cpp:566
virtual MX get_transpose() const
Transpose.
Definition: mx_node.cpp:491
virtual MX get_norm_fro() const
Frobenius norm.
Definition: mx_node.cpp:1118
virtual std::vector< MX > get_diagsplit(const std::vector< casadi_int > &offset1, const std::vector< casadi_int > &offset2) const
Create a diagonal split node.
Definition: mx_node.cpp:1254
virtual std::vector< MX > get_horzsplit(const std::vector< casadi_int > &output_offset) const
Create a horizontal split node.
Definition: mx_node.cpp:1190
virtual MX get_vertcat(const std::vector< MX > &x) const
Create a vertical concatenation node (vectors only)
Definition: mx_node.cpp:1170
virtual MX get_repsum(casadi_int m, casadi_int n) const
Create a repeated sum node.
Definition: mx_node.cpp:1231
virtual MX get_mmin() const
Min.
Definition: mx_node.cpp:1134
virtual MX get_norm_inf() const
Infinity norm.
Definition: mx_node.cpp:1126
MX get_low(const MX &v, const Dict &options) const
Find.
Definition: mx_node.cpp:1056
virtual MX get_inv() const
Inverse.
Definition: mx_node.cpp:1088
virtual std::vector< MX > get_vertsplit(const std::vector< casadi_int > &output_offset) const
Create a vertical split node (vectors only)
Definition: mx_node.cpp:1270
virtual MX get_bilin(const MX &x, const MX &y) const
Bilinear form.
Definition: mx_node.cpp:608
virtual MX get_kron_contract(const MX &x, bool inner) const
Create a Kronecker-contraction node.
Definition: mx_node.cpp:1247
virtual std::string disp(const std::vector< std::string > &arg) const =0
Print expression.
virtual MX get_rank1(const MX &alpha, const MX &x, const MX &y) const
Bilinear form.
Definition: mx_node.cpp:612
virtual double to_double() const
Get the value (only for scalar constant nodes)
Definition: mx_node.cpp:479
MX - Matrix expression.
Definition: mx.hpp:92
static MX linspace(const MX &a, const MX &b, casadi_int nsteps)
Definition: mx.cpp:2103
void ad_reverse(const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens) const
Called from MXFunction.
Definition: mx.cpp:3241
void erase(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, bool ind1=false)
Erase a submatrix (leaving structural zeros in its place)
Definition: mx.cpp:616
static MX nullspace(const MX &A)
Definition: mx.cpp:2159
static MX create(MXNode *node)
Create from node.
Definition: mx.cpp:69
bool is_multiplication() const
Check if multiplication.
Definition: mx.cpp:827
static MX unary(casadi_int op, const MX &x, bool unique=false)
Create nodes by their ID.
Definition: mx.cpp:560
void reset_input() const
Reset the marker for an input expression.
Definition: mx.cpp:1022
static MX _rank1(const MX &A, const MX &alpha, const MX &x, const MX &y)
Definition: mx.cpp:3213
static MX kron(const MX &x, const MX &b)
Definition: mx.cpp:2077
bool is_minus_one() const
check if minus one (note that false negative answers are possible)
Definition: mx.cpp:1042
static MX mmax(const MX &x)
Definition: mx.cpp:875
bool is_valid_input() const
Check if matrix can be used to define function inputs.
Definition: mx.cpp:954
static MX cumsum(const MX &x, casadi_int axis=-1)
Definition: mx.cpp:698
static MX substitute(const MX &ex, const MX &v, const MX &vdef)
Definition: mx.cpp:1525
static MX lift(const MX &x, const MX &x_guess)
Definition: mx.cpp:763
bool is_eye() const
check if identity
Definition: mx.cpp:1026
bool is_value(double val) const
check if a certain value (note that false negative answers are possible)
Definition: mx.cpp:1050
static MX horzcat(const std::vector< MX > &x)
Definition: mx.cpp:1119
const Sparsity & sparsity() const
Get the sparsity pattern.
Definition: mx.cpp:612
static std::vector< MX > difference(const std::vector< MX > &a, const std::vector< MX > &b)
Definition: mx.cpp:3099
static void separate_linear(const MX &expr, const MX &sym_lin, const MX &sym_const, MX &expr_const, MX &expr_lin, MX &expr_nonlin)
Definition: mx.cpp:2936
MX operator-() const
Definition: mx.cpp:604
bool is_output() const
Check if evaluation output.
Definition: mx.cpp:811
casadi_int n_out() const
Number of outputs.
Definition: mx.cpp:898
static MX expm_const(const MX &A, const MX &t)
Definition: mx.cpp:2147
static MX norm_fro(const MX &x)
Definition: mx.cpp:1292
static MX einstein(const MX &A, const MX &B, const MX &C, const std::vector< casadi_int > &dim_a, const std::vector< casadi_int > &dim_b, const std::vector< casadi_int > &dim_c, const std::vector< casadi_int > &a, const std::vector< casadi_int > &b, const std::vector< casadi_int > &c)
Computes an einstein dense tensor contraction.
Definition: mx.cpp:682
casadi_int n_dep() const
Get the number of dependencies of a binary SXElem.
Definition: mx.cpp:787
casadi_int n_primitives() const
Get the number of primitives for MXFunction inputs/outputs.
Definition: mx.cpp:958
static MX norm_inf(const MX &x)
Definition: mx.cpp:1300
bool __nonzero__() const
Returns the truth value of an MX expression.
Definition: mx.cpp:145
bool is_half() const
check if 0.5 (note that false negative answers are possible)
Definition: mx.cpp:1046
static std::vector< MX > vertsplit(const MX &x, const std::vector< casadi_int > &offset)
Definition: mx.cpp:1240
bool is_call() const
Check if evaluation.
Definition: mx.cpp:803
std::string name() const
Get the name.
Definition: mx.cpp:791
bool has_output() const
Check if a multiple output node.
Definition: mx.cpp:815
bool is_integer() const
Check if integer.
Definition: mx.cpp:1078
static MX jacobian(const MX &f, const MX &x, const Dict &opts=Dict())
Definition: mx.cpp:1920
Matrix< casadi_int > mapping() const
Get an IM representation of a GetNonzeros or SetNonzeros node.
Definition: mx.cpp:886
static std::vector< MX > symvar(const MX &x)
Definition: mx.cpp:2041
static MX reshape(const MX &x, casadi_int nrow, casadi_int ncol)
Definition: mx.cpp:1343
static MX find(const MX &x)
Definition: mx.cpp:2216
static MX norm_2(const MX &x)
Definition: mx.cpp:1284
bool is_inf() const
check if inf (note that false negative answers are possible)
Definition: mx.cpp:1070
static bool simplify_const_folding(std::vector< MX > &arg, std::vector< MX > &res, const Dict &opts=Dict())
Definition: mx.cpp:2388
static MX stop_diff(const MX &expr, casadi_int order)
Definition: mx.cpp:3027
bool is_constant() const
Check if constant.
Definition: mx.cpp:799
static MX eye(casadi_int n)
Identity matrix.
Definition: mx.cpp:600
static MX mac(const MX &x, const MX &y, const MX &z, const std::string &blas="reference")
Definition: mx.cpp:712
static MX sum1(const MX &x)
Definition: mx.cpp:1485
static casadi_int get_max_depth()
Get the depth to which equalities are being checked for simplifications.
Definition: mx.cpp:942
MXNode * get() const
Get a const pointer to the node.
Definition: mx.cpp:564
static void shared(std::vector< MX > &ex, std::vector< MX > &v, std::vector< MX > &vdef, const std::string &v_prefix, const std::string &v_suffix)
Definition: mx.cpp:1913
static bool contains_any(const std::vector< MX > &v, const std::vector< MX > &n)
Definition: mx.cpp:2198
static MX inf(const Sparsity &sp)
create a matrix with all inf
Definition: mx.cpp:584
MX dump(const std::string &base_filename, const Dict &opts=Dict()) const
Dump an expression.
Definition: mx.cpp:754
void reset_dump_count()
Reset the dump counter.
Definition: mx.cpp:758
bool is_commutative() const
Check if commutative operation.
Definition: mx.cpp:879
static MX project(const MX &x, const Sparsity &sp, bool intersect=false)
Definition: mx.cpp:906
static MX pinv(const MX &A, const std::string &lsolver="qr", const Dict &dict=Dict())
Definition: mx.cpp:2139
~MX()
Destructor.
Definition: mx.cpp:58
std::vector< MX > split_primitives(const MX &x) const
Split up an expression along symbolic primitives.
Definition: mx.cpp:970
static MX matrix_expand(const MX &e, const std::vector< MX > &boundary, const Dict &options)
Definition: mx.cpp:2046
static MX norm_1(const MX &x)
Definition: mx.cpp:1296
static MX mrdivide(const MX &a, const MX &b)
Definition: mx.cpp:773
static MX inv_minor(const MX &A)
Definition: mx.cpp:2033
static bool is_equal(const MX &x, const MX &y, casadi_int depth=0)
Definition: mx.cpp:867
static bool contains_all(const std::vector< MX > &v, const std::vector< MX > &n)
Definition: mx.cpp:2184
static void extract(std::vector< MX > &ex, std::vector< MX > &v, std::vector< MX > &vdef, const Dict &opts=Dict())
Definition: mx.cpp:1740
bool has_duplicates() const
Detect duplicate symbolic expressions.
Definition: mx.cpp:1018
static MX blockcat(const std::vector< std::vector< MX > > &v)
Definition: mx.cpp:1263
static MX hessian(const MX &f, const MX &x, const Dict &opts=Dict())
Definition: mx.cpp:1932
static DM evalf(const MX &m)
Definition: mx.cpp:768
MX T() const
Transpose the matrix.
Definition: mx.cpp:1095
void set_temp(casadi_int t) const
Set the temporary variable.
Definition: mx.cpp:894
std::vector< MX > get_nonzeros() const
Get nonzeros as list of scalar MXes.
Definition: mx.cpp:630
static std::vector< MX > createMultipleOutput(MXNode *node)
Create from node (multiple-outputs)
Definition: mx.cpp:130
casadi_int get_temp() const
Definition: mx.cpp:890
static MX _bilin(const MX &A, const MX &x, const MX &y)
Definition: mx.cpp:3209
void ad_forward(const std::vector< std::vector< MX > > &fseed, std::vector< std::vector< MX > > &fsens) const
Called from MXFunction.
Definition: mx.cpp:3232
static std::vector< MX > cse(const std::vector< MX > &e)
Definition: mx.cpp:2642
static MX mmin(const MX &x)
Definition: mx.cpp:871
static MX solve(const MX &a, const MX &b)
Definition: mx.cpp:2115
static MX bspline(const MX &x, const DM &coeffs, const std::vector< std::vector< double > > &knots, const std::vector< casadi_int > &degree, casadi_int m, const Dict &opts=Dict())
Definition: mx.cpp:2224
static bool simplify_ref_count(std::vector< MX > &arg, std::vector< MX > &res, const Dict &opts=Dict())
Definition: mx.cpp:2518
static MX simplify(const MX &x)
Definition: mx.cpp:1311
static std::vector< bool > which_depends(const MX &expr, const MX &var, casadi_int order=1, bool tr=false)
Definition: mx.cpp:2012
static void substitute_inplace(const std::vector< MX > &v, std::vector< MX > &vdef, std::vector< MX > &ex, bool reverse)
Definition: mx.cpp:1503
static std::vector< MX > diagsplit(const MX &x, const std::vector< casadi_int > &offset1, const std::vector< casadi_int > &offset2)
Definition: mx.cpp:1223
static MX repmat(const MX &x, casadi_int n, casadi_int m=1)
Definition: mx.cpp:2085
Function which_function() const
Get function - only valid when is_call() is true.
Definition: mx.cpp:807
static MX sparsity_cast(const MX &x, const Sparsity &sp)
Definition: mx.cpp:1361
static MX diag(const MX &x)
Definition: mx.cpp:1464
static void extract_parametric(const MX &expr, const MX &par, MX &expr_ret, std::vector< MX > &symbols, std::vector< MX > &parametric, const Dict &opts)
Definition: mx.cpp:2810
static MX det(const MX &x)
Definition: mx.cpp:2020
static MX inv_node(const MX &A)
Definition: mx.cpp:2029
bool is_op(casadi_int op) const
Is it a certain operation.
Definition: mx.cpp:823
bool is_minus_inf() const
check if -inf (note that false negative answers are possible)
Definition: mx.cpp:1074
bool is_norm() const
Check if norm.
Definition: mx.cpp:831
std::vector< MX > primitives() const
Get primitives.
Definition: mx.cpp:962
static casadi_int n_nodes(const MX &x)
Definition: mx.cpp:1475
void set_nz(const MX &m, bool ind1, const Slice &kk)
Definition: mx.cpp:463
static MX polyval(const MX &p, const MX &x)
Definition: mx.cpp:1489
MX()
Default constructor.
Definition: mx.cpp:61
static MX graph_substitute(const MX &x, const std::vector< MX > &v, const std::vector< MX > &vdef)
Definition: mx.cpp:1551
bool is_regular() const
Checks if expression does not contain NaN or Inf.
Definition: mx.cpp:1062
static MX kron_contract(const MX &m, const MX &x, bool inner)
Definition: mx.cpp:2081
casadi_int which_output() const
Get the index of evaluation output - only valid when is_output() is true.
Definition: mx.cpp:819
static MX repsum(const MX &x, casadi_int n, casadi_int m=1)
Definition: mx.cpp:2099
MX nzref(const Sparsity &sp, const std::vector< casadi_int > &nz) const
Low-level access to get_nzref.
Definition: mx.cpp:149
void serialize(SerializingStream &s) const
Serialize an object.
Definition: mx.cpp:859
static MX densify(const MX &x, const MX &val=0)
Definition: mx.cpp:923
static std::vector< MX > get_free(const Function &f)
Get free variables.
Definition: mx.cpp:3205
static bool depends_on(const MX &x, const MX &arg)
Definition: mx.cpp:2165
MX inv() const
Element-wise inverse.
Definition: mx.cpp:1087
static MX mtimes(const MX &x, const MX &y, const std::string &blas="reference")
Definition: mx.cpp:672
static MX deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: mx.cpp:863
static void set_max_depth(casadi_int eq_depth=1)
Set or reset the depth to which equalities are being checked for simplifications.
Definition: mx.cpp:938
static MX mldivide(const MX &a, const MX &b)
Definition: mx.cpp:778
static Sparsity jacobian_sparsity(const MX &f, const MX &x)
Definition: mx.cpp:2016
static MX expm(const MX &A)
Definition: mx.cpp:2154
MX attachAssert(const MX &y, const std::string &fail_message="") const
returns itself, but with an assertion attached
Definition: mx.cpp:743
static MX nan(const Sparsity &sp)
create a matrix with all nan
Definition: mx.cpp:596
Dict info() const
Definition: mx.cpp:855
static MX _sym(const std::string &name, const Sparsity &sp)
Definition: mx.cpp:946
void set(const MX &m, bool ind1, const Slice &rr)
Definition: mx.cpp:315
static DM bspline_dual(const std::vector< double > &x, const std::vector< std::vector< double > > &knots, const std::vector< casadi_int > &degree, const Dict &opts=Dict())
Definition: mx.cpp:2249
static MX trace(const MX &x)
Definition: mx.cpp:1455
bool is_one() const
check if one (note that false negative answers are possible)
Definition: mx.cpp:1038
static MX dot(const MX &x, const MX &y)
Definition: mx.cpp:735
static MX interpn_linear(const std::vector< MX > &x, const MX &v, const std::vector< MX > &xq, const Dict &opts=Dict())
Low-level access to inlined linear interpolation.
Definition: mx.cpp:3145
static MX vertcat(const std::vector< MX > &x)
Definition: mx.cpp:1165
static MX convexify(const MX &H, const Dict &opts=Dict())
Definition: mx.cpp:2256
static MX _logsumexp(const MX &x)
Definition: mx.cpp:3217
static MX if_else(const MX &cond, const MX &if_true, const MX &if_false, bool short_circuit=false)
Definition: mx.cpp:1373
MX join_primitives(const std::vector< MX > &v) const
Join an expression along symbolic primitives.
Definition: mx.cpp:994
MX dep(casadi_int ch=0) const
Get the nth dependency as MX.
Definition: mx.cpp:783
MX monitor(const std::string &comment) const
Monitor an expression.
Definition: mx.cpp:750
static std::vector< MX > horzsplit(const MX &x, const std::vector< casadi_int > &offset)
Definition: mx.cpp:1206
static MX conditional(const MX &ind, const std::vector< MX > &x, const MX &x_default, bool short_circuit=false)
Definition: mx.cpp:1395
static MX binary(casadi_int op, const MX &x, const MX &y, bool unique_x=false, bool unique_y=false)
Create nodes by their ID.
Definition: mx.cpp:533
bool is_binary() const
Is binary operation.
Definition: mx.cpp:843
static std::vector< MX > get_input(const Function &f)
Get function inputs.
Definition: mx.cpp:3201
bool is_unary() const
Is unary operation.
Definition: mx.cpp:847
bool is_zero() const
check if zero (note that false negative answers are possible)
Definition: mx.cpp:1030
bool is_transpose() const
Is the expression a transpose?
Definition: mx.cpp:1058
MXNode * operator->()
Access a member of the node.
Definition: mx.cpp:568
static bool test_cast(const SharedObjectInternal *ptr)
Check if a particular cast is allowed.
Definition: mx.cpp:1099
void get_nz(MX &m, bool ind1, const Slice &kk) const
Definition: mx.cpp:405
bool is_doubled() const
Check if the node is the sum of two equal expressions.
Definition: mx.cpp:1082
static MX transform(const MX &x, const Dict &opts=Dict())
Definition: mx.cpp:1315
static std::string print_operator(const MX &x, const std::vector< std::string > &args)
Definition: mx.cpp:1499
static std::vector< std::vector< MX > > reverse(const std::vector< MX > &ex, const std::vector< MX > &arg, const std::vector< std::vector< MX > > &v, const Dict &opts=Dict())
Definition: mx.cpp:1980
bool is_symbolic() const
Check if symbolic.
Definition: mx.cpp:795
void enlarge(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, bool ind1=false)
Enlarge matrix.
Definition: mx.cpp:662
MX printme(const MX &b) const
Definition: mx.cpp:739
static bool simplify_combine_terms(std::vector< MX > &arg, std::vector< MX > &res, const Dict &opts=Dict())
Definition: mx.cpp:1304
MX get_output(casadi_int oind) const
Get an output.
Definition: mx.cpp:902
static MX diagcat(const std::vector< MX > &x)
Definition: mx.cpp:1155
static MX low(const MX &v, const MX &p, const Dict &options=Dict())
Definition: mx.cpp:2220
casadi_int op() const
Get operation type.
Definition: mx.cpp:851
static std::vector< std::vector< MX > > forward(const std::vector< MX > &ex, const std::vector< MX > &arg, const std::vector< std::vector< MX > > &v, const Dict &opts=Dict())
Definition: mx.cpp:1949
static MX sum2(const MX &x)
Definition: mx.cpp:1481
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res, const std::vector< bool > &unique=std::vector< bool >()) const
Evaluate the MX node with new symbolic dependencies.
Definition: mx.cpp:3222
bool is_nonnegative() const
Check if a value is always nonnegative (false negatives are allowed)
Definition: mx.cpp:1054
static MX unite(const MX &A, const MX &B)
Definition: mx.cpp:1429
std::vector< Scalar > & nonzeros()
Matrix< Scalar > T() const
Transpose the matrix.
const Sparsity & sparsity() const
Const access the sparsity - reference to data member.
bool is_regular() const
Checks if expression does not contain NaN or Inf.
static Matrix< Scalar > nullspace(const Matrix< Scalar > &x)
Scalar * ptr()
static Matrix< double > eye(casadi_int n)
create an n-by-n identity matrix
Matrix and vector norms.
Definition: norm.hpp:40
Helper class for Serialization.
void tocache(const K &key, const T &value)
const std::unordered_map< K, T > & cache_map() const
bool incache(const K &key, T &value) const
Class representing a Slice.
Definition: slice.hpp:48
Slice apply(casadi_int len, bool ind1=false) const
Apply concrete length.
Definition: slice.cpp:66
std::vector< casadi_int > all() const
Get a vector of indices.
Definition: slice.cpp:90
static MatType veccat(const std::vector< MatType > &x)
static std::vector< casadi_int > offset(const std::vector< MatType > &v, bool vert=true)
General sparsity class.
Definition: sparsity.hpp:106
casadi_int get_nz(casadi_int rr, casadi_int cc) const
Get the index of an existing non-zero element.
Definition: sparsity.cpp:246
Sparsity intersect(const Sparsity &y, std::vector< unsigned char > &mapping) const
Intersection of two sparsity patterns.
Definition: sparsity.cpp:417
std::vector< casadi_int > erase(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, bool ind1=false)
Erase rows and/or columns of a matrix.
Definition: sparsity.cpp:339
Sparsity sub(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, std::vector< casadi_int > &mapping, bool ind1=false) const
Get a submatrix.
Definition: sparsity.cpp:334
void enlarge(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, bool ind1=false)
Enlarge matrix.
Definition: sparsity.cpp:545
std::vector< casadi_int > find(bool ind1=SWIG_IND1) const
Get the location of all non-zero elements as they would appear in a Dense matrix.
Definition: sparsity.cpp:737
bool is_orthonormal(bool allow_empty=false) const
Are both rows and columns orthonormal ?
Definition: sparsity.cpp:305
std::string dim(bool with_nz=false) const
Get the dimension as a string.
Definition: sparsity.cpp:588
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern *.
Definition: sparsity.cpp:1028
Sparsity T() const
Transpose the matrix.
Definition: sparsity.cpp:394
Sparsity unite(const Sparsity &y, std::vector< unsigned char > &mapping) const
Union of two sparsity patterns.
Definition: sparsity.cpp:409
bool is_reshape(const Sparsity &y) const
Check if the sparsity is a reshape of another.
Definition: sparsity.cpp:802
Sparsity get_diag(std::vector< casadi_int > &mapping) const
Definition: sparsity.cpp:612
std::vector< casadi_int > get_col() const
Get the column for each non-zero entry.
Definition: sparsity.cpp:368
static Sparsity reshape(const Sparsity &x, casadi_int nrow, casadi_int ncol)
Enlarge matrix.
Definition: sparsity.cpp:260
casadi_int nnz() const
Get the number of (structural) non-zeros.
Definition: sparsity.cpp:148
std::pair< casadi_int, casadi_int > size() const
Get the shape.
Definition: sparsity.cpp:152
std::size_t hash() const
Enlarge matrix.
Definition: sparsity.cpp:811
std::vector< casadi_int > get_row() const
Get the row for each non-zero entry.
Definition: sparsity.cpp:372
static Sparsity triplet(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, std::vector< casadi_int > &mapping, bool invert_mapping)
Create a sparsity pattern given the nonzeros in sparse triplet form *.
Definition: sparsity.cpp:1143
static Sparsity mtimes(const Sparsity &x, const Sparsity &y, const std::string &blas="reference")
Enlarge matrix.
Definition: sparsity.cpp:430
Represents a symbolic MX.
Definition: symbolic_mx.hpp:42
static ZeroByZero * getInstance()
Get a pointer to the singleton.
Function expmsol(const std::string &name, const std::string &solver, const Sparsity &A, const Dict &opts)
Definition: expm.cpp:44
static MX if_else_zero(const MX &x, const MX &y)
Conditional assignment: (x,y) -> x ? y : 0.
static MX floor(const MX &x)
Round down to nearest integer: x -> floor(x)
friend MX gradient(const MX &ex, const MX &arg, const Dict &opts=Dict())
Calculate the gradient of an expression.
static MX ne(const MX &x, const MX &y)
Logical not equal to: (x,y) -> x != y.
The casadi namespace.
Definition: archiver.cpp:28
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
T product(const std::vector< T > &values)
product
Dict combine(const Dict &first, const Dict &second, bool recurse)
Combine two dicts. First has priority.
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)
CASADI_EXPORT std::string replace(const std::string &s, const std::string &p, const std::string &r)
Replace all occurences of p with r in s.
void sort(const std::vector< T > &values, std::vector< T > &sorted_values, std::vector< casadi_int > &indices, bool invert_indices=false)
Sort the data in a vector.
std::vector< MX > trim_empty(const std::vector< MX > &x, bool both=false)
Definition: mx.cpp:1111
bool is_monotone(const std::vector< T > &v)
Check if the vector is monotone.
MX register_symbol(const MX &node, std::map< MXNode *, MX > &symbol_map, std::vector< MX > &symbol_v, std::vector< MX > &parametric_v, bool extract_trivial, casadi_int v_offset, const std::string &v_prefix, const std::string &v_suffix)
Definition: mx.cpp:2780
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void hash_combine(std::size_t &seed, T v)
Generate a hash value incrementally (function taken from boost)
bool any(const std::vector< bool > &v)
Check if any arguments are true.
Definition: casadi_misc.cpp:88
MX get_const(const Sparsity &sp, const double *v, std::unordered_multimap< std::size_t, std::pair< MX, DM > > &cache)
Definition: mx.cpp:2360
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
MX interpn_G(casadi_int i, const MX &v, const std::vector< MX > &xis, const std::vector< MX > &L, const std::vector< MX > &Lp, const std::vector< casadi_int > &strides, const Slice &I, const MX &offset=0)
Definition: mx.cpp:3115
Matrix< double > DM
Definition: dm_fwd.hpp:33
std::vector< T > reverse(const std::vector< T > &v)
Reverse a list.
bool simplify_const_folding_order(std::vector< MX > &arg, std::vector< MX > &res, const Dict &opts)
Definition: mx.cpp:2261
Dict extract_from_dict(const Dict &d, const std::string &key, T &value)
bool has_empty(const std::vector< MX > &x, bool both=false)
Definition: mx.cpp:1104
Operation
Enum for quick access to any node.
Definition: calculus.hpp:60
@ OP_INV
Definition: calculus.hpp:73
@ OP_OUTPUT
Definition: calculus.hpp:82
@ OP_PRINTME
Definition: calculus.hpp:190
@ OP_CONST
Definition: calculus.hpp:79
@ OP_TWICE
Definition: calculus.hpp:67
@ OP_INPUT
Definition: calculus.hpp:82
@ OP_LIFT
Definition: calculus.hpp:191
@ OP_DUMP
Definition: calculus.hpp:212
@ OP_PARAMETER
Definition: calculus.hpp:85
@ OP_MTIMES
Definition: calculus.hpp:100
@ OP_CALL
Definition: calculus.hpp:88
@ OP_ADD
Definition: calculus.hpp:65
@ OP_TRANSPOSE
Definition: calculus.hpp:106
@ OP_NEG
Definition: calculus.hpp:66
@ OP_MUL
Definition: calculus.hpp:65
Easy access to all the functions for a particular type.
Definition: calculus.hpp:1135