matrix_impl.hpp
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 #ifndef CASADI_MATRIX_IMPL_HPP
26 #define CASADI_MATRIX_IMPL_HPP
27 
28 #include "dm.hpp"
29 #include "im.hpp"
30 #include "sx.hpp"
31 
32 #include "sx_node.hpp"
33 #include "linsol.hpp"
34 #include "expm.hpp"
35 #include "serializing_stream.hpp"
36 #include "blas_impl.hpp"
37 
38 namespace casadi {
39  template<typename Scalar>
40  void Matrix<Scalar>::set_precision(casadi_int precision) { stream_precision_ = precision; }
41 
42  template<typename Scalar>
43  void Matrix<Scalar>::set_width(casadi_int width) { stream_width_ = width; }
44 
45  template<typename Scalar>
46  void Matrix<Scalar>::set_scientific(bool scientific) { stream_scientific_ = scientific; }
47 
48  template<typename Scalar>
49  casadi_int Matrix<Scalar>::get_precision() { return stream_precision_; }
50 
51  template<typename Scalar>
52  casadi_int Matrix<Scalar>::get_width() { return stream_width_; }
53 
54  template<typename Scalar>
55  bool Matrix<Scalar>::get_scientific() { return stream_scientific_; }
56 
57  template<typename Scalar>
58  casadi_int Matrix<Scalar>::stream_precision_ = 6;
59  template<typename Scalar>
60  casadi_int Matrix<Scalar>::stream_width_ = 0;
61  template<typename Scalar>
63 
64  template<typename Scalar>
65  std::default_random_engine Matrix<Scalar>::rng_(
66  // Seed with current time
67  std::chrono::system_clock::now().time_since_epoch().count());
68 
69  template<typename Scalar>
70  void Matrix<Scalar>::rng(casadi_int seed) {
71  rng_.seed(seed);
72  }
73 
74  template<typename Scalar>
75  bool Matrix<Scalar>::has_nz(casadi_int rr, casadi_int cc) const {
76  return sparsity().has_nz(rr, cc);
77  }
78 
79  template<typename Scalar>
81  if (numel()!=1) {
82  casadi_error("Only scalar Matrix could have a truth value, but you "
83  "provided a shape" + dim());
84  }
85  return nonzeros().at(0)!=0;
86  }
87 
88  template<typename Scalar>
89  void Matrix<Scalar>::get(Matrix<Scalar>& m, bool ind1,
90  const Slice& rr, const Slice& cc) const {
91  // Both are scalar
92  if (rr.is_scalar(size1()) && cc.is_scalar(size2())) {
93  casadi_int k = sparsity().get_nz(rr.scalar(size1()), cc.scalar(size2()));
94  if (k>=0) {
95  m = nonzeros().at(k);
96  } else {
97  m = Matrix<Scalar>(1, 1);
98  }
99  return;
100  }
101 
102  // Fall back on IM-IM
103  get(m, ind1, rr.all(size1(), ind1), cc.all(size2(), ind1));
104  }
105 
106  template<typename Scalar>
108  const Slice& rr, const Matrix<casadi_int>& cc) const {
109  // Fall back on IM-IM
110  get(m, ind1, rr.all(size1(), ind1), cc);
111  }
112 
113  template<typename Scalar>
115  const Matrix<casadi_int>& rr, const Slice& cc) const {
116  // Fall back on IM-IM
117  get(m, ind1, rr, cc.all(size2(), ind1));
118  }
119 
120  template<typename Scalar>
122  const Matrix<casadi_int>& rr, const Matrix<casadi_int>& cc) const {
123  // Scalar
124  if (rr.is_scalar(true) && cc.is_scalar(true)) {
125  return get(m, ind1, to_slice(rr, ind1), to_slice(cc, ind1));
126  }
127 
128  // Make sure dense vectors
129  casadi_assert(rr.is_dense() && rr.is_vector(),
130  "Marix::get: First index must be a dense vector");
131  casadi_assert(cc.is_dense() && cc.is_vector(),
132  "Marix::get: Second index must be a dense vector");
133 
134  // Get the sparsity pattern - does bounds checking
135  std::vector<casadi_int> mapping;
136  Sparsity sp = sparsity().sub(rr.nonzeros(), cc.nonzeros(), mapping, ind1);
137 
138  // Copy nonzeros
139  m = Matrix<Scalar>::zeros(sp);
140  for (casadi_int k=0; k<mapping.size(); ++k) m->at(k) = nonzeros().at(mapping[k]);
141  }
142 
143  template<typename Scalar>
144  void Matrix<Scalar>::get(Matrix<Scalar>& m, bool ind1, const Slice& rr) const {
145  // Scalar
146  if (rr.is_scalar(numel())) {
147  casadi_int r = rr.scalar(numel());
148  casadi_int k = sparsity().get_nz(r % size1(), r / size1());
149  if (k>=0) {
150  m = nonzeros().at(k);
151  } else {
152  m = Matrix<Scalar>(1, 1);
153  }
154  return;
155  }
156 
157  // Fall back on IM
158  get(m, ind1, rr.all(numel(), ind1));
159  }
160 
161  template<typename Scalar>
162  void Matrix<Scalar>::get(Matrix<Scalar>& m, bool ind1, const Matrix<casadi_int>& rr) const {
163  // Scalar
164  if (rr.is_scalar(true)) {
165  return get(m, ind1, to_slice(rr, ind1));
166  }
167 
168  // If the indexed matrix is dense, use nonzero indexing
169  if (is_dense()) {
170  return get_nz(m, ind1, rr);
171  }
172 
173  // Get the sparsity pattern - does bounds checking
174  std::vector<casadi_int> mapping;
175  Sparsity sp = sparsity().sub(rr.nonzeros(), rr.sparsity(), mapping, ind1);
176 
177  // If indexed matrix was a row/column vector, make sure that the result is too
178  bool tr = (is_column() && rr.is_row()) || (is_row() && rr.is_column());
179 
180  // Copy nonzeros
181  m = Matrix<Scalar>::zeros(tr ? sp.T() : sp);
182  for (casadi_int k=0; k<mapping.size(); ++k) m->at(k) = nonzeros().at(mapping[k]);
183  }
184 
185  template<typename Scalar>
186  void Matrix<Scalar>::get(Matrix<Scalar>& m, bool ind1, const Sparsity& sp) const {
187  casadi_assert(size()==sp.size(),
188  "Shape mismatch. This matrix has shape "
189  + str(size()) + ", but supplied sparsity index has shape "
190  + str(sp.size()) + ".");
191  m = project(*this, sp);
192  }
193 
194  template<typename Scalar>
195  void Matrix<Scalar>::set(const Matrix<Scalar>& m, bool ind1,
196  const Slice& rr, const Slice& cc) {
197  // Both are scalar
198  if (rr.is_scalar(size1()) && cc.is_scalar(size2()) && m.is_dense()) {
199  casadi_int oldsize = sparsity_.nnz();
200  casadi_int ind = sparsity_.add_nz(rr.scalar(size1()), cc.scalar(size2()));
201  if (oldsize == sparsity_.nnz()) {
202  nonzeros_.at(ind) = m.scalar();
203  } else {
204  nonzeros_.insert(nonzeros_.begin()+ind, m.scalar());
205  }
206  return;
207  }
208 
209  // Fall back on (IM, IM)
210  set(m, ind1, rr.all(size1(), ind1), cc.all(size2(), ind1));
211  }
212 
213  template<typename Scalar>
214  void Matrix<Scalar>::set(const Matrix<Scalar>& m, bool ind1,
215  const Slice& rr, const Matrix<casadi_int>& cc) {
216  // Fall back on (IM, IM)
217  set(m, ind1, rr.all(size1(), ind1), cc);
218  }
219 
220  template<typename Scalar>
221  void Matrix<Scalar>::set(const Matrix<Scalar>& m, bool ind1,
222  const Matrix<casadi_int>& rr, const Slice& cc) {
223  // Fall back on (IM, IM)
224  set(m, ind1, rr, cc.all(size2(), ind1));
225  }
226 
227  template<typename Scalar>
228  void Matrix<Scalar>::set(const Matrix<Scalar>& m, bool ind1,
229  const Matrix<casadi_int>& rr, const Matrix<casadi_int>& cc) {
230  // Scalar
231  if (rr.is_scalar(true) && cc.is_scalar(true) && m.is_dense()) {
232  return set(m, ind1, to_slice(rr, ind1), to_slice(cc, ind1));
233  }
234 
235  // Row vector rr (e.g. in MATLAB) is transposed to column vector
236  if (rr.size1()==1 && rr.size2()>1) {
237  return set(m, ind1, rr.T(), cc);
238  }
239 
240  // Row vector cc (e.g. in MATLAB) is transposed to column vector
241  if (cc.size1()==1 && cc.size2()>1) {
242  return set(m, ind1, rr, cc.T());
243  }
244 
245  // Make sure rr and cc are dense vectors
246  casadi_assert(rr.is_dense() && rr.is_column(),
247  "Matrix::set: First index not dense vector");
248  casadi_assert(cc.is_dense() && cc.is_column(),
249  "Matrix::set: Second index not dense vector");
250 
251  // Assert dimensions of assigning matrix
252  if (rr.size1() != m.size1() || cc.size1() != m.size2()) {
253  if (m.is_scalar()) {
254  // m scalar means "set all"
255  return set(repmat(m, rr.size1(), cc.size1()), ind1, rr, cc);
256  } else if (rr.size1() == m.size2() && cc.size1() == m.size1()
257  && std::min(m.size1(), m.size2()) == 1) {
258  // m is transposed if necessary
259  return set(m.T(), ind1, rr, cc);
260  } else {
261  // Error otherwise
262  casadi_error("Dimension mismatch. lhs is " + str(rr.size1()) + "-by-"
263  + str(cc.size1()) + ", while rhs is " + str(m.size()));
264  }
265  }
266 
267  // Dimensions
268  casadi_int sz1 = size1(), sz2 = size2();
269 
270  // Report out-of-bounds
271  casadi_assert_in_range(rr.nonzeros(), -sz1+ind1, sz1+ind1);
272  casadi_assert_in_range(cc.nonzeros(), -sz2+ind1, sz2+ind1);
273 
274  // If we are assigning with something sparse, first remove existing entries
275  if (!m.is_dense()) {
276  erase(rr.nonzeros(), cc.nonzeros(), ind1);
277  }
278 
279  // Collect all assignments
280  IM el = IM::zeros(m.sparsity());
281  for (casadi_int j=0; j<el.size2(); ++j) { // Loop over columns of m
282  casadi_int this_j = cc->at(j) - ind1; // Corresponding column in this
283  if (this_j<0) this_j += sz2;
284  for (casadi_int k=el.colind(j); k<el.colind(j+1); ++k) { // Loop over rows of m
285  casadi_int i = m.row(k);
286  casadi_int this_i = rr->at(i) - ind1; // Corresponding row in this
287  if (this_i<0) this_i += sz1;
288  el->at(k) = this_i + this_j*sz1;
289  }
290  }
291  return set(m, false, el);
292  }
293 
294  template<typename Scalar>
295  void Matrix<Scalar>::set(const Matrix<Scalar>& m, bool ind1, const Slice& rr) {
296  // Scalar
297  if (rr.is_scalar(numel()) && m.is_dense()) {
298  casadi_int r = rr.scalar(numel());
299  casadi_int oldsize = sparsity_.nnz();
300  casadi_int ind = sparsity_.add_nz(r % size1(), r / size1());
301  if (oldsize == sparsity_.nnz()) {
302  nonzeros_.at(ind) = m.scalar();
303  } else {
304  nonzeros_.insert(nonzeros_.begin()+ind, m.scalar());
305  }
306  return;
307  }
308 
309  // Fall back on IM
310  set(m, ind1, rr.all(numel(), ind1));
311  }
312 
313  template<typename Scalar>
314  void Matrix<Scalar>::set(const Matrix<Scalar>& m, bool ind1, const Matrix<casadi_int>& rr) {
315  // Scalar
316  if (rr.is_scalar(true) && m.is_dense()) {
317  return set(m, ind1, to_slice(rr, ind1));
318  }
319 
320  // Assert dimensions of assigning matrix
321  if (rr.sparsity() != m.sparsity()) {
322  if (rr.size() == m.size()) {
323  // Remove submatrix to be replaced
324  erase(rr.nonzeros(), ind1);
325 
326  // Find the intersection between rr's and m's sparsity patterns
327  Sparsity sp = rr.sparsity() * m.sparsity();
328 
329  // Project both matrices to this sparsity
330  return set(project(m, sp), ind1, Matrix<casadi_int>::project(rr, sp));
331  } else if (m.is_scalar()) {
332  // m scalar means "set all"
333  if (m.is_dense()) {
334  return set(Matrix<Scalar>(rr.sparsity(), m), ind1, rr);
335  } else {
336  return set(Matrix<Scalar>(rr.size()), ind1, rr);
337  }
338  } else if (rr.size1() == m.size2() && rr.size2() == m.size1()
339  && std::min(m.size1(), m.size2()) == 1) {
340  // m is transposed if necessary
341  return set(m.T(), ind1, rr);
342  } else {
343  // Error otherwise
344  casadi_error("Dimension mismatch. lhs is " + str(rr.size())
345  + ", while rhs is " + str(m.size()));
346  }
347  }
348 
349  // Dimensions of this
350  casadi_int sz1 = size1(), sz2 = size2(), sz = nnz(), nel = numel(), rrsz = rr.nnz();
351 
352  // Quick return if nothing to set
353  if (rrsz==0) return;
354 
355  // Check bounds
356  casadi_assert_in_range(rr.nonzeros(), -nel+ind1, nel+ind1);
357 
358  // Dense mode
359  if (is_dense() && m.is_dense()) {
360  return set_nz(m, ind1, rr);
361  }
362 
363  // Construct new sparsity pattern
364  std::vector<casadi_int> new_row =
365  sparsity().get_row(), new_col=sparsity().get_col(), nz(rr.nonzeros());
366  new_row.reserve(sz+rrsz);
367  new_col.reserve(sz+rrsz);
368  nz.reserve(rrsz);
369  for (std::vector<casadi_int>::iterator i=nz.begin(); i!=nz.end(); ++i) {
370  if (ind1) (*i)--;
371  if (*i<0) *i += nel;
372  new_row.push_back(*i % sz1);
373  new_col.push_back(*i / sz1);
374  }
375  Sparsity sp = Sparsity::triplet(sz1, sz2, new_row, new_col);
376 
377  // If needed, update pattern
378  if (sp != sparsity()) *this = project(*this, sp);
379 
380  // Find the nonzeros corresponding to rr
381  sparsity().get_nz(nz);
382 
383  // Carry out the assignments
384  for (casadi_int i=0; i<nz.size(); ++i) {
385  nonzeros().at(nz[i]) = m->at(i);
386  }
387  }
388 
389  template<typename Scalar>
390  void Matrix<Scalar>::set(const Matrix<Scalar>& m, bool ind1, const Sparsity& sp) {
391  casadi_assert(size()==sp.size(),
392  "set(Sparsity sp): shape mismatch. This matrix has shape "
393  + str(size()) + ", but supplied sparsity index has shape "
394  + str(sp.size()) + ".");
395  std::vector<casadi_int> ii = sp.find();
396  if (m.is_scalar()) {
397  (*this)(ii) = densify(m);
398  } else {
399  (*this)(ii) = densify(m(ii));
400  }
401  }
402 
403  template<typename Scalar>
404  void Matrix<Scalar>::get_nz(Matrix<Scalar>& m, bool ind1, const Slice& kk) const {
405  // Scalar
406  if (kk.is_scalar(nnz())) {
407  m = nonzeros().at(kk.scalar(nnz()));
408  return;
409  }
410 
411  // Fall back on IM
412  get_nz(m, ind1, kk.all(nnz(), ind1));
413  }
414 
415  template<typename Scalar>
416  void Matrix<Scalar>::get_nz(Matrix<Scalar>& m, bool ind1, const Matrix<casadi_int>& kk) const {
417  // Scalar
418  if (kk.is_scalar(true)) {
419  return get_nz(m, ind1, to_slice(kk, ind1));
420  }
421 
422  // Get nonzeros of kk
423  const std::vector<casadi_int>& k = kk.nonzeros();
424  casadi_int sz = nnz();
425 
426  // Check bounds
427  casadi_assert_in_range(k, -sz+ind1, sz+ind1);
428 
429  // If indexed matrix was a row/column vector, make sure that the result is too
430  bool tr = (is_column() && kk.is_row()) || (is_row() && kk.is_column());
431 
432  // Copy nonzeros
433  m = zeros(tr ? kk.sparsity().T() : kk.sparsity());
434  for (casadi_int el=0; el<k.size(); ++el) {
435  casadi_assert(!(ind1 && k[el]<=0), "Matlab is 1-based, but requested index "
436  + str(k[el]) + ". Note that negative slices are"
437  " disabled in the Matlab interface. "
438  "Possibly you may want to use 'end'.");
439  casadi_int k_el = k[el]-ind1;
440  m->at(el) = nonzeros().at(k_el>=0 ? k_el : k_el+sz);
441  }
442  }
443 
444  template<typename Scalar>
445  void Matrix<Scalar>::set_nz(const Matrix<Scalar>& m, bool ind1, const Slice& kk) {
446  // Scalar
447  if (kk.is_scalar(nnz())) {
448  nonzeros().at(kk.scalar(nnz())) = m.scalar();
449  return;
450  }
451 
452  // Fallback on IM
453  set_nz(m, ind1, kk.all(nnz(), ind1));
454  }
455 
456  template<typename Scalar>
457  void Matrix<Scalar>::set_nz(const Matrix<Scalar>& m, bool ind1, const Matrix<casadi_int>& kk) {
458  // Scalar
459  if (kk.is_scalar(true)) {
460  return set_nz(m, ind1, to_slice(kk, ind1));
461  }
462 
463  // Assert dimensions of assigning matrix
464  if (kk.sparsity() != m.sparsity()) {
465  if (m.is_scalar()) {
466  // m scalar means "set all"
467  if (!m.is_dense()) return; // Nothing to set
468  return set_nz(Matrix<Scalar>(kk.sparsity(), m), ind1, kk);
469  } else if (kk.size() == m.size()) {
470  // Project sparsity if needed
471  return set_nz(project(m, kk.sparsity()), ind1, kk);
472  } else if (kk.size1() == m.size2() && kk.size2() == m.size1()
473  && std::min(m.size1(), m.size2()) == 1) {
474  // m is transposed if necessary
475  return set_nz(m.T(), ind1, kk);
476  } else {
477  // Error otherwise
478  casadi_error("Dimension mismatch. lhs is " + str(kk.size())
479  + ", while rhs is " + str(m.size()));
480  }
481  }
482 
483  // Get nonzeros
484  const std::vector<casadi_int>& k = kk.nonzeros();
485  casadi_int sz = nnz();
486 
487  // Check bounds
488  casadi_assert_in_range(k, -sz+ind1, sz+ind1);
489 
490  // Set nonzeros, ignoring negative indices
491  for (casadi_int el=0; el<k.size(); ++el) {
492  casadi_assert(!(ind1 && k[el]<=0),
493  "Matlab is 1-based, but requested index " + str(k[el])
494  + ". Note that negative slices are disabled in the Matlab interface. "
495  "Possibly you may want to use 'end'.");
496  casadi_int k_el = k[el]-ind1;
497  nonzeros().at(k_el>=0 ? k_el : k_el+sz) = m->at(el);
498  }
499  }
500 
501  template<typename Scalar>
503  return densify(x, 0);
504  }
505 
506  template<typename Scalar>
507  Matrix<Scalar> Matrix<Scalar>::densify(const Matrix<Scalar>& x,
508  const Matrix<Scalar>& val) {
509  // Check argument
510  casadi_assert_dev(val.is_scalar());
511 
512  // Quick return if possible
513  if (x.is_dense()) return x;
514 
515  // Get sparsity pattern
516  casadi_int nrow = x.size1();
517  casadi_int ncol = x.size2();
518  const casadi_int* colind = x.colind();
519  const casadi_int* row = x.row();
520  auto it = x.nonzeros().cbegin();
521 
522  // New data vector
523  std::vector<Scalar> d(nrow*ncol, val.scalar());
524 
525  // Copy nonzeros
526  for (casadi_int cc=0; cc<ncol; ++cc) {
527  for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
528  d[cc*nrow + row[el]] = *it++;
529  }
530  }
531 
532  // Construct return matrix
533  return Matrix<Scalar>(Sparsity::dense(x.size()), d);
534  }
535 
536  template<typename Scalar>
537  Matrix<Scalar> Matrix<Scalar>::cumsum(const Matrix<Scalar> &x, casadi_int axis) {
538  if (axis==-1) axis = x.is_row();
539  Matrix<Scalar> ret = x;
540  if (axis==0) {
541  for (casadi_int i=1;i<x.size1();++i)
542  ret(i, Slice()) += ret(i-1, Slice());
543  } else {
544  for (casadi_int i=1;i<x.size2();++i)
545  ret(Slice(), i) += ret(Slice(), i-1);
546  }
547  return ret;
548  }
549 
550  template<typename Scalar>
551  Matrix<Scalar> Matrix<Scalar>::einstein(
552  const Matrix<Scalar>& A, const Matrix<Scalar>& B, const Matrix<Scalar>& C,
553  const std::vector<casadi_int>& dim_a, const std::vector<casadi_int>& dim_b,
554  const std::vector<casadi_int>& dim_c,
555  const std::vector<casadi_int>& a, const std::vector<casadi_int>& b,
556  const std::vector<casadi_int>& c) {
557  std::vector<casadi_int> iter_dims;
558  std::vector<casadi_int> strides_a;
559  std::vector<casadi_int> strides_b;
560  std::vector<casadi_int> strides_c;
561  casadi_int n_iter = einstein_process(A, B, C, dim_a, dim_b, dim_c, a, b, c,
562  iter_dims, strides_a, strides_b, strides_c);
563 
564  const std::vector<Scalar>& Av = A.nonzeros();
565  const std::vector<Scalar>& Bv = B.nonzeros();
566 
567  Matrix<Scalar> ret = C;
568  std::vector<Scalar>& Cv = ret.nonzeros();
569 
570  einstein_eval(n_iter, iter_dims, strides_a, strides_b, strides_c,
571  get_ptr(Av), get_ptr(Bv), get_ptr(Cv));
572  return ret;
573  }
574 
575  template<typename Scalar>
577  const std::vector<casadi_int>& dim_a, const std::vector<casadi_int>& dim_b,
578  const std::vector<casadi_int>& dim_c,
579  const std::vector<casadi_int>& a, const std::vector<casadi_int>& b,
580  const std::vector<casadi_int>& c) {
581  return Matrix<Scalar>::einstein(A, B, Matrix<Scalar>::zeros(product(dim_c), 1),
582  dim_a, dim_b, dim_c, a, b, c);
583  }
584 
585  template<typename Scalar>
586  Matrix<Scalar>::Matrix() : sparsity_(Sparsity(0, 0)) {
587  }
588 
589  template<typename Scalar>
590  Matrix<Scalar>::Matrix(const Matrix<Scalar>& m) : sparsity_(m.sparsity_), nonzeros_(m.nonzeros_) {
591  }
592 
593  template<typename Scalar>
594  Matrix<Scalar>::Matrix(const std::vector<Scalar>& x) :
595  sparsity_(Sparsity::dense(x.size(), 1)), nonzeros_(x) {
596  }
597 
598  template<typename Scalar>
600  sparsity_ = m.sparsity_;
601  nonzeros_ = m.nonzeros_;
602  return *this;
603  }
604 
605  template<typename Scalar>
606  std::vector<Scalar>* Matrix<Scalar>::operator->() {
607  return &nonzeros_;
608  }
609 
610  template<typename Scalar>
611  const std::vector<Scalar>* Matrix<Scalar>::operator->() const {
612  return &nonzeros_;
613  }
614 
615  template<typename Scalar>
616  std::string Matrix<Scalar>::type_name() { return matrixName<Scalar>(); }
617 
618  template<typename Scalar>
619  void Matrix<Scalar>::print_scalar(std::ostream &stream) const {
620  casadi_assert(numel()==1, "Not a scalar");
621 
622  StreamStateGuard backup(stream);
623 
624  stream.precision(stream_precision_);
625  stream.width(stream_width_);
626  if (stream_scientific_) {
627  stream.setf(std::ios::scientific);
628  } else {
629  stream.unsetf(std::ios::scientific);
630  }
631 
632  if (nnz()==0) {
633  stream << "00";
634  } else {
635  stream << scalar();
636  }
637  stream << std::flush;
638  }
639 
640  template<typename Scalar>
641  void Matrix<Scalar>::print_vector(std::ostream &stream, bool truncate) const {
642  print_vector(stream, sparsity(), ptr(), truncate);
643  }
644 
645  template<typename Scalar>
646  void Matrix<Scalar>::print_vector(std::ostream &stream, const Sparsity& sp,
647  const Scalar* nonzeros, bool truncate) {
648  casadi_assert(sp.is_column(), "Not a vector");
649 
650  // Get components
651  std::vector<std::string> nz, inter;
652  print_split(sp.nnz(), nonzeros, nz, inter);
653 
654  // Print intermediate expressions
655  for (casadi_int i=0; i<inter.size(); ++i)
656  stream << "@" << (i+1) << "=" << inter[i] << ", ";
657  inter.clear();
658 
659  // Access data structures
660  const casadi_int* row = sp.row();
661  casadi_int nnz = sp.nnz();
662  casadi_int size1 = sp.size1();
663 
664  // No need to truncate if less than 1000 entries
665  const casadi_int max_numel = 1000;
666  if (truncate && size1<=max_numel) truncate=false;
667 
668  // Nonzero
669  casadi_int el=0;
670 
671  // Loop over rows
672  stream << "[";
673  for (casadi_int rr=0; rr<size1; ++rr) {
674  // String representation
675  std::string s = el<nnz && rr==row[el] ? nz.at(el++) : "00";
676 
677  // Truncate?
678  if (truncate && rr>=3 && rr<size1-3) {
679  // Do not print
680  if (rr==3) stream << ", ...";
681  } else {
682  // Print
683  if (rr!=0) stream << ", ";
684  stream << s;
685  }
686  }
687  stream << "]" << std::flush;
688  }
689 
690  template<typename Scalar>
691  void Matrix<Scalar>::print_dense(std::ostream &stream, bool truncate) const {
692  print_dense(stream, sparsity(), ptr(), truncate);
693  }
694 
695  template<typename Scalar>
696  void Matrix<Scalar>::print_sparse(std::ostream &stream, bool truncate) const {
697  print_sparse(stream, sparsity(), ptr(), truncate);
698  }
699 
700  template<typename Scalar>
701  void Matrix<Scalar>::print_split(std::vector<std::string>& nz,
702  std::vector<std::string>& inter) const {
703 
704  print_split(nnz(), ptr(), nz, inter);
705  }
706 
707  template<typename Scalar>
708  void Matrix<Scalar>::print_default(std::ostream &stream, const Sparsity& sp,
709  const Scalar* nonzeros, bool truncate) {
710  if (sp.is_empty()) {
711  stream << sp.size1() << "x" << sp.size2();
712  } else if (sp.numel()==1) {
713  if (sp.nnz()==0) {
714  stream << "00";
715  } else {
716  print_scalar(stream, *nonzeros);
717  }
718  } else if (sp.is_column()) {
719  print_vector(stream, sp, nonzeros, truncate);
720  } else if (std::max(sp.size1(), sp.size2())<=10 ||
721  static_cast<double>(sp.nnz())/static_cast<double>(sp.numel())>=0.5) {
722  // if "small" or "dense"
723  print_dense(stream, sp, nonzeros, truncate);
724  } else {
725  print_sparse(stream, sp, nonzeros, truncate);
726  }
727  }
728 
729  template<typename Scalar>
730  void Matrix<Scalar>::print_canonical(std::ostream &stream, const Sparsity& sp,
731  const Scalar* nonzeros, bool truncate) {
732  casadi_error("'print_canonical' not defined for " + type_name());
733  }
734 
735  template<typename Scalar>
736  void Matrix<Scalar>::print_scalar(std::ostream &stream, const Scalar& e) {
737  std::streamsize precision = stream.precision();
738  std::streamsize width = stream.width();
739  std::ios_base::fmtflags flags = stream.flags();
740 
741  stream.precision(stream_precision_);
742  stream.width(stream_width_);
743  if (stream_scientific_) {
744  stream.setf(std::ios::scientific);
745  } else {
746  stream.unsetf(std::ios::scientific);
747  }
748  stream << e;
749  stream << std::flush;
750 
751  stream.precision(precision);
752  stream.width(width);
753  stream.flags(flags);
754  }
755 
756  template<typename Scalar>
757  void Matrix<Scalar>::print_split(casadi_int nnz, const Scalar* nonzeros,
758  std::vector<std::string>& nz,
759  std::vector<std::string>& inter) {
760  nz.resize(nnz);
761  inter.resize(0);
762 
763  // Temporary
764  std::stringstream ss;
765  ss.precision(stream_precision_);
766  ss.width(stream_width_);
767  if (stream_scientific_) {
768  ss.setf(std::ios::scientific);
769  } else {
770  ss.unsetf(std::ios::scientific);
771  }
772 
773  // Print nonzeros
774  for (casadi_int i=0; i<nz.size(); ++i) {
775  ss.str(std::string());
776  ss << nonzeros[i];
777  nz[i] = ss.str();
778  }
779  }
780 
781  template<typename Scalar>
782  void Matrix<Scalar>::print_sparse(std::ostream &stream, const Sparsity& sp,
783  const Scalar* nonzeros, bool truncate) {
784  // Access data structures
785  casadi_int size1 = sp.size1();
786  casadi_int size2 = sp.size2();
787  const casadi_int* colind = sp.colind();
788  const casadi_int* row = sp.row();
789  casadi_int nnz = sp.nnz();
790 
791  // Quick return if all zero sparse
792  if (nnz==0) {
793  stream << "all zero sparse: " << size1 << "-by-" << size2 << std::flush;
794  return;
795  }
796 
797  // Print header
798  stream << "sparse: " << size1 << "-by-" << size2 << ", " << nnz << " nnz";
799 
800  // Get components
801  std::vector<std::string> nz, inter;
802  print_split(nnz, nonzeros, nz, inter);
803 
804  // Print intermediate expressions
805  for (casadi_int i=0; i<inter.size(); ++i)
806  stream << std::endl << " @" << (i+1) << "=" << inter[i] << ",";
807  inter.clear();
808 
809  // No need to truncate if less than 1000 nonzeros
810  const casadi_int max_nnz = 1000;
811  if (truncate && nnz<=max_nnz) truncate=false;
812 
813  // Print nonzeros
814  for (casadi_int cc=0; cc<size2; ++cc) {
815  for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
816  if (truncate && el>=3 && el<nnz-3) {
817  if (el==3) stream << std::endl << " ...";
818  } else {
819  stream << std::endl << " (" << row[el] << ", " << cc << ") -> " << nz.at(el);
820  InterruptHandler::check();
821  }
822  }
823  }
824  stream << std::flush;
825  }
826 
827  template<typename Scalar>
828  void Matrix<Scalar>::print_dense(std::ostream &stream, const Sparsity& sp,
829  const Scalar* nonzeros, bool truncate) {
830  // Get components
831  std::vector<std::string> nz, inter;
832  print_split(sp.nnz(), nonzeros, nz, inter);
833 
834  // Print intermediate expressions
835  for (casadi_int i=0; i<inter.size(); ++i)
836  stream << "@" << (i+1) << "=" << inter[i] << ", ";
837  inter.clear();
838 
839  // Access data structures
840  casadi_int size1 = sp.size1();
841  casadi_int size2 = sp.size2();
842  const casadi_int* colind = sp.colind();
843  const casadi_int* row = sp.row();
844 
845  // No need to truncate if less than 1000 entries
846  const casadi_int max_numel = 1000;
847  if (truncate && size1*size2<=max_numel) truncate=false;
848 
849  // Truncate rows and/or columns
850  bool truncate_rows = truncate && size1>=7;
851  bool truncate_columns = truncate && size2>=7;
852 
853  // Index counter for each column
854  std::vector<casadi_int> ind(colind, colind+size2+1);
855 
856  // Print as a single line?
857  bool oneliner=size1<=1;
858 
859  // Loop over rows
860  for (casadi_int rr=0; rr<size1; ++rr) {
861  // Print row?
862  bool print_row = !(truncate_rows && rr>=3 && rr<size1-3);
863 
864  // Beginning of row
865  if (rr==0) {
866  if (!oneliner) stream << std::endl;
867  stream << "[[";
868  } else if (print_row) {
869  stream << " [";
870  }
871 
872  // Loop over columns
873  for (casadi_int cc=0; cc<size2; ++cc) {
874  // String representation of element
875  std::string s = ind[cc]<colind[cc+1] && row[ind[cc]]==rr
876  ? nz.at(ind[cc]++) : "00";
877 
878  // Skip whole row?
879  if (!print_row) continue;
880 
881  // Print column?
882  bool print_column = !(truncate_columns && cc>=3 && cc<size2-3);
883 
884  // Print element
885  if (print_column) {
886  if (cc!=0) stream << ", ";
887  stream << s;
888  } else if (cc==3) {
889  stream << ", ...";
890  }
891  }
892 
893  // End of row
894  if (rr<size1-1) {
895  if (print_row) {
896  stream << "], ";
897  if (!oneliner) stream << std::endl;
898  } else if (rr==3) {
899  stream << " ...," << std::endl;
900  }
901  } else {
902  stream << "]]";
903  }
904  }
905  stream << std::flush;
906  }
907 
908  template<typename Scalar>
909  void Matrix<Scalar>::to_file(const std::string& filename, const std::string& format) const {
910  to_file(filename, sparsity(), ptr(), format);
911  }
912 
913  template<typename Scalar>
914  void Matrix<Scalar>::disp(std::ostream& stream, bool more) const {
915  print_default(stream, sparsity(), ptr());
916  }
917 
918  template<typename Scalar>
919  std::string Matrix<Scalar>::get_str(bool more) const {
920  std::stringstream ss;
921  disp(ss, more);
922  return ss.str();
923  }
924 
925  template<typename Scalar>
926  void Matrix<Scalar>::reserve(casadi_int nnz) {
927  reserve(nnz, size2());
928  }
929 
930  template<typename Scalar>
931  void Matrix<Scalar>::reserve(casadi_int nnz, casadi_int ncol) {
932  nonzeros().reserve(nnz);
933  }
934 
935  template<typename Scalar>
936  void Matrix<Scalar>::resize(casadi_int nrow, casadi_int ncol) {
937  sparsity_.resize(nrow, ncol);
938  }
939 
940  template<typename Scalar>
941  void Matrix<Scalar>::clear() {
942  sparsity_ = Sparsity(0, 0);
943  nonzeros().clear();
944  }
945 
946  template<typename Scalar>
948  sparsity_(
949  Sparsity::dense(1, 1)),
950  nonzeros_(std::vector<Scalar>(1, static_cast<Scalar>(val))) {
951  }
952 
953  template<typename Scalar>
954  Matrix<Scalar>::Matrix(const std::vector< std::vector<double> >& d) {
955  // Get dimensions
956  casadi_int nrow=d.size();
957  casadi_int ncol=d.empty() ? 1 : d.front().size();
958 
959  // Assert consistency
960  for (casadi_int rr=0; rr<nrow; ++rr) {
961  casadi_assert(ncol==d[rr].size(),
962  "Shape mismatch.\n"
963  "Attempting to construct a matrix from a nested list.\n"
964  "I got convinced that the desired size is (" + str(nrow) + " x " + str(ncol)
965  + " ), but now I encounter a vector of size (" + str(d[rr].size()) + " )");
966  }
967 
968  // Form matrix
969  sparsity_ = Sparsity::dense(nrow, ncol);
970  nonzeros().resize(nrow*ncol);
971  typename std::vector<Scalar>::iterator it=nonzeros_.begin();
972  for (casadi_int cc=0; cc<ncol; ++cc) {
973  for (casadi_int rr=0; rr<nrow; ++rr) {
974  *it++ = static_cast<Scalar>(d[rr][cc]);
975  }
976  }
977  }
978 
979  template<typename Scalar>
980  Matrix<Scalar>::Matrix(const Sparsity& sp) : sparsity_(sp), nonzeros_(sp.nnz(), 1) {
981  }
982 
983  template<typename Scalar>
984  Matrix<Scalar>::Matrix(casadi_int nrow, casadi_int ncol) : sparsity_(nrow, ncol) {
985  }
986 
987  template<typename Scalar>
988  Matrix<Scalar>::Matrix(const std::pair<casadi_int, casadi_int>& rc) : sparsity_(rc) {
989  }
990 
991  template<typename Scalar>
992  Matrix<Scalar>::Matrix(const Sparsity& sp, const Scalar& val, bool dummy) :
993  sparsity_(sp), nonzeros_(sp.nnz(), val) {
994  }
995 
996  template<typename Scalar>
997  Matrix<Scalar>::Matrix(const Sparsity& sp, const std::vector<Scalar>& d, bool dummy) :
998  sparsity_(sp), nonzeros_(d) {
999  casadi_assert(sp.nnz()==d.size(), "Size mismatch.\n"
1000  "You supplied a sparsity of " + sp.dim()
1001  + ", but the supplied vector is of length " + str(d.size()));
1002  }
1003 
1004  template<typename Scalar>
1005  Matrix<Scalar>::Matrix(const Sparsity& sp, const Matrix<Scalar>& d) {
1006  if (d.is_scalar()) {
1007  *this = Matrix<Scalar>(sp, d.scalar(), false);
1008  } else if (sp.nnz()==0) {
1009  casadi_assert(d.nnz()==0,
1010  "You passed nonzeros (" + d.dim(true) +
1011  ") to the constructor of a fully sparse matrix (" + sp.dim(true) + ").");
1012  *this = Matrix<Scalar>(sp);
1013  } else if (d.is_column() || d.size1()==1) {
1014  casadi_assert_dev(sp.nnz()==d.numel());
1015  if (d.is_dense()) {
1016  *this = Matrix<Scalar>(sp, d.nonzeros(), false);
1017  } else {
1018  *this = Matrix<Scalar>(sp, densify(d).nonzeros(), false);
1019  }
1020  } else {
1021  casadi_error("Matrix(Sparsity, Matrix): Only allowed for scalars and vectors");
1022  }
1023  }
1024 
1025  template<typename Scalar>
1026  Matrix<Scalar> Matrix<Scalar>::unary(casadi_int op, const Matrix<Scalar> &x) {
1027  // Return value
1028  Matrix<Scalar> ret = Matrix<Scalar>::zeros(x.sparsity());
1029 
1030  // Nonzeros
1031  std::vector<Scalar>& ret_data = ret.nonzeros();
1032  const std::vector<Scalar>& x_data = x.nonzeros();
1033 
1034  // Do the operation on all non-zero elements
1035  for (casadi_int el=0; el<x.nnz(); ++el) {
1036  casadi_math<Scalar>::fun(op, x_data[el], x_data[el], ret_data[el]);
1037  }
1038 
1039  // Check the value of the structural zero-entries, if there are any
1040  if (!x.is_dense() && !operation_checker<F0XChecker>(op)) {
1041  // Get the value for the structural zeros
1042  Scalar fcn_0;
1043  casadi_math<Scalar>::fun(op, 0, 0, fcn_0);
1044  if (!casadi_limits<Scalar>::is_zero(fcn_0)) { // Remove this if?
1045  ret = densify(ret, fcn_0);
1046  }
1047  }
1048 
1049  return ret;
1050  }
1051 
1052  template<typename Scalar>
1053  Matrix<Scalar> Matrix<Scalar>::operator-() const {
1054  return unary(OP_NEG, *this);
1055  }
1056 
1057  template<typename Scalar>
1058  Matrix<Scalar> Matrix<Scalar>::operator+() const {
1059  return *this;
1060  }
1061 
1062  template<typename Scalar>
1063  Matrix<Scalar> Matrix<Scalar>::mrdivide(const Matrix<Scalar>& b,
1064  const Matrix<Scalar>& a) {
1065  if (a.is_scalar() || b.is_scalar()) return b/a;
1066  return solve(a.T(), b.T()).T();
1067  }
1068 
1069  template<typename Scalar>
1070  Matrix<Scalar> Matrix<Scalar>::mldivide(const Matrix<Scalar>& a,
1071  const Matrix<Scalar>& b) {
1072  if (a.is_scalar() || b.is_scalar()) return b/a;
1073  return solve(a, b);
1074  }
1075 
1076  template<typename Scalar>
1077  Matrix<Scalar> Matrix<Scalar>::printme(const Matrix<Scalar>& y) const {
1078  return binary(OP_PRINTME, *this, y);
1079  }
1080 
1081  template<typename Scalar>
1082  void Matrix<Scalar>::erase(const std::vector<casadi_int>& rr,
1083  const std::vector<casadi_int>& cc, bool ind1) {
1084  // Erase from sparsity pattern
1085  std::vector<casadi_int> mapping = sparsity_.erase(rr, cc, ind1);
1086 
1087  // Update non-zero entries
1088  for (casadi_int k=0; k<mapping.size(); ++k)
1089  nonzeros()[k] = nonzeros()[mapping[k]];
1090 
1091  // Truncate nonzero vector
1092  nonzeros().resize(mapping.size());
1093  }
1094 
1095  template<typename Scalar>
1096  void Matrix<Scalar>::erase(const std::vector<casadi_int>& rr, bool ind1) {
1097  // Erase from sparsity pattern
1098  std::vector<casadi_int> mapping = sparsity_.erase(rr, ind1);
1099 
1100  // Update non-zero entries
1101  for (casadi_int k=0; k<mapping.size(); ++k)
1102  nonzeros()[k] = nonzeros()[mapping[k]];
1103 
1104  // Truncate nonzero vector
1105  nonzeros().resize(mapping.size());
1106  }
1107 
1108  template<typename Scalar>
1109  void Matrix<Scalar>::remove(const std::vector<casadi_int>& rr,
1110  const std::vector<casadi_int>& cc) {
1111  casadi_assert_bounded(rr, size1());
1112  casadi_assert_bounded(cc, size2());
1113 
1114  // Remove by performing a complementary slice
1115  std::vector<casadi_int> rrc = complement(rr, size1());
1116  std::vector<casadi_int> ccc = complement(cc, size2());
1117 
1118  Matrix<Scalar> ret = (*this)(rrc, ccc); // NOLINT(cppcoreguidelines-slicing)
1119 
1120  operator=(ret);
1121 
1122  }
1123 
1124  template<typename Scalar>
1125  void Matrix<Scalar>::enlarge(casadi_int nrow, casadi_int ncol, const std::vector<casadi_int>& rr,
1126  const std::vector<casadi_int>& cc, bool ind1) {
1127  sparsity_.enlarge(nrow, ncol, rr, cc, ind1);
1128  }
1129 
1130  template<typename Scalar>
1131  const Sparsity& Matrix<Scalar>::sparsity() const {
1132  return sparsity_;
1133  }
1134 
1135  template<typename Scalar>
1136  std::vector<Scalar>& Matrix<Scalar>::nonzeros() {
1137  return nonzeros_;
1138  }
1139 
1140  template<typename Scalar>
1141  const std::vector<Scalar>& Matrix<Scalar>::nonzeros() const {
1142  return nonzeros_;
1143  }
1144 
1145  template<typename Scalar>
1146  Scalar* Matrix<Scalar>::ptr() {
1147  return nonzeros_.empty() ? nullptr : &nonzeros_.front();
1148  }
1149 
1150  template<typename Scalar>
1151  const Scalar* Matrix<Scalar>::ptr() const {
1152  return nonzeros_.empty() ? nullptr : &nonzeros_.front();
1153  }
1154 
1155  template<typename Scalar>
1156  Sparsity Matrix<Scalar>::get_sparsity() const {
1157  return sparsity();
1158  }
1159 
1160  template<typename Scalar>
1161  Matrix<Scalar> Matrix<Scalar>::mtimes(const Matrix<Scalar> &x, const Matrix<Scalar> &y,
1162  const std::string& blas) {
1163  if (x.is_scalar() || y.is_scalar()) {
1164  // Use element-wise multiplication if at least one factor scalar
1165  return x*y;
1166  } else {
1167  Matrix<Scalar> z = Matrix<Scalar>::zeros(Sparsity::mtimes(x.sparsity(), y.sparsity()));
1168  return mac(x, y, z, blas);
1169  }
1170  }
1171 
1172  // Dense fast-path dispatch for Matrix<T>::mac.
1173  template<typename T>
1174  inline void mtimes_dense_dispatch(const std::string& /*blas*/,
1175  const T* A, casadi_int m, casadi_int k,
1176  const T* B, casadi_int n, T* C) {
1177  casadi_mtimes_dense(A, m, k, B, n, C, 0);
1178  }
1179  template<>
1180  void CASADI_EXPORT mtimes_dense_dispatch<double>(const std::string& blas,
1181  const double* A,
1182  casadi_int m, casadi_int k,
1183  const double* B, casadi_int n,
1184  double* C);
1185 
1186  template<typename Scalar>
1187  Matrix<Scalar> Matrix<Scalar>::mac(const Matrix<Scalar> &x,
1188  const Matrix<Scalar> &y,
1189  const Matrix<Scalar> &z,
1190  const std::string& blas) {
1191  if (x.is_scalar() || y.is_scalar()) {
1192  // Use element-wise multiplication if at least one factor scalar
1193  return z + x*y;
1194  }
1195 
1196  // Check matching dimensions
1197  casadi_assert(x.size2()==y.size1(),
1198  "Matrix product with incompatible dimensions. Lhs is "
1199  + x.dim() + " and rhs is " + y.dim() + ".");
1200 
1201  casadi_assert(y.size2()==z.size2(),
1202  "Matrix addition with incompatible dimensions. Lhs is "
1203  + mtimes(x, y).dim() + " and rhs is " + z.dim() + ".");
1204 
1205  casadi_assert(x.size1()==z.size1(),
1206  "Matrix addition with incompatible dimensions. Lhs is "
1207  + mtimes(x, y).dim() + " and rhs is " + z.dim() + ".");
1208 
1209  // Check if we can simplify the product
1210  if (x.is_eye()) return y + z;
1211  if (y.is_eye()) return x + z;
1212  if (x.is_zero() || y.is_zero()) return z;
1213 
1214  Matrix<Scalar> ret = z;
1215  if (x.is_dense() && y.is_dense() && z.is_dense()) {
1216  // Dense fast path: routes through Blas for double, plain
1217  // casadi_mtimes_dense for symbolic types.
1218  mtimes_dense_dispatch<Scalar>(blas,
1219  x.ptr(), x.size1(), x.size2(),
1220  y.ptr(), y.size2(), ret.ptr());
1221  return ret;
1222  }
1223  // Sparse fallback (Blas plugin choice ignored -- no plugin handles CCS).
1224  std::vector<Scalar> work(x.size1());
1225  casadi_mtimes(x.ptr(), x.sparsity(), y.ptr(), y.sparsity(),
1226  ret.ptr(), ret.sparsity(), get_ptr(work), false);
1227  return ret;
1228  }
1229 
1230  template<typename Scalar>
1231  Matrix<Scalar> Matrix<Scalar>::
1232  _bilin(const Matrix<Scalar>& A, const Matrix<Scalar>& x,
1233  const Matrix<Scalar>& y) {
1234  return casadi_bilin(A.ptr(), A.sparsity(), x.ptr(), y.ptr());
1235  }
1236 
1237  template<typename Scalar>
1238  Matrix<Scalar> Matrix<Scalar>::
1239  _rank1(const Matrix<Scalar>& A, const Matrix<Scalar>& alpha,
1240  const Matrix<Scalar>& x, const Matrix<Scalar>& y) {
1241  Matrix<Scalar> ret = A;
1242  casadi_rank1(ret.ptr(), ret.sparsity(), *alpha.ptr(), x.ptr(), y.ptr());
1243  return ret;
1244  }
1245 
1246 
1247  template<typename Scalar>
1248  Matrix<Scalar> Matrix<Scalar>::
1249  _logsumexp(const Matrix<Scalar>& x) {
1250  Matrix<Scalar> mx = mmax(x);
1251  return mx+log(sum1(exp(x-mx)));
1252  }
1253 
1254  template<typename Scalar>
1255  Matrix<Scalar> Matrix<Scalar>::T() const {
1256  // quick return if empty or scalar
1257  if ((size1()==0 && size2()==0) || is_scalar()) return *this;
1258 
1259  // Create the new sparsity pattern and the mapping
1260  std::vector<casadi_int> mapping;
1261  Sparsity s = sparsity().transpose(mapping);
1262 
1263  // create the return matrix
1264  Matrix<Scalar> ret = zeros(s);
1265 
1266  // Copy the content
1267  for (casadi_int i=0; i<mapping.size(); ++i)
1268  ret->at(i) = nonzeros().at(mapping[i]);
1269 
1270  return ret;
1271  }
1272 
1273  template<typename Scalar>
1274  const Scalar Matrix<Scalar>::scalar() const {
1275  // Make sure that the matrix is 1-by-1
1276  casadi_assert(is_scalar(), "Can only convert 1-by-1 matrices to scalars");
1277 
1278  // return zero or the nonzero element
1279  if (nnz()==1)
1280  return nonzeros()[0];
1281  else
1282  return casadi_limits<Scalar>::zero;
1283  }
1284 
1285  template<typename Scalar>
1286  Matrix<Scalar> Matrix<Scalar>::binary(casadi_int op,
1287  const Matrix<Scalar> &x,
1288  const Matrix<Scalar> &y) {
1289  if (x.is_scalar()) {
1290  return scalar_matrix(op, x, y);
1291  } else if (y.is_scalar()) {
1292  return matrix_scalar(op, x, y);
1293  } else {
1294  return matrix_matrix(op, x, y);
1295  }
1296  }
1297 
1298  template<typename Scalar>
1299  std::vector< Matrix<Scalar> > Matrix<Scalar>::call(const Function& f,
1300  const std::vector< Matrix<Scalar> > &x) {
1301  // Flatten all inputs
1302  std::vector<Scalar> dep;
1303  for (auto & e : x) {
1304  dep.insert(dep.end(), e.nonzeros().begin(), e.nonzeros().end());
1305  }
1306 
1307  std::vector<Scalar> r = Matrix<Scalar>::call(f, dep);
1308 
1309  // Package rsults in 1-by-1 Matrix objects
1310  std::vector< Matrix<Scalar> > ret;
1311  ret.reserve(r.size());
1312  for (auto & e : r) {
1313  ret.push_back(e);
1314  }
1315 
1316  return ret;
1317  }
1318 
1319 
1320  template<typename Scalar>
1321  std::vector<Scalar> Matrix<Scalar>::call(const Function& f, const std::vector< Scalar > &x) {
1322  casadi_error("'call' not defined for " + type_name());
1323  }
1324 
1325  template<typename Scalar>
1326  Matrix<Scalar> Matrix<Scalar>::
1327  scalar_matrix(casadi_int op, const Matrix<Scalar> &x, const Matrix<Scalar> &y) {
1328  if ( (operation_checker<FX0Checker>(op) && y.nnz()==0) ||
1329  (operation_checker<F0XChecker>(op) && x.nnz()==0))
1330  return Matrix<Scalar>::zeros(Sparsity(y.size()));
1331 
1332  // Return value
1333  Matrix<Scalar> ret = Matrix<Scalar>::zeros(y.sparsity());
1334 
1335  // Nonzeros
1336  std::vector<Scalar>& ret_data = ret.nonzeros();
1337  const std::vector<Scalar>& x_data = x.nonzeros();
1338  const Scalar& x_val = x_data.empty() ? casadi_limits<Scalar>::zero : x->front();
1339  const std::vector<Scalar>& y_data = y.nonzeros();
1340 
1341  // Do the operation on all non-zero elements
1342  for (casadi_int el=0; el<y.nnz(); ++el) {
1343  casadi_math<Scalar>::fun(op, x_val, y_data[el], ret_data[el]);
1344  }
1345 
1346  // Check the value of the structural zero-entries, if there are any
1347  if (!y.is_dense() && !operation_checker<FX0Checker>(op)) {
1348  // Get the value for the structural zeros
1349  Scalar fcn_0;
1350  casadi_math<Scalar>::fun(op, x_val, casadi_limits<Scalar>::zero, fcn_0);
1351  if (!casadi_limits<Scalar>::is_zero(fcn_0)) { // Remove this if?
1352  ret = densify(ret, fcn_0);
1353  }
1354  }
1355 
1356  return ret;
1357  }
1358 
1359  template<typename Scalar>
1360  Matrix<Scalar> Matrix<Scalar>::
1361  matrix_scalar(casadi_int op, const Matrix<Scalar> &x, const Matrix<Scalar> &y) {
1362 
1363  if ( (operation_checker<FX0Checker>(op) && y.nnz()==0) ||
1364  (operation_checker<F0XChecker>(op) && x.nnz()==0))
1365  return Matrix<Scalar>::zeros(Sparsity(x.size()));
1366 
1367  // Return value
1368  Matrix<Scalar> ret = Matrix<Scalar>::zeros(x.sparsity());
1369 
1370  // Nonzeros
1371  std::vector<Scalar>& ret_data = ret.nonzeros();
1372  const std::vector<Scalar>& x_data = x.nonzeros();
1373  const std::vector<Scalar>& y_data = y.nonzeros();
1374  const Scalar& y_val = y_data.empty() ? casadi_limits<Scalar>::zero : y->front();
1375 
1376  // Do the operation on all non-zero elements
1377  for (casadi_int el=0; el<x.nnz(); ++el) {
1378  casadi_math<Scalar>::fun(op, x_data[el], y_val, ret_data[el]);
1379  }
1380 
1381  // Check the value of the structural zero-entries, if there are any
1382  if (!x.is_dense() && !operation_checker<F0XChecker>(op)) {
1383  // Get the value for the structural zeros
1384  Scalar fcn_0;
1385  casadi_math<Scalar>::fun(op, casadi_limits<Scalar>::zero, y_val, fcn_0);
1386  if (!casadi_limits<Scalar>::is_zero(fcn_0)) { // Remove this if?
1387  ret = densify(ret, fcn_0);
1388  }
1389  }
1390 
1391  return ret;
1392  }
1393 
1394  template<typename Scalar>
1395  Matrix<Scalar> Matrix<Scalar>::
1396  matrix_matrix(casadi_int op, const Matrix<Scalar> &x, const Matrix<Scalar> &y) {
1397  // Check, correct dimensions
1398  if (x.size() != y.size()) {
1399  // x and y are horizontal multiples of each other?
1400  if (!x.is_empty() && !y.is_empty()) {
1401  if (x.size1() == y.size1() && x.size2() % y.size2() == 0) {
1402  return matrix_matrix(op, x, repmat(y, 1, x.size2() / y.size2()));
1403  } else if (y.size1() == x.size1() && y.size2() % x.size2() == 0) {
1404  return matrix_matrix(op, repmat(x, 1, y.size2() / x.size2()), y);
1405  }
1406  }
1407  // x and y are empty horizontal multiples of each other?
1408  if (x.size1()==0 && y.size1()==0 && x.size2()>0 && y.size2()>0) {
1409  if (x.size2() % y.size2() == 0) {
1410  return Matrix<Scalar>(0, x.size2());
1411  } else if (y.size2() % x.size2() == 0) {
1412  return Matrix<Scalar>(0, y.size2());
1413  }
1414  }
1415  // Dimension mismatch
1416  casadi_error("Dimension mismatch for " + casadi_math<Scalar>::print(op, "x", "y") +
1417  ", x is " + x.dim() + ", while y is " + y.dim());
1418  }
1419 
1420  // Get the sparsity pattern of the result
1421  // (ignoring structural zeros giving rise to nonzero result)
1422  const Sparsity& x_sp = x.sparsity();
1423  const Sparsity& y_sp = y.sparsity();
1424  Sparsity r_sp = x_sp.combine(y_sp, operation_checker<F0XChecker>(op),
1425  operation_checker<FX0Checker>(op));
1426 
1427  // Return value
1428  Matrix<Scalar> r = zeros(r_sp);
1429 
1430  // Perform the operations elementwise
1431  if (x_sp==y_sp) {
1432  // Matching sparsities
1433  casadi_math<Scalar>::fun(op, x.ptr(), y.ptr(), r.ptr(), r_sp.nnz());
1434  } else if (y_sp==r_sp) {
1435  // Project first argument
1436  Matrix<Scalar> x_mod = x(r_sp);
1437  casadi_math<Scalar>::fun(op, x_mod.ptr(), y.ptr(), r.ptr(), r_sp.nnz());
1438  } else if (x_sp==r_sp) {
1439  // Project second argument
1440  Matrix<Scalar> y_mod = y(r_sp);
1441  casadi_math<Scalar>::fun(op, x.ptr(), y_mod.ptr(), r.ptr(), r_sp.nnz());
1442  } else {
1443  // Project both arguments
1444  Matrix<Scalar> x_mod = x(r_sp);
1445  Matrix<Scalar> y_mod = y(r_sp);
1446  casadi_math<Scalar>::fun(op, x_mod.ptr(), y_mod.ptr(), r.ptr(), r_sp.nnz());
1447  }
1448 
1449  // Handle structural zeros giving rise to nonzero result, e.g. cos(0) == 1
1450  if (!r.is_dense() && !operation_checker<F00Checker>(op)) {
1451  // Get the value for the structural zeros
1452  Scalar fcn_0;
1453  casadi_math<Scalar>::fun(op, casadi_limits<Scalar>::zero,
1454  casadi_limits<Scalar>::zero, fcn_0);
1455  r = densify(r, fcn_0);
1456  }
1457 
1458  return r;
1459  }
1460 
1461  template<typename Scalar>
1462  Matrix<Scalar> Matrix<Scalar>::triplet(const std::vector<casadi_int>& row,
1463  const std::vector<casadi_int>& col,
1464  const Matrix<Scalar>& d) {
1465  casadi_int nrow = row.empty() ? 0 : *std::max_element(row.begin(), row.end()) + 1;
1466  casadi_int ncol = col.empty() ? 0 : *std::max_element(col.begin(), col.end()) + 1;
1467  return triplet(row, col, d, nrow, ncol);
1468  }
1469 
1470  template<typename Scalar>
1471  Matrix<Scalar> Matrix<Scalar>::triplet(const std::vector<casadi_int>& row,
1472  const std::vector<casadi_int>& col,
1473  const Matrix<Scalar>& d,
1474  const std::pair<casadi_int, casadi_int>& rc) {
1475  return triplet(row, col, d, rc.first, rc.second);
1476  }
1477 
1478  template<typename Scalar>
1479  Matrix<Scalar> Matrix<Scalar>::triplet(const std::vector<casadi_int>& row,
1480  const std::vector<casadi_int>& col,
1481  const Matrix<Scalar>& d,
1482  casadi_int nrow, casadi_int ncol) {
1483  casadi_assert(col.size()==row.size() && col.size()==d.nnz(),
1484  "Argument error in Matrix<Scalar>::triplet(row, col, d): "
1485  "supplied lists must all be of equal length, but got: "
1486  + str(row.size()) + ", " + str(col.size()) + " and " + str(d.nnz()));
1487  std::vector<casadi_int> mapping;
1488  Sparsity sp = Sparsity::triplet(nrow, ncol, row, col, mapping, false);
1489  return Matrix<Scalar>(sp, d.nz(mapping));
1490  }
1491 
1492  template<typename Scalar>
1493  Matrix<Scalar> Matrix<Scalar>::eye(casadi_int n) {
1494  return Matrix<Scalar>::ones(Sparsity::diag(n));
1495  }
1496 
1497  template<typename Scalar>
1498  Matrix<Scalar> Matrix<Scalar>::inf(const Sparsity& sp) {
1499  casadi_assert(std::numeric_limits<Scalar>::has_infinity,
1500  "Datatype cannot represent infinity");
1501  return Matrix<Scalar>(sp, std::numeric_limits<Scalar>::infinity(), false);
1502  }
1503 
1504 
1505  template<typename Scalar>
1506  Matrix<Scalar> Matrix<Scalar>::inf(const std::pair<casadi_int, casadi_int>& rc) {
1507  return inf(rc.first, rc.second);
1508  }
1509 
1510  template<typename Scalar>
1511  Matrix<Scalar> Matrix<Scalar>::inf(casadi_int nrow, casadi_int ncol) {
1512  return inf(Sparsity::dense(nrow, ncol));
1513  }
1514 
1515  template<typename Scalar>
1516  Matrix<Scalar> Matrix<Scalar>::nan(const Sparsity& sp) {
1517  casadi_assert(std::numeric_limits<Scalar>::has_quiet_NaN,
1518  "Datatype cannot represent not-a-number");
1519  return Matrix<Scalar>(sp, std::numeric_limits<Scalar>::quiet_NaN(), false);
1520  }
1521 
1522  template<typename Scalar>
1523  Matrix<Scalar> Matrix<Scalar>::nan(const std::pair<casadi_int, casadi_int>& rc) {
1524  return nan(rc.first, rc.second);
1525  }
1526 
1527  template<typename Scalar>
1528  Matrix<Scalar> Matrix<Scalar>::nan(casadi_int nrow, casadi_int ncol) {
1529  return nan(Sparsity::dense(nrow, ncol));
1530  }
1531 
1532  template<typename Scalar>
1533  bool Matrix<Scalar>::is_regular() const {
1534  return casadi::is_regular(nonzeros_);
1535  }
1536 
1537  template<typename Scalar>
1538  bool Matrix<Scalar>::is_smooth() const {
1539  return true;
1540  }
1541 
1542  template<typename Scalar>
1543  casadi_int Matrix<Scalar>::element_hash() const {
1544  casadi_error("'element_hash' not defined for " + type_name());
1545  }
1546 
1547  template<typename Scalar>
1548  bool Matrix<Scalar>::is_leaf() const {
1549  casadi_error("'is_leaf' not defined for " + type_name());
1550  }
1551 
1552  template<typename Scalar>
1553  bool Matrix<Scalar>::is_commutative() const {
1554  casadi_error("'is_commutative' not defined for " + type_name());
1555  }
1556 
1557  template<typename Scalar>
1558  bool Matrix<Scalar>::is_symbolic() const {
1559  return false;
1560  }
1561 
1562  template<typename Scalar>
1563  casadi_int Matrix<Scalar>::op() const {
1564  casadi_error("'op' not defined for " + type_name());
1565  }
1566 
1567  template<typename Scalar>
1568  bool Matrix<Scalar>::is_op(casadi_int k) const {
1569  casadi_error("'is_op' not defined for " + type_name());
1570  }
1571 
1572  template<typename Scalar>
1573  void Matrix<Scalar>::export_code(const std::string& lang,
1574  std::ostream &stream, const Dict& options) const {
1575  casadi_error("'export_code' not defined for " + type_name());
1576  }
1577 
1578  template<typename Scalar>
1579  bool Matrix<Scalar>::is_valid_input() const {
1580  return false;
1581  }
1582 
1583  template<typename Scalar>
1584  bool Matrix<Scalar>::has_duplicates() const {
1585  casadi_error("'has_duplicates' not defined for " + type_name());
1586  }
1587 
1588  template<typename Scalar>
1589  void Matrix<Scalar>::reset_input() const {
1590  casadi_error("'reset_input' not defined for " + type_name());
1591  }
1592 
1593  template<typename Scalar>
1594  Matrix<double> Matrix<Scalar>::from_file(const std::string& filename,
1595  const std::string& format_hint) {
1596  casadi_error("'from_file' not defined for " + type_name());
1597  }
1598 
1599  template<typename Scalar>
1600  bool Matrix<Scalar>::is_integer() const {
1601  // Look for non-integers
1602  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_integer(e)) return false;
1603 
1604  // Integer if reached this point
1605  return true;
1606  }
1607 
1608  template<typename Scalar>
1609  bool Matrix<Scalar>::is_constant() const {
1610  // Look for non-constants
1611  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_constant(e)) return false;
1612 
1613  // Constant if we reach this point
1614  return true;
1615  }
1616 
1617  template<typename Scalar>
1618  bool Matrix<Scalar>::is_call() const {
1619  casadi_assert(is_scalar(), "'is_call' only defined for scalar expressions");
1620 
1621  return false;
1622  }
1623 
1624  template<typename Scalar>
1625  bool Matrix<Scalar>::is_output() const {
1626  casadi_assert(is_scalar(), "'is_output' only defined for scalar expressions");
1627 
1628  return false;
1629  }
1630 
1631  template<typename Scalar>
1632  Matrix<Scalar> Matrix<Scalar>::get_output(casadi_int oind) const {
1633  casadi_error("'get_output' not defined for " + type_name());
1634  }
1635 
1636  template<typename Scalar>
1637  bool Matrix<Scalar>::has_output() const {
1638  casadi_assert(is_scalar(), "'has_output' only defined for scalar expressions");
1639 
1640  return false;
1641  }
1642 
1643  template<typename Scalar>
1644  Function Matrix<Scalar>::which_function() const {
1645  casadi_error("'which_function' not defined for " + type_name());
1646  }
1647 
1648  template<typename Scalar>
1649  casadi_int Matrix<Scalar>::which_output() const {
1650  casadi_error("'which_output' not defined for " + type_name());
1651  }
1652 
1653  template<typename Scalar>
1654  bool Matrix<Scalar>::is_one() const {
1655  if (!is_dense()) return false;
1656 
1657  // Look for non-ones
1658  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_one(e)) return false;
1659 
1660  return true;
1661  }
1662 
1663  template<typename Scalar>
1664  bool Matrix<Scalar>::is_minus_one() const {
1665  if (!is_dense()) return false;
1666 
1667  // Look for non-minus-ones
1668  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_minus_one(e)) return false;
1669 
1670  return true;
1671  }
1672 
1673  template<typename Scalar>
1674  bool Matrix<Scalar>::is_half() const {
1675  if (!is_dense()) return false;
1676 
1677  // Look for non-halves
1678  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_half(e)) return false;
1679 
1680  return true;
1681  }
1682 
1683  template<typename Scalar>
1684  bool Matrix<Scalar>::is_value(double val) const {
1685  if (val==0.0) return is_zero();
1686  if (!is_dense()) return false;
1687 
1688  // Look for non-values
1689  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_value(e, val)) return false;
1690 
1691  return true;
1692  }
1693 
1694  template<typename Scalar>
1695  bool Matrix<Scalar>::is_inf() const {
1696  if (!is_dense()) return false;
1697 
1698  // Look for inf
1699  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_inf(e)) return false;
1700 
1701  return true;
1702  }
1703 
1704  template<typename Scalar>
1705  bool Matrix<Scalar>::is_minus_inf() const {
1706  if (!is_dense()) return false;
1707 
1708  // Look for -inf
1709  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_minus_inf(e)) return false;
1710 
1711  return true;
1712  }
1713 
1714  template<typename Scalar>
1715  bool Matrix<Scalar>::is_nonnegative() const {
1716  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_nonnegative(e)) return false;
1717  return true;
1718  }
1719 
1720  template<typename Scalar>
1721  bool Matrix<Scalar>::is_zero() const {
1722 
1723  // Look for non-zeros
1724  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_zero(e)) return false;
1725 
1726  return true;
1727  }
1728 
1729  template<typename Scalar>
1730  bool Matrix<Scalar>::is_eye() const {
1731 
1732  // Make sure that the matrix is diagonal
1733  if (!sparsity().is_diag()) return false;
1734 
1735  // Make sure that all entries are one
1736  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_one(e)) return false;
1737 
1738  return true;
1739  }
1740 
1741  template<typename Scalar>
1742  bool Matrix<Scalar>::is_equal(const Matrix<Scalar> &x, const Matrix<Scalar> &y,
1743  casadi_int depth) {
1744  // Assert matching dimensions
1745  casadi_assert(x.size() == y.size(), "Dimension mismatch");
1746 
1747  // Project to union of patterns and call recursively if different sparsity
1748  if (x.sparsity() != y.sparsity()) {
1749  Sparsity sp = x.sparsity() + y.sparsity();
1750  return is_equal(project(x, sp), project(y, sp), depth);
1751  }
1752 
1753  // Check individual elements
1754  auto y_it = y.nonzeros().begin();
1755  for (auto&& e : x.nonzeros()) {
1756  if (!casadi_limits<Scalar>::is_equal(e, *y_it++, depth)) return false;
1757  }
1758 
1759  // True if reched this point
1760  return true;
1761  }
1762 
1763  // To avoid overloaded function name conflicts
1764  template<typename Scalar>
1765  inline Matrix<Scalar> mmin_nonstatic(const Matrix<Scalar> &x) {
1766  if (x.is_empty()) return Matrix<Scalar>();
1767  return casadi_mmin(x.ptr(), x.nnz(), x.is_dense());
1768  }
1769 
1770  template<typename Scalar>
1771  Matrix<Scalar> Matrix<Scalar>::mmin(const Matrix<Scalar> &x) {
1772  return mmin_nonstatic(x);
1773  }
1774 
1775  // To avoid overloaded function name conflicts
1776  template<typename Scalar>
1777  inline Matrix<Scalar> mmax_nonstatic(const Matrix<Scalar> &x) {
1778  if (x.is_empty()) return Matrix<Scalar>();
1779  return casadi_mmax(x.ptr(), x.nnz(), x.is_dense());
1780  }
1781 
1782  template<typename Scalar>
1783  Matrix<Scalar> Matrix<Scalar>::mmax(const Matrix<Scalar> &x) {
1784  return mmax_nonstatic(x);
1785  }
1786 
1787  template<typename Scalar>
1788  bool Matrix<Scalar>::has_zeros() const {
1789  // Check if the structural nonzero is known to be zero
1790  for (auto&& e : nonzeros()) if (casadi_limits<Scalar>::is_zero(e)) return true;
1791 
1792  // No known zeros amongst the structurally nonzero entries
1793  return false;
1794  }
1795 
1796  template<typename Scalar>
1797  std::vector<Scalar> Matrix<Scalar>::get_nonzeros() const {
1798  return nonzeros_;
1799  }
1800 
1801  template<typename Scalar>
1802  std::vector<Scalar> Matrix<Scalar>::get_elements() const {
1803  return static_cast< std::vector<Scalar>>(*this);
1804  }
1805 
1806  template<typename Scalar>
1807  std::string Matrix<Scalar>::name() const {
1808  casadi_error("'name' not defined for " + type_name());
1809  }
1810 
1811  template<typename Scalar>
1812  Matrix<Scalar> Matrix<Scalar>::dep(casadi_int ch) const {
1813  casadi_error("'dep' not defined for " + type_name());
1814  }
1815 
1816  template<typename Scalar>
1817  casadi_int Matrix<Scalar>::n_dep() const {
1818  casadi_error("'n_dep' not defined for " + type_name());
1819  }
1820 
1821  template<typename Scalar>
1822  Matrix<Scalar> Matrix<Scalar>::rand( // NOLINT(runtime/threadsafe_fn)
1823  casadi_int nrow,
1824  casadi_int ncol) {
1825  return rand(Sparsity::dense(nrow, ncol)); // NOLINT(runtime/threadsafe_fn)
1826  }
1827 
1828  template<typename Scalar>
1829  Matrix<Scalar> Matrix<Scalar>::rand( // NOLINT(runtime/threadsafe_fn)
1830  const std::pair<casadi_int, casadi_int>& rc) {
1831  return rand(rc.first, rc.second); // NOLINT(runtime/threadsafe_fn)
1832  }
1833 
1834  template<typename Scalar>
1835  Matrix<Scalar> Matrix<Scalar>::project(const Matrix<Scalar>& x,
1836  const Sparsity& sp, bool intersect) {
1837  if (intersect) {
1838  return project(x, sp.intersect(x.sparsity()), false);
1839  } else {
1840  casadi_assert(sp.size()==x.size(), "Dimension mismatch");
1841  Matrix<Scalar> ret = Matrix<Scalar>::zeros(sp);
1842  std::vector<Scalar> w(x.size1());
1843  casadi_project(x.ptr(), x.sparsity(), ret.ptr(), sp, get_ptr(w));
1844  return ret;
1845  }
1846  }
1847 
1848  template<typename Scalar>
1849  void Matrix<Scalar>::set_max_depth(casadi_int eq_depth) {
1850  casadi_error("'set_max_depth' not defined for " + type_name());
1851  }
1852 
1853  template<typename Scalar>
1854  casadi_int Matrix<Scalar>::get_max_depth() {
1855  casadi_error("'get_max_depth' not defined for " + type_name());
1856  }
1857 
1858  template<typename Scalar>
1859  Matrix<Scalar> Matrix<Scalar>::det(const Matrix<Scalar>& x) {
1860  casadi_int n = x.size2();
1861  casadi_assert(n == x.size1(), "matrix must be square");
1862 
1863  // Trivial return if scalar
1864  if (x.is_scalar()) return x;
1865 
1866  // Trivial case 2 x 2
1867  if (n==2) return x(0, 0) * x(1, 1) - x(0, 1) * x(1, 0);
1868 
1869  // Return expression
1870  Matrix<Scalar> ret = 0;
1871 
1872  // Find out which is the best direction to expand along
1873 
1874  // Build up an IM with ones on the non-zeros
1875  Matrix<casadi_int> sp = IM::ones(x.sparsity());
1876 
1877  // Have a count of the nonzeros for each row
1878  Matrix<casadi_int> row_count = Matrix<casadi_int>::sum2(sp);
1879 
1880  // A blank row? determinant is structurally zero
1881  if (!row_count.is_dense()) return 0;
1882 
1883  // Have a count of the nonzeros for each col
1884  Matrix<casadi_int> col_count = Matrix<casadi_int>::sum1(sp).T();
1885 
1886  // A blank col? determinant is structurally zero
1887  if (!col_count.is_dense()) return 0;
1888 
1889  casadi_int min_row = std::distance(row_count.nonzeros().begin(),
1890  std::min_element(row_count.nonzeros().begin(),
1891  row_count.nonzeros().end()));
1892  casadi_int min_col = std::distance(col_count.nonzeros().begin(),
1893  std::min_element(col_count.nonzeros().begin(),
1894  col_count.nonzeros().end()));
1895 
1896  if (min_row <= min_col) {
1897  // Expand along row j
1898  casadi_int j = row_count.sparsity().row(min_row);
1899 
1900  Matrix<Scalar> row = x(j, Slice(0, n));
1901 
1902  std::vector< casadi_int > col_i = row.sparsity().get_col();
1903 
1904  for (casadi_int k=0; k<row.nnz(); ++k) {
1905  // Sum up the cofactors
1906  ret += row->at(k)*cofactor(x, col_i.at(k), j);
1907  }
1908  return ret;
1909  } else {
1910  // Expand along col i
1911  casadi_int i = col_count.sparsity().row(min_col);
1912 
1913  Matrix<Scalar> col = x(Slice(0, n), i);
1914 
1915  const casadi_int* row_i = col.row();
1916 
1917  for (casadi_int k=0; k<col.nnz(); ++k) {
1918  // Sum up the cofactors
1919  ret += col->at(k)*cofactor(x, i, row_i[k]);
1920  }
1921  return ret;
1922  }
1923 
1924  }
1925 
1926  template<typename Scalar>
1927  Matrix<Scalar> Matrix<Scalar>::
1928  det(const Matrix<Scalar>& x, const std::string& lsolver, const Dict& dict) {
1929  casadi_error("'det' with plugin not defined for " + type_name());
1930  return Matrix<Scalar>();
1931  }
1932 
1933  template<typename Scalar>
1934  Matrix<Scalar> Matrix<Scalar>::sum2(const Matrix<Scalar>& x) {
1935  return mtimes(x, Matrix<Scalar>::ones(x.size2(), 1));
1936  }
1937 
1938  template<typename Scalar>
1939  Matrix<Scalar> Matrix<Scalar>::sum1(const Matrix<Scalar>& x) {
1940  return mtimes(Matrix<Scalar>::ones(1, x.size1()), x);
1941  }
1942 
1943  template<typename Scalar>
1944  Matrix<Scalar> Matrix<Scalar>::minor(const Matrix<Scalar>& x,
1945  casadi_int i, casadi_int j) {
1946  casadi_int n = x.size2();
1947  casadi_assert(n == x.size1(), "minor: matrix must be square");
1948 
1949  // Trivial return if scalar
1950  if (n==1) return 1;
1951 
1952  // Remove col i and row j
1953  Matrix<Scalar> M = Matrix<Scalar>(n-1, n-1);
1954 
1955  std::vector<casadi_int> col = x.sparsity().get_col();
1956  const casadi_int* row = x.sparsity().row();
1957 
1958  for (casadi_int k=0; k<x.nnz(); ++k) {
1959  casadi_int i1 = col[k];
1960  casadi_int j1 = row[k];
1961 
1962  if (i1 == i || j1 == j) continue;
1963 
1964  casadi_int i2 = (i1<i)?i1:i1-1;
1965  casadi_int j2 = (j1<j)?j1:j1-1;
1966 
1967  M(j2, i2) = x(j1, i1);
1968  }
1969  return det(M);
1970  }
1971 
1972  template<typename Scalar>
1973  Matrix<Scalar> Matrix<Scalar>::cofactor(const Matrix<Scalar>& A, casadi_int i, casadi_int j) {
1974 
1975  // Calculate the i, j minor
1976  Matrix<Scalar> minor_ij = minor(A, i, j);
1977  // Calculate the cofactor
1978  casadi_int sign_i = 1-2*((i+j) % 2);
1979 
1980  return sign_i * minor_ij;
1981  }
1982 
1983  template<typename Scalar>
1984  Matrix<Scalar> Matrix<Scalar>::adj(const Matrix<Scalar>& x) {
1985  casadi_int n = x.size2();
1986  casadi_assert(n == x.size1(), "adj: matrix must be square");
1987 
1988  // Temporary placeholder
1989  Matrix<Scalar> temp;
1990 
1991  // Cofactor matrix
1992  Matrix<Scalar> C = Matrix<Scalar>(n, n);
1993  for (casadi_int i=0; i<n; ++i)
1994  for (casadi_int j=0; j<n; ++j) {
1995  temp = cofactor(x, i, j);
1996  if (!temp.is_zero()) C(j, i) = temp;
1997  }
1998 
1999  return C.T();
2000  }
2001 
2002  template<typename Scalar>
2003  Matrix<Scalar> Matrix<Scalar>::inv_minor(const Matrix<Scalar>& x) {
2004  // laplace formula
2005  return adj(x)/det(x);
2006  }
2007 
2008  template<typename Scalar>
2009  Matrix<Scalar> Matrix<Scalar>::reshape(const Matrix<Scalar>& x,
2010  casadi_int nrow, casadi_int ncol) {
2011  Sparsity sp = Sparsity::reshape(x.sparsity(), nrow, ncol);
2012  return Matrix<Scalar>(sp, x.nonzeros(), false);
2013  }
2014 
2015  template<typename Scalar>
2016  Matrix<Scalar> Matrix<Scalar>::reshape(const Matrix<Scalar>& x, const Sparsity& sp) {
2017  // quick return if already the right shape
2018  if (sp==x.sparsity()) return x;
2019 
2020  // make sure that the patterns match
2021  casadi_assert(sp.is_reshape(x.sparsity()),
2022  "Reshape mismatch: cannot reshape " + x.dim() + " to " + sp.dim(true));
2023 
2024  return Matrix<Scalar>(sp, x.nonzeros(), false);
2025  }
2026 
2027  template<typename Scalar>
2028  Matrix<Scalar> Matrix<Scalar>::sparsity_cast(const Matrix<Scalar>& x, const Sparsity& sp) {
2029  // quick return if already the right shape
2030  if (sp==x.sparsity()) return x;
2031 
2032  casadi_assert(sp.nnz()==x.nnz(), "sparsity_cast: x has " + str(x.nnz()) + " nonzeros, "
2033  "but the target pattern has " + str(sp.nnz()));
2034 
2035  return Matrix<Scalar>(sp, x.nonzeros(), false);
2036  }
2037 
2038  template<typename Scalar>
2039  Matrix<Scalar> Matrix<Scalar>::trace(const Matrix<Scalar>& x) {
2040  casadi_assert(x.is_square(), "trace: must be square");
2041  Scalar res=0;
2042  const Scalar* d=x.ptr();
2043  casadi_int size2 = x.size2();
2044  const casadi_int *colind=x.colind(), *row=x.row();
2045  for (casadi_int c=0; c<size2; c++) {
2046  for (casadi_int k=colind[c]; k!=colind[c+1]; ++k) {
2047  if (row[k]==c) {
2048  res += d[k];
2049  }
2050  }
2051  }
2052  return res;
2053  }
2054 
2055  template<typename Scalar>
2056  Matrix<Scalar>
2057  Matrix<Scalar>::blockcat(const std::vector< std::vector<Matrix<Scalar> > > &v) {
2058  std::vector< Matrix<Scalar> > ret;
2059  for (casadi_int i=0; i<v.size(); ++i)
2060  if (!v[i].empty()) ret.push_back(horzcat(v[i]));
2061  if (ret.empty()) return Matrix<Scalar>(0, 0);
2062  return vertcat(ret);
2063  }
2064 
2065  template<typename Scalar>
2066  Matrix<Scalar> Matrix<Scalar>::horzcat(const std::vector<Matrix<Scalar> > &v) {
2067  // Concatenate sparsity patterns
2068  std::vector<Sparsity> sp(v.size());
2069  for (casadi_int i=0; i<v.size(); ++i) sp[i] = v[i].sparsity();
2070  Matrix<Scalar> ret = zeros(Sparsity::horzcat(sp));
2071 
2072  // Copy nonzeros
2073  auto i=ret->begin();
2074  for (auto&& j : v) {
2075  std::copy(j->begin(), j->end(), i);
2076  i += j.nnz();
2077  }
2078  return ret;
2079  }
2080 
2081  template<typename Scalar>
2082  std::vector<Matrix<Scalar> >
2083  Matrix<Scalar>::horzsplit(const Matrix<Scalar>& x, const std::vector<casadi_int>& offset) {
2084  // Split up the sparsity pattern
2085  std::vector<Sparsity> sp = Sparsity::horzsplit(x.sparsity(), offset);
2086 
2087  // Return object
2088  std::vector<Matrix<Scalar> > ret;
2089  ret.reserve(sp.size());
2090 
2091  // Copy data
2092  auto i=x.nonzeros().begin();
2093  for (auto&& j : sp) {
2094  auto i_next = i + j.nnz();
2095  ret.push_back(Matrix<Scalar>(j, std::vector<Scalar>(i, i_next), false));
2096  i = i_next;
2097  }
2098 
2099  // Return the assembled matrix
2100  casadi_assert_dev(i==x.nonzeros().end());
2101  return ret;
2102  }
2103 
2104  template<typename Scalar>
2105  Matrix<Scalar> Matrix<Scalar>::vertcat(const std::vector<Matrix<Scalar> > &v) {
2106  // Consistency check
2107  casadi_int ncol = 0;
2108  for (auto&& e : v) {
2109  if (e.size2()==0) continue;
2110  casadi_assert(ncol==0 || e.size2()==ncol, "vertcat: Mismatching number of columns, "
2111  "got " + str(ncol) + " and " + str(e.size2()));
2112  ncol = e.size2();
2113  }
2114 
2115  std::vector<Matrix<Scalar> > vT(v.size());
2116  for (casadi_int i=0; i<v.size(); ++i) vT[i] = v[i].T();
2117  return horzcat(vT).T();
2118  }
2119 
2120  template<typename Scalar>
2121  std::vector< Matrix<Scalar> >
2122  Matrix<Scalar>::vertsplit(const Matrix<Scalar>& x, const std::vector<casadi_int>& offset) {
2123  std::vector< Matrix<Scalar> > ret = horzsplit(x.T(), offset);
2124  for (auto&& e : ret) e = e.T();
2125  return ret;
2126  }
2127 
2128  template<typename Scalar>
2129  std::vector< Matrix<Scalar> >
2130  Matrix<Scalar>::diagsplit(const Matrix<Scalar>& x, const std::vector<casadi_int>& offset1,
2131  const std::vector<casadi_int>& offset2) {
2132  // Consistency check
2133  check_offset(offset1, x.size1(), "diagsplit");
2134  check_offset(offset2, x.size2(), "diagsplit");
2135  casadi_assert(offset1.size()==offset2.size(),
2136  "diagsplit: offset1 and offset2 must have the same length");
2137 
2138  // Number of outputs
2139  casadi_int n = offset1.size()-1;
2140 
2141  // Return value
2142  std::vector< Matrix<Scalar> > ret;
2143 
2144  // Caveat: this is a very silly implementation
2145  for (casadi_int i=0; i<n; ++i) {
2146  ret.push_back(x(Slice(offset1[i], offset1[i+1]), Slice(offset2[i], offset2[i+1])));
2147  }
2148 
2149  // Entries outside the diagonal blocks must be zero
2150  casadi_int n_dropped = 0;
2151  for (auto&& e : x.nonzeros()) n_dropped += !casadi_limits<Scalar>::is_zero(e);
2152  for (auto&& r : ret) {
2153  for (auto&& e : r.nonzeros()) n_dropped -= !casadi_limits<Scalar>::is_zero(e);
2154  }
2155  casadi_assert(n_dropped==0,
2156  "diagsplit: the presence of nonzeros outside the diagonal blocks is unsupported.");
2157 
2158  return ret;
2159  }
2160 
2161  template<typename Scalar>
2162  Matrix<Scalar> Matrix<Scalar>::dot(const Matrix<Scalar> &x,
2163  const Matrix<Scalar> &y) {
2164  casadi_assert(x.size()==y.size(), "dot: Dimension mismatch");
2165  if (x.sparsity()!=y.sparsity()) {
2166  Sparsity sp = x.sparsity() * y.sparsity();
2167  return dot(project(x, sp), project(y, sp));
2168  }
2169  return casadi_dot(x.nnz(), x.ptr(), y.ptr());
2170  }
2171 
2172  template<typename Scalar>
2173  Matrix<Scalar> Matrix<Scalar>::all(const Matrix<Scalar>& x) {
2174  if (!x.is_dense()) return false;
2175  Scalar ret=1;
2176  for (casadi_int i=0; i<x.nnz(); ++i) {
2177  ret = ret && x->at(i)==1;
2178  }
2179  return ret;
2180  }
2181 
2182  template<typename Scalar>
2183  Matrix<Scalar> Matrix<Scalar>::any(const Matrix<Scalar>& x) {
2184  if (!x.is_dense()) return false;
2185  Scalar ret=0;
2186  for (casadi_int i=0; i<x.nnz(); ++i) {
2187  ret = ret || x->at(i)==1;
2188  }
2189  return ret;
2190  }
2191 
2192  template<typename Scalar>
2193  Matrix<Scalar> Matrix<Scalar>::norm_1(const Matrix<Scalar>& x) {
2194  return casadi_norm_1(x.nnz(), x.ptr());
2195  }
2196 
2197  template<typename Scalar>
2198  Matrix<Scalar> Matrix<Scalar>::norm_2(const Matrix<Scalar>& x) {
2199  if (x.is_vector()) {
2200  return norm_fro(x);
2201  } else {
2202  casadi_error("2-norms currently only supported for vectors. "
2203  "Did you intend to calculate a Frobenius norms (norm_fro)?");
2204  }
2205  }
2206 
2207  template<typename Scalar>
2208  Matrix<Scalar> Matrix<Scalar>::norm_fro(const Matrix<Scalar>& x) {
2209  return casadi_norm_2(x.nnz(), x.ptr());
2210  }
2211 
2212  template<typename Scalar>
2213  Matrix<Scalar> Matrix<Scalar>::norm_inf(const Matrix<Scalar>& x) {
2214  // Get largest element by absolute value
2215  Matrix<Scalar> s = 0;
2216  for (auto i=x.nonzeros().begin(); i!=x.nonzeros().end(); ++i) {
2217  s = fmax(s, fabs(Matrix<Scalar>(*i)));
2218  }
2219  return s;
2220  }
2221 
2222  template<typename Scalar>
2223  void Matrix<Scalar>::
2224  qr_sparse(const Matrix<Scalar>& A,
2225  Matrix<Scalar>& V, Matrix<Scalar> &R, Matrix<Scalar>& beta,
2226  std::vector<casadi_int>& prinv, std::vector<casadi_int>& pc, bool amd) {
2227  // Calculate the pattern
2228  Sparsity spV, spR;
2229  A.sparsity().qr_sparse(spV, spR, prinv, pc, amd);
2230  // Calculate the nonzeros
2231  casadi_int nrow_ext = spV.size1(), ncol = spV.size2();
2232  V = nan(spV);
2233  R = nan(spR);
2234  beta = nan(ncol, 1);
2235  std::vector<Scalar> w(nrow_ext);
2236  casadi_qr(A.sparsity(), A.ptr(), get_ptr(w), spV, V.ptr(),
2237  spR, R.ptr(), beta.ptr(),
2238  get_ptr(prinv), get_ptr(pc));
2239  }
2240 
2241  template<typename Scalar>
2242  Matrix<Scalar> Matrix<Scalar>::
2243  qr_solve(const Matrix<Scalar>& b, const Matrix<Scalar>& v,
2244  const Matrix<Scalar>& r, const Matrix<Scalar>& beta,
2245  const std::vector<casadi_int>& prinv, const std::vector<casadi_int>& pc,
2246  bool tr) {
2247  // Get dimensions, check consistency
2248  casadi_int ncol = v.size2();
2249  casadi_int nrow = b.size1(), nrhs = b.size2();
2250  casadi_assert(r.size()==v.size(), "'r', 'v' dimension mismatch");
2251  casadi_assert(beta.is_vector() && beta.numel()==ncol, "'beta' has wrong dimension");
2252  casadi_assert(prinv.size()==r.size1(), "'pinv' has wrong dimension");
2253  // Work vector
2254  std::vector<Scalar> w(nrow+ncol);
2255  // Return value
2256  Matrix<Scalar> x = densify(b);
2257  casadi_qr_solve(x.ptr(), nrhs, tr, v.sparsity(), v.ptr(), r.sparsity(), r.ptr(),
2258  beta.ptr(), get_ptr(prinv), get_ptr(pc), get_ptr(w));
2259  return x;
2260  }
2261 
2262  template<typename Scalar>
2263  void Matrix<Scalar>::qr(const Matrix<Scalar>& A,
2264  Matrix<Scalar>& Q, Matrix<Scalar> &R) {
2265  // The following algorithm is taken from J. Demmel:
2266  // Applied Numerical Linear Algebra (algorithm 3.1.)
2267  casadi_assert(A.size1()>=A.size2(), "qr: fewer rows than columns");
2268 
2269  // compute Q and R column by column
2270  Q = R = Matrix<Scalar>();
2271  for (casadi_int i=0; i<A.size2(); ++i) {
2272  // Initialize qi to be the i-th column of *this
2273  Matrix<Scalar> ai = A(Slice(), i);
2274  Matrix<Scalar> qi = ai;
2275  // The i-th column of R
2276  Matrix<Scalar> ri = Matrix<Scalar>(A.size2(), 1);
2277 
2278  // subtract the projection of qi in the previous directions from ai
2279  for (casadi_int j=0; j<i; ++j) {
2280 
2281  // Get the j-th column of Q
2282  Matrix<Scalar> qj = Q(Slice(), j); // NOLINT(cppcoreguidelines-slicing)
2283 
2284  ri(j, 0) = mtimes(qi.T(), qj); // Modified Gram-Schmidt
2285  // ri[j] = dot(qj, ai); // Classical Gram-Schmidt
2286 
2287  // Remove projection in direction j
2288  if (ri.has_nz(j, 0))
2289  qi -= ri(j, 0) * qj;
2290  }
2291 
2292  // Normalize qi
2293  ri(i, 0) = norm_2(qi);
2294  qi /= ri(i, 0);
2295 
2296  // Update R and Q
2297  Q = Matrix<Scalar>::horzcat({Q, qi});
2298  R = Matrix<Scalar>::horzcat({R, ri});
2299  }
2300  }
2301 
2302  template<typename Scalar>
2303  void Matrix<Scalar>::ldl(const Matrix<Scalar>& A, Matrix<Scalar> &D,
2304  Matrix<Scalar>& LT, std::vector<casadi_int>& p, bool amd) {
2305  // Symbolic factorization
2306  Sparsity Lt_sp = A.sparsity().ldl(p, amd);
2307 
2308  // Get dimension
2309  casadi_int n=A.size1();
2310 
2311  // Calculate entries in L and D
2312  std::vector<Scalar> D_nz(n), L_nz(Lt_sp.nnz()), w(n);
2313  casadi_ldl(A.sparsity(), get_ptr(A.nonzeros()), Lt_sp,
2314  get_ptr(L_nz), get_ptr(D_nz), get_ptr(p), get_ptr(w));
2315 
2316  // Assemble L and D
2317  LT = Matrix<Scalar>(Lt_sp, L_nz);
2318  D = D_nz;
2319  }
2320 
2321  template<typename Scalar>
2322  Matrix<Scalar> Matrix<Scalar>::
2323  ldl_solve(const Matrix<Scalar>& b, const Matrix<Scalar>& D, const Matrix<Scalar>& LT,
2324  const std::vector<casadi_int>& p) {
2325  // Get dimensions, check consistency
2326  casadi_int n = b.size1(), nrhs = b.size2();
2327  casadi_assert(p.size()==n, "'p' has wrong dimension");
2328  casadi_assert(LT.size1()==n && LT.size2()==n, "'LT' has wrong dimension");
2329  casadi_assert(D.is_vector() && D.numel()==n, "'D' has wrong dimension");
2330  // Solve for all right-hand-sides
2331  Matrix<Scalar> x = densify(b);
2332  std::vector<Scalar> w(n);
2333  casadi_ldl_solve(x.ptr(), nrhs, LT.sparsity(), LT.ptr(), D.ptr(), get_ptr(p), get_ptr(w));
2334  return x;
2335  }
2336 
2337  template<typename Scalar>
2338  Matrix<Scalar> Matrix<Scalar>::nullspace(const Matrix<Scalar>& A) {
2339  Matrix<Scalar> X = A;
2340  casadi_int n = X.size1();
2341  casadi_int m = X.size2();
2342  casadi_assert(m>=n, "nullspace(): expecting a flat matrix (more columns than rows), "
2343  "but got " + str(X.dim()) + ".");
2344 
2345  Matrix<Scalar> seed = DM::eye(m)(Slice(0, m), Slice(n, m)); // NOLINT(cppcoreguidelines-slicing)
2346 
2347  std::vector< Matrix<Scalar> > us;
2348  std::vector< Matrix<Scalar> > betas;
2349 
2350  Matrix<Scalar> beta;
2351 
2352  for (casadi_int i=0;i<n;++i) {
2353  Matrix<Scalar> x = X(i, Slice(i, m)); // NOLINT(cppcoreguidelines-slicing)
2354  Matrix<Scalar> u = Matrix<Scalar>(x);
2355  Matrix<Scalar> sigma = sqrt(sum2(x*x));
2356  const Matrix<Scalar>& x0 = x(0, 0);
2357  u(0, 0) = 1;
2358 
2359  Matrix<Scalar> b = -copysign(sigma, x0);
2360 
2361  u(Slice(0), Slice(1, m-i))*= 1/(x0-b);
2362  beta = 1-x0/b;
2363 
2364  X(Slice(i, n), Slice(i, m)) -=
2365  beta*mtimes(mtimes(X(Slice(i, n), Slice(i, m)), u.T()), u);
2366  us.push_back(u);
2367  betas.push_back(beta);
2368  }
2369 
2370  for (casadi_int i=n-1;i>=0;--i) {
2371  seed(Slice(i, m), Slice(0, m-n)) -=
2372  betas[i]*mtimes(us[i].T(), mtimes(us[i], seed(Slice(i, m), Slice(0, m-n))));
2373  }
2374 
2375  return seed;
2376 
2377  }
2378 
2379  template<typename Scalar>
2380  Matrix<Scalar> Matrix<Scalar>::chol(const Matrix<Scalar>& A) {
2381  // Perform an LDL transformation
2382  Matrix<Scalar> D, LT;
2383  std::vector<casadi_int> p;
2384  ldl(A, D, LT, p, false);
2385  // Add unit diagonal
2386  LT += Matrix<Scalar>::eye(D.size1());
2387  // Get the cholesky factor: R*R' = L*D*L' = (sqrt(D)*L')'*(sqrt(D)*L')
2388  return mtimes(diag(sqrt(D)), LT);
2389  }
2390 
2391  template<typename Scalar>
2392  Matrix<Scalar> Matrix<Scalar>::solve(const Matrix<Scalar>& a, const Matrix<Scalar>& b) {
2393  // check dimensions
2394  casadi_assert(a.size1() == b.size1(), "solve Ax=b: dimension mismatch: b has "
2395  + str(b.size1()) + " rows while A has " + str(a.size1()) + ".");
2396  casadi_assert(a.size1() == a.size2(), "solve: A not square but " + str(a.dim()));
2397 
2398  if (a.is_tril()) {
2399  // forward substitution if lower triangular
2400  Matrix<Scalar> x = b;
2401  const casadi_int* Arow = a.row();
2402  const casadi_int* Acolind = a.colind();
2403  const std::vector<Scalar> & Adata = a.nonzeros();
2404  for (casadi_int i=0; i<a.size2(); ++i) { // loop over columns forwards
2405  for (casadi_int k=0; k<b.size2(); ++k) { // for every right hand side
2406  if (!x.has_nz(i, k)) continue;
2407  x(i, k) /= a(i, i);
2408  for (casadi_int kk=Acolind[i+1]-1; kk>=Acolind[i] && Arow[kk]>i; --kk) {
2409  casadi_int j = Arow[kk];
2410  x(j, k) -= Adata[kk]*x(i, k);
2411  }
2412  }
2413  }
2414  return x;
2415  } else if (a.is_triu()) {
2416  // backward substitution if upper triangular
2417  Matrix<Scalar> x = b;
2418  const casadi_int* Arow = a.row();
2419  const casadi_int* Acolind = a.colind();
2420  const std::vector<Scalar> & Adata = a.nonzeros();
2421  for (casadi_int i=a.size2()-1; i>=0; --i) { // loop over columns backwards
2422  for (casadi_int k=0; k<b.size2(); ++k) { // for every right hand side
2423  if (!x.has_nz(i, k)) continue;
2424  x(i, k) /= a(i, i);
2425  for (casadi_int kk=Acolind[i]; kk<Acolind[i+1] && Arow[kk]<i; ++kk) {
2426  casadi_int j = Arow[kk];
2427  x(j, k) -= Adata[kk]*x(i, k);
2428  }
2429  }
2430  }
2431  return x;
2432  } else if (a.has_zeros()) {
2433 
2434  // If there are structurally nonzero entries that are known to be zero,
2435  // remove these and rerun the algorithm
2436  return solve(sparsify(a), b);
2437 
2438  } else {
2439 
2440  // Make a BLT transformation of A
2441  std::vector<casadi_int> rowperm, colperm, rowblock, colblock;
2442  std::vector<casadi_int> coarse_rowblock, coarse_colblock;
2443  a.sparsity().btf(rowperm, colperm, rowblock, colblock,
2444  coarse_rowblock, coarse_colblock);
2445 
2446  // Permute the right hand side
2447  Matrix<Scalar> bperm = b(rowperm, Slice());
2448 
2449  // Permute the linear system
2450  Matrix<Scalar> Aperm = a(rowperm, colperm);
2451 
2452  // Solution
2453  Matrix<Scalar> xperm;
2454 
2455  // Solve permuted system
2456  if (Aperm.is_tril()) {
2457 
2458  // Forward substitution if lower triangular
2459  xperm = solve(Aperm, bperm);
2460 
2461  } else if (a.size2()<=3) {
2462 
2463  // Form inverse by minor expansion and multiply if very small (up to 3-by-3)
2464  xperm = mtimes(inv_minor(Aperm), bperm);
2465 
2466  } else {
2467 
2468  // Make a QR factorization
2469  Matrix<Scalar> Q, R;
2470  qr(Aperm, Q, R);
2471 
2472  // Solve the factorized system (note that solve will now be fast since it is triangular)
2473  xperm = solve(R, mtimes(Q.T(), bperm));
2474  }
2475 
2476  // get the inverted column permutation
2477  std::vector<casadi_int> inv_colperm(colperm.size());
2478  for (casadi_int k=0; k<colperm.size(); ++k)
2479  inv_colperm[colperm[k]] = k;
2480 
2481  // Permute back the solution and return
2482  Matrix<Scalar> x = xperm(inv_colperm, Slice()); // NOLINT(cppcoreguidelines-slicing)
2483  return x;
2484  }
2485  }
2486 
2487  template<typename Scalar>
2488  Matrix<Scalar> Matrix<Scalar>::
2489  solve(const Matrix<Scalar>& a, const Matrix<Scalar>& b,
2490  const std::string& lsolver, const Dict& dict) {
2491  casadi_error("'solve' with plugin not defined for " + type_name());
2492  return Matrix<Scalar>();
2493  }
2494 
2495  template<typename Scalar>
2496  Matrix<Scalar> Matrix<Scalar>::
2497  inv(const Matrix<Scalar>& a) {
2498  return solve(a, Matrix<Scalar>::eye(a.size1()));
2499  }
2500 
2501  template<typename Scalar>
2502  Matrix<Scalar> Matrix<Scalar>::
2503  inv(const Matrix<Scalar>& a,
2504  const std::string& lsolver, const Dict& dict) {
2505  casadi_error("'inv' with plugin not defined for " + type_name());
2506  return Matrix<Scalar>();
2507  }
2508 
2509  template<typename Scalar>
2510  Matrix<Scalar> Matrix<Scalar>::pinv(const Matrix<Scalar>& A) {
2511  if (A.size2()>=A.size1()) {
2512  return solve(mtimes(A, A.T()), A).T();
2513  } else {
2514  return solve(mtimes(A.T(), A), A.T());
2515  }
2516  }
2517 
2518  template<typename Scalar>
2519  Matrix<Scalar> Matrix<Scalar>::
2520  pinv(const Matrix<Scalar>& A, const std::string& lsolver, const Dict& dict) {
2521  casadi_error("'solve' not defined for " + type_name());
2522  return Matrix<Scalar>();
2523  }
2524 
2525  template<typename Scalar>
2526  Matrix<Scalar> Matrix<Scalar>::
2527  expm_const(const Matrix<Scalar>& A, const Matrix<Scalar>& t) {
2528  casadi_error("'solve' not defined for " + type_name());
2529  return Matrix<Scalar>();
2530  }
2531 
2532  template<typename Scalar>
2533  Matrix<Scalar> Matrix<Scalar>::
2534  expm(const Matrix<Scalar>& A) {
2535  casadi_error("'solve' not defined for " + type_name());
2536  return Matrix<Scalar>();
2537  }
2538 
2539  template<typename Scalar>
2540  Matrix<Scalar> Matrix<Scalar>::kron(const Matrix<Scalar>& a, const Matrix<Scalar>& b) {
2541  std::vector<Scalar> ret(a.nnz()*b.nnz());
2542  casadi_kron(get_ptr(a), a.sparsity(), get_ptr(b), b.sparsity(), get_ptr(ret));
2543 
2544  Sparsity sp_ret = Sparsity::kron(a.sparsity(), b.sparsity());
2545  return Matrix<Scalar>(sp_ret, ret, false);
2546  }
2547 
2548  template<typename Scalar>
2549  Matrix<Scalar> Matrix<Scalar>::diag(const Matrix<Scalar>& A) {
2550  // Nonzero mapping
2551  std::vector<casadi_int> mapping;
2552  // Get the sparsity
2553  Sparsity sp = A.sparsity().get_diag(mapping);
2554 
2555  Matrix<Scalar> ret = zeros(sp);
2556 
2557  for (casadi_int k=0; k<mapping.size(); k++) ret.nz(k) = A.nz(mapping[k]);
2558  return ret;
2559  }
2560 
2564  template<typename Scalar>
2565  Matrix<Scalar> Matrix<Scalar>::diagcat(const std::vector< Matrix<Scalar> > &A) {
2566  std::vector<Scalar> data;
2567 
2568  std::vector<Sparsity> sp;
2569  for (casadi_int i=0;i<A.size();++i) {
2570  data.insert(data.end(), A[i].nonzeros().begin(), A[i].nonzeros().end());
2571  sp.push_back(A[i].sparsity());
2572  }
2573 
2574  return Matrix<Scalar>(Sparsity::diagcat(sp), data, false);
2575  }
2576 
2580  template<typename Scalar>
2581  bool Matrix<Scalar>::simplify_ref_count(std::vector< Matrix<Scalar> >& arg,
2582  std::vector< Matrix<Scalar> >& res,
2583  const Dict& opts) {
2584  casadi_error("'simplify_ref_count' not defined for " + type_name());
2585  }
2586 
2590  template<typename Scalar>
2591  bool Matrix<Scalar>::simplify_const_folding(std::vector< Matrix<Scalar> >& arg,
2592  std::vector< Matrix<Scalar> >& res,
2593  const Dict& opts) {
2594  casadi_error("'simplify_const_folding' not defined for " + type_name());
2595  }
2596 
2597  template<typename Scalar>
2598  bool Matrix<Scalar>::simplify_combine_terms(std::vector< Matrix<Scalar> >& arg,
2599  std::vector< Matrix<Scalar> >& res,
2600  const Dict& opts) {
2601  casadi_error("'simplify_combine_terms' not defined for " + type_name());
2602  }
2603 
2604  template<typename Scalar>
2605  Matrix<Scalar> Matrix<Scalar>::unite(const Matrix<Scalar>& A, const Matrix<Scalar>& B) {
2606  // Join the sparsity patterns
2607  std::vector<unsigned char> mapping;
2608  Sparsity sp = A.sparsity().unite(B.sparsity(), mapping);
2609 
2610  // Create return matrix
2611  Matrix<Scalar> ret = zeros(sp);
2612 
2613  // Copy sparsity
2614  casadi_int elA=0, elB=0;
2615  for (casadi_int k=0; k<mapping.size(); ++k) {
2616  if (mapping[k]==1) {
2617  ret.nonzeros()[k] = A.nonzeros()[elA++];
2618  } else if (mapping[k]==2) {
2619  ret.nonzeros()[k] = B.nonzeros()[elB++];
2620  } else {
2621  casadi_error("Pattern intersection not empty");
2622  }
2623  }
2624 
2625  casadi_assert_dev(A.nnz()==elA);
2626  casadi_assert_dev(B.nnz()==elB);
2627 
2628  return ret;
2629  }
2630 
2631  template<typename Scalar>
2632  Matrix<Scalar> Matrix<Scalar>::polyval(const Matrix<Scalar>& p, const Matrix<Scalar>& x) {
2633  casadi_assert(p.is_dense(), "polynomial coefficients vector must be dense");
2634  casadi_assert(p.is_vector() && p.nnz()>0, "polynomial coefficients must be a vector");
2635  // Structural zeros of x map to the constant term
2636  Matrix<Scalar> ret = casadi_limits<Scalar>::is_zero(p->back()) ? x : densify(x);
2637  for (auto&& e : ret.nonzeros()) {
2638  e = casadi_polyval(p.ptr(), p.numel()-1, e);
2639  }
2640  return ret;
2641  }
2642 
2643  template<typename Scalar>
2644  Matrix<Scalar> Matrix<Scalar>::norm_inf_mul(const Matrix<Scalar>& x,
2645  const Matrix<Scalar>& y) {
2646  casadi_assert(y.size1()==x.size2(), "Dimension error. Got " + x.dim()
2647  + " times " + y.dim() + ".");
2648 
2649  // Allocate work vectors
2650  std::vector<Scalar> dwork(x.size1());
2651  std::vector<casadi_int> iwork(x.size1()+1+y.size2());
2652 
2653  // Call C runtime
2654  return casadi_norm_inf_mul(x.ptr(), x.sparsity(), y.ptr(), y.sparsity(),
2655  get_ptr(dwork), get_ptr(iwork));
2656  }
2657 
2658  template<typename Scalar>
2659  void Matrix<Scalar>::expand(const Matrix<Scalar>& ex,
2660  Matrix<Scalar> &weights, Matrix<Scalar>& terms) {
2661  casadi_error("'expand' not defined for " + type_name());
2662  }
2663 
2664  template<typename Scalar>
2665  Matrix<Scalar> Matrix<Scalar>::pw_const(const Matrix<Scalar>& ex,
2666  const Matrix<Scalar>& tval,
2667  const Matrix<Scalar>& val) {
2668  casadi_error("'pw_const' not defined for " + type_name());
2669  return Matrix<Scalar>();
2670  }
2671 
2672  template<typename Scalar>
2673  Matrix<Scalar> Matrix<Scalar>::pw_lin(const Matrix<Scalar>& ex,
2674  const Matrix<Scalar>& tval,
2675  const Matrix<Scalar>& val) {
2676  casadi_error("'pw_lin' not defined for " + type_name());
2677  return Matrix<Scalar>();
2678  }
2679 
2680  template<typename Scalar>
2681  Matrix<Scalar> Matrix<Scalar>::if_else(const Matrix<Scalar> &cond,
2682  const Matrix<Scalar> &if_true,
2683  const Matrix<Scalar> &if_false,
2684  bool short_circuit) {
2685  return if_else_zero(cond, if_true) + if_else_zero(!cond, if_false);
2686  }
2687 
2688  template<typename Scalar>
2689  Matrix<Scalar> Matrix<Scalar>::conditional(const Matrix<Scalar>& ind,
2690  const std::vector<Matrix<Scalar> >& x,
2691  const Matrix<Scalar>& x_default,
2692  bool short_circuit) {
2693  casadi_assert(!short_circuit,
2694  "Short-circuiting 'conditional' not supported for " + type_name());
2695  casadi_assert(ind.is_scalar(true),
2696  "conditional: first argument must be scalar. Got " + ind.dim()+ " instead.");
2697 
2698  Matrix<Scalar> ret = x_default;
2699  for (casadi_int k=0; k<x.size(); ++k) {
2700  ret = if_else(ind==k, x[k], ret, short_circuit);
2701  }
2702  return ret;
2703  }
2704 
2705  template<typename Scalar>
2706  Matrix<Scalar> Matrix<Scalar>::heaviside(const Matrix<Scalar>& x) {
2707  return (1+sign(x))/2;
2708  }
2709 
2710  template<typename Scalar>
2711  Matrix<Scalar> Matrix<Scalar>::rectangle(const Matrix<Scalar>& x) {
2712  return 0.5*(sign(x+0.5)-sign(x-0.5));
2713  }
2714 
2715  template<typename Scalar>
2716  Matrix<Scalar> Matrix<Scalar>::triangle(const Matrix<Scalar>& x) {
2717  return rectangle(x/2)*(1-fabs(x));
2718  }
2719 
2720  template<typename Scalar>
2721  Matrix<Scalar> Matrix<Scalar>::ramp(const Matrix<Scalar>& x) {
2722  return x*heaviside(x);
2723  }
2724 
2725  template<typename Scalar>
2726  Matrix<Scalar> Matrix<Scalar>::
2727  gauss_quadrature(const Matrix<Scalar> &f,
2728  const Matrix<Scalar> &x, const Matrix<Scalar> &a,
2729  const Matrix<Scalar> &b, casadi_int order) {
2730  return gauss_quadrature(f, x, a, b, order, Matrix<Scalar>());
2731  }
2732 
2733  template<typename Scalar>
2734  Matrix<Scalar> Matrix<Scalar>::gauss_quadrature(const Matrix<Scalar>& f,
2735  const Matrix<Scalar>& x,
2736  const Matrix<Scalar>& a,
2737  const Matrix<Scalar>& b, casadi_int order,
2738  const Matrix<Scalar>& w) {
2739  casadi_error("'gauss_quadrature' not defined for " + type_name());
2740  return Matrix<Scalar>();
2741  }
2742 
2743  template<typename Scalar>
2744  Matrix<Scalar> Matrix<Scalar>::simplify(const Matrix<Scalar> &x) {
2745  return x;
2746  }
2747 
2748  template<typename Scalar>
2749  Matrix<Scalar> Matrix<Scalar>::transform(const Matrix<Scalar> &x, const Dict& opts) {
2750  casadi_error("'transform' not defined for " + type_name());
2751  }
2752 
2753  template<typename Scalar>
2754  Matrix<Scalar> Matrix<Scalar>::transform(const Matrix<Scalar> &x,
2755  const std::vector<std::vector<GenericType> >& passes, const Dict& opts) {
2756  casadi_error("'transform' not defined for " + type_name());
2757  }
2758 
2759  template<typename Scalar>
2760  std::vector<Matrix<Scalar> > Matrix<Scalar>::transform(const std::vector<Matrix<Scalar> >& x,
2761  const Dict& opts) {
2762  casadi_error("'transform' not defined for " + type_name());
2763  }
2764 
2765  template<typename Scalar>
2766  std::vector<Matrix<Scalar> > Matrix<Scalar>::transform(const std::vector<Matrix<Scalar> >& x,
2767  const std::vector<std::vector<GenericType> >& passes, const Dict& opts) {
2768  casadi_error("'transform' not defined for " + type_name());
2769  }
2770 
2771  template<typename Scalar>
2772  Matrix<Scalar> Matrix<Scalar>::substitute(const Matrix<Scalar>& ex,
2773  const Matrix<Scalar>& v,
2774  const Matrix<Scalar>& vdef) {
2775  casadi_error("'substitute' not defined for " + type_name());
2776  return Matrix<Scalar>();
2777  }
2778 
2779  template<typename Scalar>
2780  std::vector<Matrix<Scalar> >
2781  Matrix<Scalar>::substitute(const std::vector<Matrix<Scalar> >& ex,
2782  const std::vector<Matrix<Scalar> >& v,
2783  const std::vector<Matrix<Scalar> >& vdef) {
2784  casadi_error("'substitute' not defined for " + type_name());
2785  return std::vector<Matrix<Scalar> >();
2786  }
2787 
2788  template<typename Scalar>
2789  void Matrix<Scalar>::substitute_inplace(const std::vector<Matrix<Scalar> >& v,
2790  std::vector<Matrix<Scalar> >& vdef,
2791  std::vector<Matrix<Scalar> >& ex,
2792  bool reverse) {
2793  casadi_error("'substitute_inplace' not defined for " + type_name());
2794  }
2795 
2796  template<typename Scalar>
2797  void Matrix<Scalar>::extract_parametric(const Matrix<Scalar> &expr,
2798  const Matrix<Scalar>& par,
2799  Matrix<Scalar>& expr_ret,
2800  std::vector<Matrix<Scalar> >& symbols,
2801  std::vector< Matrix<Scalar> >& parametric,
2802  const Dict& opts) {
2803  casadi_error("'extract_parametric' not defined for " + type_name());
2804  }
2805 
2806  template<typename Scalar>
2807  void Matrix<Scalar>::separate_linear(const Matrix<Scalar> &expr,
2808  const Matrix<Scalar> &sym_lin, const Matrix<Scalar> &sym_const,
2809  Matrix<Scalar>& expr_const, Matrix<Scalar>& expr_lin, Matrix<Scalar>& expr_nonlin) {
2810  casadi_error("'separate_linear' not defined for " + type_name());
2811  }
2812 
2813  template<typename Scalar>
2814  bool Matrix<Scalar>::depends_on(const Matrix<Scalar> &x, const Matrix<Scalar> &arg) {
2815  casadi_error("'depends_on' not defined for " + type_name());
2816  return false;
2817  }
2818 
2819  template<typename Scalar>
2820  bool Matrix<Scalar>::contains_all(const std::vector <Matrix<Scalar> >& v,
2821  const std::vector <Matrix<Scalar> > &n) {
2822  casadi_error("'contains_all' not defined for " + type_name());
2823  return false;
2824  }
2825 
2826  template<typename Scalar>
2827  bool Matrix<Scalar>::contains_any(const std::vector<Matrix<Scalar> >& v,
2828  const std::vector <Matrix<Scalar> > &n) {
2829  casadi_error("'contains_any' not defined for " + type_name());
2830  return false;
2831  }
2832 
2833  template<typename Scalar>
2834  std::vector< Matrix<Scalar> > Matrix<Scalar>::cse(const std::vector< Matrix<Scalar> >& e) {
2835  casadi_error("'cse' not defined for " + type_name());
2836  return {};
2837  }
2838 
2839 
2840  template<typename Scalar>
2841  Matrix<Scalar> Matrix<Scalar>::
2842  jacobian(const Matrix<Scalar> &f, const Matrix<Scalar> &x, const Dict& opts) {
2843  casadi_error("'jacobian' not defined for " + type_name());
2844  return Matrix<Scalar>();
2845  }
2846 
2847  template<typename Scalar>
2848  Matrix<Scalar> Matrix<Scalar>::hessian(const Matrix<Scalar> &f,
2849  const Matrix<Scalar> &x,
2850  const Dict& opts) {
2851  casadi_error("'hessian' not defined for " + type_name());
2852  return Matrix<Scalar>();
2853  }
2854 
2855  template<typename Scalar>
2856  Matrix<Scalar> Matrix<Scalar>::hessian(const Matrix<Scalar> &f,
2857  const Matrix<Scalar> &x,
2858  Matrix<Scalar> &g,
2859  const Dict& opts) {
2860  casadi_error("'hessian' not defined for " + type_name());
2861  return Matrix<Scalar>();
2862  }
2863 
2864  template<typename Scalar>
2865  std::vector<std::vector<Matrix<Scalar> > >
2866  Matrix<Scalar>::
2867  forward(const std::vector<Matrix<Scalar> > &ex,
2868  const std::vector<Matrix<Scalar> > &arg,
2869  const std::vector<std::vector<Matrix<Scalar> > > &v,
2870  const Dict& opts) {
2871  casadi_error("'forward' not defined for " + type_name());
2872  }
2873 
2874  template<typename Scalar>
2875  std::vector<std::vector<Matrix<Scalar> > >
2876  Matrix<Scalar>::
2877  reverse(const std::vector<Matrix<Scalar> > &ex,
2878  const std::vector<Matrix<Scalar> > &arg,
2879  const std::vector<std::vector<Matrix<Scalar> > > &v,
2880  const Dict& opts) {
2881  casadi_error("'reverse' not defined for " + type_name());
2882  }
2883 
2884  template<typename Scalar>
2885  std::vector<bool>
2886  Matrix<Scalar>::which_depends(const Matrix<Scalar> &expr, const Matrix<Scalar> &var,
2887  casadi_int order, bool tr) {
2888  casadi_error("'which_depends' not defined for " + type_name());
2889  return std::vector<bool>();
2890  }
2891 
2892  template<typename Scalar>
2893  Sparsity
2894  Matrix<Scalar>::jacobian_sparsity(const Matrix<Scalar> &f, const Matrix<Scalar> &x) {
2895  casadi_error("'jacobian_sparsity' not defined for " + type_name());
2896  return Sparsity();
2897  }
2898 
2899  template<typename Scalar>
2900  Matrix<Scalar> Matrix<Scalar>::taylor(const Matrix<Scalar>& f,
2901  const Matrix<Scalar>& x,
2902  const Matrix<Scalar>& a, casadi_int order) {
2903  casadi_error("'taylor' not defined for " + type_name());
2904  return Matrix<Scalar>();
2905  }
2906 
2907  template<typename Scalar>
2908  Matrix<Scalar> Matrix<Scalar>::mtaylor(const Matrix<Scalar>& f,
2909  const Matrix<Scalar>& x,
2910  const Matrix<Scalar>& a, casadi_int order) {
2911  casadi_error("'mtaylor' not defined for " + type_name());
2912  return Matrix<Scalar>();
2913  }
2914 
2915  template<typename Scalar>
2916  Matrix<Scalar> Matrix<Scalar>::mtaylor(const Matrix<Scalar>& f,
2917  const Matrix<Scalar>& x,
2918  const Matrix<Scalar>& a, casadi_int order,
2919  const std::vector<casadi_int>&order_contributions) {
2920  casadi_error("'mtaylor' not defined for " + type_name());
2921  return Matrix<Scalar>();
2922  }
2923 
2924  template<typename Scalar>
2925  casadi_int Matrix<Scalar>::n_nodes(const Matrix<Scalar>& x) {
2926  casadi_error("'n_nodes' not defined for " + type_name());
2927  return 0;
2928  }
2929 
2930  template<typename Scalar>
2931  std::string
2932  Matrix<Scalar>::print_operator(const Matrix<Scalar>& x,
2933  const std::vector<std::string>& args) {
2934  casadi_error("'print_operator' not defined for " + type_name());
2935  return std::string();
2936  }
2937 
2938  template<typename Scalar>
2939  std::vector<Matrix<Scalar> > Matrix<Scalar>::symvar(const Matrix<Scalar>& x) {
2940  casadi_error("'symvar' not defined for " + type_name());
2941  return std::vector<Matrix<Scalar> >();
2942  }
2943 
2944  template<typename Scalar>
2945  void Matrix<Scalar>::extract(std::vector<Matrix<Scalar>>& ex, std::vector<Matrix<Scalar>>& v,
2946  std::vector<Matrix<Scalar>>& vdef, const Dict& opts) {
2947  casadi_error("'extract' not defined for " + type_name());
2948  }
2949 
2950  template<typename Scalar>
2951  void Matrix<Scalar>::shared(std::vector<Matrix<Scalar> >& ex,
2952  std::vector<Matrix<Scalar> >& v,
2953  std::vector<Matrix<Scalar> >& vdef,
2954  const std::string& v_prefix,
2955  const std::string& v_suffix) {
2956  casadi_error("'shared' not defined for " + type_name());
2957  }
2958 
2959  template<typename Scalar>
2960  Matrix<Scalar> Matrix<Scalar>::poly_coeff(const Matrix<Scalar>& f,
2961  const Matrix<Scalar>&x) {
2962  casadi_error("'poly_coeff' not defined for " + type_name());
2963  }
2964 
2965  template<typename Scalar>
2966  Matrix<Scalar> Matrix<Scalar>::poly_roots(const Matrix<Scalar>& p) {
2967  casadi_error("'poly_roots' not defined for " + type_name());
2968  }
2969 
2970  template<typename Scalar>
2971  Matrix<Scalar> Matrix<Scalar>::eig_symbolic(const Matrix<Scalar>& m) {
2972  casadi_error("'eig_symbolic' not defined for " + type_name());
2973  }
2974 
2975  template<typename Scalar>
2976  DM Matrix<Scalar>::evalf(const Matrix<Scalar>& m) {
2977  Function f("f", std::vector<SX>{}, std::vector<SX>{m});
2978  return f(std::vector<DM>{})[0];
2979  }
2980 
2981  template<typename Scalar>
2982  Matrix<Scalar> Matrix<Scalar>::sparsify(const Matrix<Scalar>& x, double tol) {
2983  // Quick return if there are no entries to be removed
2984  bool remove_nothing = true;
2985  for (auto it=x.nonzeros().begin(); it!=x.nonzeros().end() && remove_nothing; ++it) {
2986  remove_nothing = !casadi_limits<Scalar>::is_almost_zero(*it, tol);
2987  }
2988  if (remove_nothing) return x;
2989 
2990  // Get the current sparsity pattern
2991  casadi_int size1 = x.size1();
2992  casadi_int size2 = x.size2();
2993  const casadi_int* colind = x.colind();
2994  const casadi_int* row = x.row();
2995 
2996  // Construct the new sparsity pattern
2997  std::vector<casadi_int> new_colind(1, 0), new_row;
2998  std::vector<Scalar> new_data;
2999 
3000  // Loop over the columns
3001  for (casadi_int cc=0; cc<size2; ++cc) {
3002  // Loop over existing nonzeros
3003  for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
3004  // If it is not known to be a zero
3005  if (!casadi_limits<Scalar>::is_almost_zero(x->at(el), tol)) {
3006  // Save the nonzero in its new location
3007  new_data.push_back(x->at(el));
3008 
3009  // Add to pattern
3010  new_row.push_back(row[el]);
3011  }
3012  }
3013  // Save the new column offset
3014  new_colind.push_back(new_row.size());
3015  }
3016 
3017  // Construct the sparsity pattern
3018  Sparsity sp(size1, size2, new_colind, new_row);
3019 
3020  // Construct matrix and return
3021  return Matrix<Scalar>(sp, new_data);
3022  }
3023 
3024 
3025  template<typename Scalar>
3026  std::vector<Matrix<Scalar> > Matrix<Scalar>::get_input(const Function& f) {
3027  casadi_error("'get_input' not defined for " + type_name());
3028  }
3029 
3030  template<typename Scalar>
3031  std::vector<Matrix<Scalar> > Matrix<Scalar>::get_free(const Function& f) {
3032  casadi_error("'get_free' not defined for " + type_name());
3033  }
3034 
3035  template<typename Scalar>
3036  Matrix<Scalar>::operator double() const {
3037  casadi_assert_dev(is_scalar());
3038  return static_cast<double>(scalar());
3039  }
3040 
3041  template<typename Scalar>
3042  Matrix<Scalar>::operator casadi_int() const {
3043  casadi_assert_dev(is_scalar());
3044  return static_cast<casadi_int>(scalar());
3045  }
3046 
3047  template<typename Scalar>
3048  Matrix<Scalar> Matrix<Scalar>::_sym(const std::string& name, const Sparsity& sp) {
3049  casadi_error("'sym' not defined for " + type_name());
3050  }
3051 
3052  template<typename Scalar>
3053  Matrix<Scalar> Matrix<Scalar>::rand(const Sparsity& sp) { // NOLINT(runtime/threadsafe_fn)
3054 
3055  casadi_error("'rand' not defined for " + type_name());
3056  }
3057 
3058  template<typename Scalar>
3059  std::string Matrix<Scalar>::serialize() const {
3060  std::stringstream ss;
3061  serialize(ss);
3062  return ss.str();
3063  }
3064 
3065  template<typename Scalar>
3066  void Matrix<Scalar>::serialize(SerializingStream& s) const {
3067  s.pack("Matrix::sparsity", sparsity());
3068  s.pack("Matrix::nonzeros", nonzeros());
3069  }
3070 
3071  template<typename Scalar>
3072  Matrix<Scalar> Matrix<Scalar>::deserialize(DeserializingStream& s) {
3074  s.unpack("Matrix::sparsity", sp);
3075  std::vector<Scalar> nz;
3076  s.unpack("Matrix::nonzeros", nz);
3077  return Matrix<Scalar>(sp, nz, false);
3078  }
3079 
3080  template<typename Scalar>
3081  void Matrix<Scalar>::serialize(std::ostream &stream) const {
3082  SerializingStream s(stream);
3083  serialize(s);
3084  }
3085 
3086  template<typename Scalar>
3087  Matrix<Scalar> Matrix<Scalar>::deserialize(std::istream &stream) {
3088  DeserializingStream s(stream);
3089  return Matrix<Scalar>::deserialize(s);
3090  }
3091 
3092  template<typename Scalar>
3093  Matrix<Scalar> Matrix<Scalar>::deserialize(const std::string& s) {
3094  std::stringstream ss;
3095  ss << s;
3096  return deserialize(ss);
3097  }
3098 
3099 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
3100  template<typename Scalar>
3101  std::mutex& Matrix<Scalar>::get_mutex_temp() {
3102  casadi_error("'get_mutex_temp' not defined for " + type_name());
3103  }
3104 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
3105 
3106 } // namespace casadi
3107 
3108 #endif // CASADI_MATRIX_IMPL_HPP
Function object.
Definition: function.hpp:126
Sparsity sparsity() const
Get the sparsity pattern.
bool is_dense() const
Check if the matrix is dense, i.e. nnz() equals numel()
bool is_column() const
Check if the matrix is a column vector (i.e. size2()==1)
casadi_int row(casadi_int el) const
Get the sparsity pattern. See the Sparsity class for details.
bool is_vector() const
Check if the matrix is a row or column vector.
casadi_int nnz() const
Get the number of structural nonzeros.
casadi_int size2() const
Get the second dimension (i.e. number of columns)
bool is_row() const
Check if the matrix is a row vector (i.e. size1()==1)
casadi_int size1() const
Get the first dimension (i.e. number of rows)
casadi_int colind(casadi_int col) const
Get the sparsity pattern. See the Sparsity class for details.
static Matrix< Scalar > zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
std::pair< casadi_int, casadi_int > size() const
Get the shape as a pair (number of rows, number of columns)
bool is_scalar(bool scalar_and_dense=false) const
Check if the matrix is scalar, i.e. 1-by-1.
Sparse matrix class. SX and DM are specializations.
bool has_nz(casadi_int rr, casadi_int cc) const
Check whether element (rr, cc) is a structural nonzero.
Definition: matrix_impl.hpp:75
void print_split(std::vector< std::string > &nz, std::vector< std::string > &inter) const
String representation of each nonzero and of the shared subexpressions.
Matrix< Scalar > T() const
Transpose the matrix.
static void set_precision(casadi_int precision)
Set the precision, field width and scientific flag used when printing nonzeros.
Definition: matrix_impl.hpp:40
static casadi_int get_precision()
Get the precision, field width and scientific flag used when printing nonzeros.
Definition: matrix_impl.hpp:49
void get(Matrix< Scalar > &m, bool ind1, const Slice &rr) const
Get elements by a single (linear) index.
void resize(casadi_int nrow, casadi_int ncol)
Change the shape in place, keeping nonzeros that remain inside the new bounds.
void print_sparse(std::ostream &stream, bool truncate=true) const
Print as a list of (row, col) -> value triplets, column-major order.
static void set_width(casadi_int width)
Definition: matrix_impl.hpp:43
void clear()
Reset to an empty 0-by-0 matrix, in place.
Matrix()
Empty 0-by-0 matrix.
void set(const Matrix< Scalar > &m, bool ind1, const Slice &rr)
Assign elements by a single (linear) index.
static casadi_int get_width()
Definition: matrix_impl.hpp:52
static bool get_scientific()
Definition: matrix_impl.hpp:55
static std::string type_name()
Name of the class: "DM" or "SX".
void to_file(const std::string &filename, const std::string &format="") const
Write a numerical matrix to a text file (DM only)
static void set_scientific(bool scientific)
Definition: matrix_impl.hpp:46
void disp(std::ostream &stream, bool more=false) const
Print a representation of the object to a stream.
bool __nonzero__() const
Truth value of a 1-by-1 matrix (Python: bool(x))
Definition: matrix_impl.hpp:80
void erase(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, bool ind1=false)
Erase the block at the given rows and columns, leaving structural zeros.
static void rng(casadi_int seed)
Seed the random number generator used by rand.
Definition: matrix_impl.hpp:70
void print_dense(std::ostream &stream, bool truncate=true) const
Print as a dense matrix, one row per line, structural zeros as 00.
void reserve(casadi_int nnz)
Reserve storage for the given number of nonzeros (performance hint, no visible effect)
void set_nz(const Matrix< Scalar > &m, bool ind1, const Slice &k)
Assign structural nonzeros by their position in the nonzero storage.
void print_vector(std::ostream &stream, bool truncate=true) const
Print a column vector as [a, b, ...], structural zeros as 00.
std::string get_str(bool more=false) const
Get the string representation that disp prints.
void get_nz(Matrix< Scalar > &m, bool ind1, const Slice &k) const
Get structural nonzeros by their position in the nonzero storage.
void print_scalar(std::ostream &stream) const
Print a 1-by-1 matrix as a bare number or expression.
Helper class for Serialization.
Class representing a Slice.
Definition: slice.hpp:48
std::vector< casadi_int > all() const
Get a vector of indices.
casadi_int scalar(casadi_int len) const
Get scalar (if is_scalar)
bool is_scalar(casadi_int len) const
Is the slice a scalar.
General sparsity class.
Definition: sparsity.hpp:200
std::vector< casadi_int > find(bool ind1=SWIG_IND1) const
Flat (column-major) element index of every nonzero.
Sparsity sub(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, std::vector< casadi_int > &mapping, bool ind1=false) const
Pattern of the submatrix with rows rr and columns cc.
casadi_int numel() const
Total number of entries, structural zeros included, i.e. size1()*size2()
casadi_int size1() const
Number of rows.
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern.
Sparsity T() const
Transposed pattern.
bool is_column() const
Check whether the pattern is a column vector, i.e. size2() == 1.
static Sparsity triplet(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, std::vector< casadi_int > &mapping, bool invert_mapping)
Create a sparsity pattern from the (row, col) index of every nonzero.
casadi_int nnz() const
Number of structural nonzeros.
casadi_int size2() const
Number of columns.
casadi_int row(casadi_int el) const
Row index of nonzero el.
bool is_empty(bool both=false) const
Check whether the pattern has a zero dimension.
std::pair< casadi_int, casadi_int > size() const
Shape as a pair (number of rows, number of columns)
casadi_limits class
friend Matrix< Scalar > einstein(const Matrix< Scalar > &A, const Matrix< Scalar > &B, const Matrix< Scalar > &C, const std::vector< casadi_int > &dim_a, const std::vector< casadi_int > &dim_b, const std::vector< casadi_int > &dim_c, const std::vector< casadi_int > &a, const std::vector< casadi_int > &b, const std::vector< casadi_int > &c)
Compute any contraction of two dense tensors, using index/einstein notation.
friend Matrix< Scalar > densify(const Matrix< Scalar > &x)
Make the matrix dense if not already.
friend Matrix< Scalar > cumsum(const Matrix< Scalar > &x, casadi_int axis=-1)
Returns cumulative sum along given axis (MATLAB convention)
const long double alpha[8][8]
The casadi namespace.
Definition: archiver.hpp:32
void einstein_eval(casadi_int n_iter, const std::vector< casadi_int > &iter_dims, const std::vector< casadi_int > &strides_a, const std::vector< casadi_int > &strides_b, const std::vector< casadi_int > &strides_c, const T *a_in, const T *b_in, T *c_in)
Definition: shared.hpp:161
casadi_int einstein_process(const T &A, const T &B, const T &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, std::vector< casadi_int > &iter_dims, std::vector< casadi_int > &strides_a, std::vector< casadi_int > &strides_b, std::vector< casadi_int > &strides_c)
Definition: shared.hpp:35
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
bool is_zero(const T &x)
Matrix< double > DM
Definition: dm_fwd.hpp:33
bool is_regular(const std::vector< T > &v)
Checks if array does not contain NaN or Inf.
Slice CASADI_EXPORT to_slice(const IM &x, bool ind1=false)
Convert IM to Slice.