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