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