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>
576  Matrix<Scalar> Matrix<Scalar>::einstein(const Matrix<Scalar>& A, const Matrix<Scalar>& B,
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>
947  Matrix<Scalar>::Matrix(double val) :
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>
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))
1331 
1332  // Return value
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  return triplet(row, col, d, *std::max_element(row.begin(), row.end()),
1466  *std::max_element(col.begin(), col.end()));
1467  }
1468 
1469  template<typename Scalar>
1470  Matrix<Scalar> Matrix<Scalar>::triplet(const std::vector<casadi_int>& row,
1471  const std::vector<casadi_int>& col,
1472  const Matrix<Scalar>& d,
1473  const std::pair<casadi_int, casadi_int>& rc) {
1474  return triplet(row, col, d, rc.first, rc.second);
1475  }
1476 
1477  template<typename Scalar>
1478  Matrix<Scalar> Matrix<Scalar>::triplet(const std::vector<casadi_int>& row,
1479  const std::vector<casadi_int>& col,
1480  const Matrix<Scalar>& d,
1481  casadi_int nrow, casadi_int ncol) {
1482  casadi_assert(col.size()==row.size() && col.size()==d.nnz(),
1483  "Argument error in Matrix<Scalar>::triplet(row, col, d): "
1484  "supplied lists must all be of equal length, but got: "
1485  + str(row.size()) + ", " + str(col.size()) + " and " + str(d.nnz()));
1486  std::vector<casadi_int> mapping;
1487  Sparsity sp = Sparsity::triplet(nrow, ncol, row, col, mapping, false);
1488  return Matrix<Scalar>(sp, d.nz(mapping));
1489  }
1490 
1491  template<typename Scalar>
1492  Matrix<Scalar> Matrix<Scalar>::eye(casadi_int n) {
1493  return Matrix<Scalar>::ones(Sparsity::diag(n));
1494  }
1495 
1496  template<typename Scalar>
1497  Matrix<Scalar> Matrix<Scalar>::inf(const Sparsity& sp) {
1498  casadi_assert(std::numeric_limits<Scalar>::has_infinity,
1499  "Datatype cannot represent infinity");
1500  return Matrix<Scalar>(sp, std::numeric_limits<Scalar>::infinity(), false);
1501  }
1502 
1503 
1504  template<typename Scalar>
1505  Matrix<Scalar> Matrix<Scalar>::inf(const std::pair<casadi_int, casadi_int>& rc) {
1506  return inf(rc.first, rc.second);
1507  }
1508 
1509  template<typename Scalar>
1510  Matrix<Scalar> Matrix<Scalar>::inf(casadi_int nrow, casadi_int ncol) {
1511  return inf(Sparsity::dense(nrow, ncol));
1512  }
1513 
1514  template<typename Scalar>
1515  Matrix<Scalar> Matrix<Scalar>::nan(const Sparsity& sp) {
1516  casadi_assert(std::numeric_limits<Scalar>::has_quiet_NaN,
1517  "Datatype cannot represent not-a-number");
1518  return Matrix<Scalar>(sp, std::numeric_limits<Scalar>::quiet_NaN(), false);
1519  }
1520 
1521  template<typename Scalar>
1522  Matrix<Scalar> Matrix<Scalar>::nan(const std::pair<casadi_int, casadi_int>& rc) {
1523  return nan(rc.first, rc.second);
1524  }
1525 
1526  template<typename Scalar>
1527  Matrix<Scalar> Matrix<Scalar>::nan(casadi_int nrow, casadi_int ncol) {
1528  return nan(Sparsity::dense(nrow, ncol));
1529  }
1530 
1531  template<typename Scalar>
1532  bool Matrix<Scalar>::is_regular() const {
1533  return casadi::is_regular(nonzeros_);
1534  }
1535 
1536  template<typename Scalar>
1537  bool Matrix<Scalar>::is_smooth() const {
1538  return true;
1539  }
1540 
1541  template<typename Scalar>
1542  casadi_int Matrix<Scalar>::element_hash() const {
1543  casadi_error("'element_hash' not defined for " + type_name());
1544  }
1545 
1546  template<typename Scalar>
1547  bool Matrix<Scalar>::is_leaf() const {
1548  casadi_error("'is_leaf' not defined for " + type_name());
1549  }
1550 
1551  template<typename Scalar>
1552  bool Matrix<Scalar>::is_commutative() const {
1553  casadi_error("'is_commutative' not defined for " + type_name());
1554  }
1555 
1556  template<typename Scalar>
1557  bool Matrix<Scalar>::is_symbolic() const {
1558  return false;
1559  }
1560 
1561  template<typename Scalar>
1562  casadi_int Matrix<Scalar>::op() const {
1563  casadi_error("'op' not defined for " + type_name());
1564  }
1565 
1566  template<typename Scalar>
1567  bool Matrix<Scalar>::is_op(casadi_int k) const {
1568  casadi_error("'is_op' not defined for " + type_name());
1569  }
1570 
1571  template<typename Scalar>
1572  void Matrix<Scalar>::export_code(const std::string& lang,
1573  std::ostream &stream, const Dict& options) const {
1574  casadi_error("'export_code' not defined for " + type_name());
1575  }
1576 
1577  template<typename Scalar>
1578  bool Matrix<Scalar>::is_valid_input() const {
1579  return false;
1580  }
1581 
1582  template<typename Scalar>
1583  bool Matrix<Scalar>::has_duplicates() const {
1584  casadi_error("'has_duplicates' not defined for " + type_name());
1585  }
1586 
1587  template<typename Scalar>
1588  void Matrix<Scalar>::reset_input() const {
1589  casadi_error("'reset_input' not defined for " + type_name());
1590  }
1591 
1592  template<typename Scalar>
1593  Matrix<double> Matrix<Scalar>::from_file(const std::string& filename,
1594  const std::string& format_hint) {
1595  casadi_error("'from_file' not defined for " + type_name());
1596  }
1597 
1598  template<typename Scalar>
1599  bool Matrix<Scalar>::is_integer() const {
1600  // Look for non-integers
1601  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_integer(e)) return false;
1602 
1603  // Integer if reached this point
1604  return true;
1605  }
1606 
1607  template<typename Scalar>
1608  bool Matrix<Scalar>::is_constant() const {
1609  // Look for non-constants
1610  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_constant(e)) return false;
1611 
1612  // Constant if we reach this point
1613  return true;
1614  }
1615 
1616  template<typename Scalar>
1617  bool Matrix<Scalar>::is_call() const {
1618  casadi_assert(is_scalar(), "'is_call' only defined for scalar expressions");
1619 
1620  return false;
1621  }
1622 
1623  template<typename Scalar>
1624  bool Matrix<Scalar>::is_output() const {
1625  casadi_assert(is_scalar(), "'is_output' only defined for scalar expressions");
1626 
1627  return false;
1628  }
1629 
1630  template<typename Scalar>
1631  Matrix<Scalar> Matrix<Scalar>::get_output(casadi_int oind) const {
1632  casadi_error("'get_output' not defined for " + type_name());
1633  }
1634 
1635  template<typename Scalar>
1636  bool Matrix<Scalar>::has_output() const {
1637  casadi_assert(is_scalar(), "'has_output' only defined for scalar expressions");
1638 
1639  return false;
1640  }
1641 
1642  template<typename Scalar>
1643  Function Matrix<Scalar>::which_function() const {
1644  casadi_error("'which_function' not defined for " + type_name());
1645  }
1646 
1647  template<typename Scalar>
1648  casadi_int Matrix<Scalar>::which_output() const {
1649  casadi_error("'which_output' not defined for " + type_name());
1650  }
1651 
1652  template<typename Scalar>
1653  bool Matrix<Scalar>::is_one() const {
1654  if (!is_dense()) return false;
1655 
1656  // Look for non-ones
1657  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_one(e)) return false;
1658 
1659  return true;
1660  }
1661 
1662  template<typename Scalar>
1663  bool Matrix<Scalar>::is_minus_one() const {
1664  if (!is_dense()) return false;
1665 
1666  // Look for non-minus-ones
1667  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_minus_one(e)) return false;
1668 
1669  return true;
1670  }
1671 
1672  template<typename Scalar>
1673  bool Matrix<Scalar>::is_half() const {
1674  if (!is_dense()) return false;
1675 
1676  // Look for non-halves
1677  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_half(e)) return false;
1678 
1679  return true;
1680  }
1681 
1682  template<typename Scalar>
1683  bool Matrix<Scalar>::is_value(double val) const {
1684  if (val==0.0) return is_zero();
1685  if (!is_dense()) return false;
1686 
1687  // Look for non-values
1688  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_value(e, val)) return false;
1689 
1690  return true;
1691  }
1692 
1693  template<typename Scalar>
1694  bool Matrix<Scalar>::is_inf() const {
1695  if (!is_dense()) return false;
1696 
1697  // Look for inf
1698  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_inf(e)) return false;
1699 
1700  return true;
1701  }
1702 
1703  template<typename Scalar>
1704  bool Matrix<Scalar>::is_minus_inf() const {
1705  if (!is_dense()) return false;
1706 
1707  // Look for -inf
1708  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_minus_inf(e)) return false;
1709 
1710  return true;
1711  }
1712 
1713  template<typename Scalar>
1714  bool Matrix<Scalar>::is_nonnegative() const {
1715  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_nonnegative(e)) return false;
1716  return true;
1717  }
1718 
1719  template<typename Scalar>
1720  bool Matrix<Scalar>::is_zero() const {
1721 
1722  // Look for non-zeros
1723  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_zero(e)) return false;
1724 
1725  return true;
1726  }
1727 
1728  template<typename Scalar>
1729  bool Matrix<Scalar>::is_eye() const {
1730 
1731  // Make sure that the matrix is diagonal
1732  if (!sparsity().is_diag()) return false;
1733 
1734  // Make sure that all entries are one
1735  for (auto&& e : nonzeros()) if (!casadi_limits<Scalar>::is_one(e)) return false;
1736 
1737  return true;
1738  }
1739 
1740  template<typename Scalar>
1741  bool Matrix<Scalar>::is_equal(const Matrix<Scalar> &x, const Matrix<Scalar> &y,
1742  casadi_int depth) {
1743  // Assert matching dimensions
1744  casadi_assert(x.size() == y.size(), "Dimension mismatch");
1745 
1746  // Project to union of patterns and call recursively if different sparsity
1747  if (x.sparsity() != y.sparsity()) {
1748  Sparsity sp = x.sparsity() + y.sparsity();
1749  return is_equal(project(x, sp), project(y, sp), depth);
1750  }
1751 
1752  // Check individual elements
1753  auto y_it = y.nonzeros().begin();
1754  for (auto&& e : x.nonzeros()) {
1755  if (!casadi_limits<Scalar>::is_equal(e, *y_it++, depth)) return false;
1756  }
1757 
1758  // True if reched this point
1759  return true;
1760  }
1761 
1762  // To avoid overloaded function name conflicts
1763  template<typename Scalar>
1764  inline Matrix<Scalar> mmin_nonstatic(const Matrix<Scalar> &x) {
1765  if (x.is_empty()) return Matrix<Scalar>();
1766  return casadi_mmin(x.ptr(), x.nnz(), x.is_dense());
1767  }
1768 
1769  template<typename Scalar>
1770  Matrix<Scalar> Matrix<Scalar>::mmin(const Matrix<Scalar> &x) {
1771  return mmin_nonstatic(x);
1772  }
1773 
1774  // To avoid overloaded function name conflicts
1775  template<typename Scalar>
1776  inline Matrix<Scalar> mmax_nonstatic(const Matrix<Scalar> &x) {
1777  if (x.is_empty()) return Matrix<Scalar>();
1778  return casadi_mmax(x.ptr(), x.nnz(), x.is_dense());
1779  }
1780 
1781  template<typename Scalar>
1782  Matrix<Scalar> Matrix<Scalar>::mmax(const Matrix<Scalar> &x) {
1783  return mmax_nonstatic(x);
1784  }
1785 
1786  template<typename Scalar>
1787  bool Matrix<Scalar>::has_zeros() const {
1788  // Check if the structural nonzero is known to be zero
1789  for (auto&& e : nonzeros()) if (casadi_limits<Scalar>::is_zero(e)) return true;
1790 
1791  // No known zeros amongst the structurally nonzero entries
1792  return false;
1793  }
1794 
1795  template<typename Scalar>
1796  std::vector<Scalar> Matrix<Scalar>::get_nonzeros() const {
1797  return nonzeros_;
1798  }
1799 
1800  template<typename Scalar>
1801  std::vector<Scalar> Matrix<Scalar>::get_elements() const {
1802  return static_cast< std::vector<Scalar>>(*this);
1803  }
1804 
1805  template<typename Scalar>
1806  std::string Matrix<Scalar>::name() const {
1807  casadi_error("'name' not defined for " + type_name());
1808  }
1809 
1810  template<typename Scalar>
1811  Matrix<Scalar> Matrix<Scalar>::dep(casadi_int ch) const {
1812  casadi_error("'dep' not defined for " + type_name());
1813  }
1814 
1815  template<typename Scalar>
1816  casadi_int Matrix<Scalar>::n_dep() const {
1817  casadi_error("'n_dep' not defined for " + type_name());
1818  }
1819 
1820  template<typename Scalar>
1821  Matrix<Scalar> Matrix<Scalar>::rand( // NOLINT(runtime/threadsafe_fn)
1822  casadi_int nrow,
1823  casadi_int ncol) {
1824  return rand(Sparsity::dense(nrow, ncol)); // NOLINT(runtime/threadsafe_fn)
1825  }
1826 
1827  template<typename Scalar>
1828  Matrix<Scalar> Matrix<Scalar>::rand( // NOLINT(runtime/threadsafe_fn)
1829  const std::pair<casadi_int, casadi_int>& rc) {
1830  return rand(rc.first, rc.second); // NOLINT(runtime/threadsafe_fn)
1831  }
1832 
1833  template<typename Scalar>
1834  Matrix<Scalar> Matrix<Scalar>::project(const Matrix<Scalar>& x,
1835  const Sparsity& sp, bool intersect) {
1836  if (intersect) {
1837  return project(x, sp.intersect(x.sparsity()), false);
1838  } else {
1839  casadi_assert(sp.size()==x.size(), "Dimension mismatch");
1840  Matrix<Scalar> ret = Matrix<Scalar>::zeros(sp);
1841  std::vector<Scalar> w(x.size1());
1842  casadi_project(x.ptr(), x.sparsity(), ret.ptr(), sp, get_ptr(w));
1843  return ret;
1844  }
1845  }
1846 
1847  template<typename Scalar>
1848  void Matrix<Scalar>::set_max_depth(casadi_int eq_depth) {
1849  casadi_error("'set_max_depth' not defined for " + type_name());
1850  }
1851 
1852  template<typename Scalar>
1853  casadi_int Matrix<Scalar>::get_max_depth() {
1854  casadi_error("'get_max_depth' not defined for " + type_name());
1855  }
1856 
1857  template<typename Scalar>
1858  Matrix<Scalar> Matrix<Scalar>::det(const Matrix<Scalar>& x) {
1859  casadi_int n = x.size2();
1860  casadi_assert(n == x.size1(), "matrix must be square");
1861 
1862  // Trivial return if scalar
1863  if (x.is_scalar()) return x;
1864 
1865  // Trivial case 2 x 2
1866  if (n==2) return x(0, 0) * x(1, 1) - x(0, 1) * x(1, 0);
1867 
1868  // Return expression
1869  Matrix<Scalar> ret = 0;
1870 
1871  // Find out which is the best direction to expand along
1872 
1873  // Build up an IM with ones on the non-zeros
1874  Matrix<casadi_int> sp = IM::ones(x.sparsity());
1875 
1876  // Have a count of the nonzeros for each row
1877  Matrix<casadi_int> row_count = Matrix<casadi_int>::sum2(sp);
1878 
1879  // A blank row? determinant is structurally zero
1880  if (!row_count.is_dense()) return 0;
1881 
1882  // Have a count of the nonzeros for each col
1883  Matrix<casadi_int> col_count = Matrix<casadi_int>::sum1(sp).T();
1884 
1885  // A blank col? determinant is structurally zero
1886  if (!row_count.is_dense()) return 0;
1887 
1888  casadi_int min_row = std::distance(row_count.nonzeros().begin(),
1889  std::min_element(row_count.nonzeros().begin(),
1890  row_count.nonzeros().end()));
1891  casadi_int min_col = std::distance(col_count.nonzeros().begin(),
1892  std::min_element(col_count.nonzeros().begin(),
1893  col_count.nonzeros().end()));
1894 
1895  if (min_row <= min_col) {
1896  // Expand along row j
1897  casadi_int j = row_count.sparsity().row(min_row);
1898 
1899  Matrix<Scalar> row = x(j, Slice(0, n));
1900 
1901  std::vector< casadi_int > col_i = row.sparsity().get_col();
1902 
1903  for (casadi_int k=0; k<row.nnz(); ++k) {
1904  // Sum up the cofactors
1905  ret += row->at(k)*cofactor(x, col_i.at(k), j);
1906  }
1907  return ret;
1908  } else {
1909  // Expand along col i
1910  casadi_int i = col_count.sparsity().row(min_col);
1911 
1912  Matrix<Scalar> col = x(Slice(0, n), i);
1913 
1914  const casadi_int* row_i = col.row();
1915 
1916  for (casadi_int k=0; k<col.nnz(); ++k) {
1917  // Sum up the cofactors
1918  ret += col->at(k)*cofactor(x, i, row_i[k]);
1919  }
1920  return ret;
1921  }
1922 
1923  }
1924 
1925  template<typename Scalar>
1926  Matrix<Scalar> Matrix<Scalar>::
1927  det(const Matrix<Scalar>& x, const std::string& lsolver, const Dict& dict) {
1928  casadi_error("'det' with plugin not defined for " + type_name());
1929  return Matrix<Scalar>();
1930  }
1931 
1932  template<typename Scalar>
1933  Matrix<Scalar> Matrix<Scalar>::sum2(const Matrix<Scalar>& x) {
1934  return mtimes(x, Matrix<Scalar>::ones(x.size2(), 1));
1935  }
1936 
1937  template<typename Scalar>
1938  Matrix<Scalar> Matrix<Scalar>::sum1(const Matrix<Scalar>& x) {
1939  return mtimes(Matrix<Scalar>::ones(1, x.size1()), x);
1940  }
1941 
1942  template<typename Scalar>
1943  Matrix<Scalar> Matrix<Scalar>::minor(const Matrix<Scalar>& x,
1944  casadi_int i, casadi_int j) {
1945  casadi_int n = x.size2();
1946  casadi_assert(n == x.size1(), "minor: matrix must be square");
1947 
1948  // Trivial return if scalar
1949  if (n==1) return 1;
1950 
1951  // Remove col i and row j
1952  Matrix<Scalar> M = Matrix<Scalar>(n-1, n-1);
1953 
1954  std::vector<casadi_int> col = x.sparsity().get_col();
1955  const casadi_int* row = x.sparsity().row();
1956 
1957  for (casadi_int k=0; k<x.nnz(); ++k) {
1958  casadi_int i1 = col[k];
1959  casadi_int j1 = row[k];
1960 
1961  if (i1 == i || j1 == j) continue;
1962 
1963  casadi_int i2 = (i1<i)?i1:i1-1;
1964  casadi_int j2 = (j1<j)?j1:j1-1;
1965 
1966  M(j2, i2) = x(j1, i1);
1967  }
1968  return det(M);
1969  }
1970 
1971  template<typename Scalar>
1972  Matrix<Scalar> Matrix<Scalar>::cofactor(const Matrix<Scalar>& A, casadi_int i, casadi_int j) {
1973 
1974  // Calculate the i, j minor
1975  Matrix<Scalar> minor_ij = minor(A, i, j);
1976  // Calculate the cofactor
1977  casadi_int sign_i = 1-2*((i+j) % 2);
1978 
1979  return sign_i * minor_ij;
1980  }
1981 
1982  template<typename Scalar>
1983  Matrix<Scalar> Matrix<Scalar>::adj(const Matrix<Scalar>& x) {
1984  casadi_int n = x.size2();
1985  casadi_assert(n == x.size1(), "adj: matrix must be square");
1986 
1987  // Temporary placeholder
1988  Matrix<Scalar> temp;
1989 
1990  // Cofactor matrix
1991  Matrix<Scalar> C = Matrix<Scalar>(n, n);
1992  for (casadi_int i=0; i<n; ++i)
1993  for (casadi_int j=0; j<n; ++j) {
1994  temp = cofactor(x, i, j);
1995  if (!temp.is_zero()) C(j, i) = temp;
1996  }
1997 
1998  return C.T();
1999  }
2000 
2001  template<typename Scalar>
2002  Matrix<Scalar> Matrix<Scalar>::inv_minor(const Matrix<Scalar>& x) {
2003  // laplace formula
2004  return adj(x)/det(x);
2005  }
2006 
2007  template<typename Scalar>
2008  Matrix<Scalar> Matrix<Scalar>::reshape(const Matrix<Scalar>& x,
2009  casadi_int nrow, casadi_int ncol) {
2010  Sparsity sp = Sparsity::reshape(x.sparsity(), nrow, ncol);
2011  return Matrix<Scalar>(sp, x.nonzeros(), false);
2012  }
2013 
2014  template<typename Scalar>
2015  Matrix<Scalar> Matrix<Scalar>::reshape(const Matrix<Scalar>& x, const Sparsity& sp) {
2016  // quick return if already the right shape
2017  if (sp==x.sparsity()) return x;
2018 
2019  // make sure that the patterns match
2020  casadi_assert_dev(sp.is_reshape(x.sparsity()));
2021 
2022  return Matrix<Scalar>(sp, x.nonzeros(), false);
2023  }
2024 
2025  template<typename Scalar>
2026  Matrix<Scalar> Matrix<Scalar>::sparsity_cast(const Matrix<Scalar>& x, const Sparsity& sp) {
2027  // quick return if already the right shape
2028  if (sp==x.sparsity()) return x;
2029 
2030  casadi_assert_dev(sp.nnz()==x.nnz());
2031 
2032  return Matrix<Scalar>(sp, x.nonzeros(), false);
2033  }
2034 
2035  template<typename Scalar>
2036  Matrix<Scalar> Matrix<Scalar>::trace(const Matrix<Scalar>& x) {
2037  casadi_assert(x.is_square(), "trace: must be square");
2038  Scalar res=0;
2039  const Scalar* d=x.ptr();
2040  casadi_int size2 = x.size2();
2041  const casadi_int *colind=x.colind(), *row=x.row();
2042  for (casadi_int c=0; c<size2; c++) {
2043  for (casadi_int k=colind[c]; k!=colind[c+1]; ++k) {
2044  if (row[k]==c) {
2045  res += d[k];
2046  }
2047  }
2048  }
2049  return res;
2050  }
2051 
2052  template<typename Scalar>
2053  Matrix<Scalar>
2054  Matrix<Scalar>::blockcat(const std::vector< std::vector<Matrix<Scalar> > > &v) {
2055  std::vector< Matrix<Scalar> > ret;
2056  for (casadi_int i=0; i<v.size(); ++i)
2057  ret.push_back(horzcat(v[i]));
2058  return vertcat(ret);
2059  }
2060 
2061  template<typename Scalar>
2062  Matrix<Scalar> Matrix<Scalar>::horzcat(const std::vector<Matrix<Scalar> > &v) {
2063  // Concatenate sparsity patterns
2064  std::vector<Sparsity> sp(v.size());
2065  for (casadi_int i=0; i<v.size(); ++i) sp[i] = v[i].sparsity();
2066  Matrix<Scalar> ret = zeros(Sparsity::horzcat(sp));
2067 
2068  // Copy nonzeros
2069  auto i=ret->begin();
2070  for (auto&& j : v) {
2071  std::copy(j->begin(), j->end(), i);
2072  i += j.nnz();
2073  }
2074  return ret;
2075  }
2076 
2077  template<typename Scalar>
2078  std::vector<Matrix<Scalar> >
2079  Matrix<Scalar>::horzsplit(const Matrix<Scalar>& x, const std::vector<casadi_int>& offset) {
2080  // Split up the sparsity pattern
2081  std::vector<Sparsity> sp = Sparsity::horzsplit(x.sparsity(), offset);
2082 
2083  // Return object
2084  std::vector<Matrix<Scalar> > ret;
2085  ret.reserve(sp.size());
2086 
2087  // Copy data
2088  auto i=x.nonzeros().begin();
2089  for (auto&& j : sp) {
2090  auto i_next = i + j.nnz();
2091  ret.push_back(Matrix<Scalar>(j, std::vector<Scalar>(i, i_next), false));
2092  i = i_next;
2093  }
2094 
2095  // Return the assembled matrix
2096  casadi_assert_dev(i==x.nonzeros().end());
2097  return ret;
2098  }
2099 
2100  template<typename Scalar>
2101  Matrix<Scalar> Matrix<Scalar>::vertcat(const std::vector<Matrix<Scalar> > &v) {
2102  std::vector<Matrix<Scalar> > vT(v.size());
2103  for (casadi_int i=0; i<v.size(); ++i) vT[i] = v[i].T();
2104  return horzcat(vT).T();
2105  }
2106 
2107  template<typename Scalar>
2108  std::vector< Matrix<Scalar> >
2109  Matrix<Scalar>::vertsplit(const Matrix<Scalar>& x, const std::vector<casadi_int>& offset) {
2110  std::vector< Matrix<Scalar> > ret = horzsplit(x.T(), offset);
2111  for (auto&& e : ret) e = e.T();
2112  return ret;
2113  }
2114 
2115  template<typename Scalar>
2116  std::vector< Matrix<Scalar> >
2117  Matrix<Scalar>::diagsplit(const Matrix<Scalar>& x, const std::vector<casadi_int>& offset1,
2118  const std::vector<casadi_int>& offset2) {
2119  // Consistency check
2120  casadi_assert_dev(!offset1.empty());
2121  casadi_assert_dev(offset1.front()==0);
2122  casadi_assert_dev(offset1.back()==x.size1());
2123  casadi_assert_dev(is_monotone(offset1));
2124 
2125  // Consistency check
2126  casadi_assert_dev(!offset2.empty());
2127  casadi_assert_dev(offset2.front()==0);
2128  casadi_assert_dev(offset2.back()==x.size2());
2129  casadi_assert_dev(is_monotone(offset2));
2130 
2131  // Number of outputs
2132  casadi_int n = offset1.size()-1;
2133 
2134  // Return value
2135  std::vector< Matrix<Scalar> > ret;
2136 
2137  // Caveat: this is a very silly implementation
2138  for (casadi_int i=0; i<n; ++i) {
2139  ret.push_back(x(Slice(offset1[i], offset1[i+1]), Slice(offset2[i], offset2[i+1])));
2140  }
2141 
2142  return ret;
2143  }
2144 
2145  template<typename Scalar>
2146  Matrix<Scalar> Matrix<Scalar>::dot(const Matrix<Scalar> &x,
2147  const Matrix<Scalar> &y) {
2148  casadi_assert(x.size()==y.size(), "dot: Dimension mismatch");
2149  if (x.sparsity()!=y.sparsity()) {
2150  Sparsity sp = x.sparsity() * y.sparsity();
2151  return dot(project(x, sp), project(y, sp));
2152  }
2153  return casadi_dot(x.nnz(), x.ptr(), y.ptr());
2154  }
2155 
2156  template<typename Scalar>
2157  Matrix<Scalar> Matrix<Scalar>::all(const Matrix<Scalar>& x) {
2158  if (!x.is_dense()) return false;
2159  Scalar ret=1;
2160  for (casadi_int i=0; i<x.nnz(); ++i) {
2161  ret = ret && x->at(i)==1;
2162  }
2163  return ret;
2164  }
2165 
2166  template<typename Scalar>
2167  Matrix<Scalar> Matrix<Scalar>::any(const Matrix<Scalar>& x) {
2168  if (!x.is_dense()) return false;
2169  Scalar ret=0;
2170  for (casadi_int i=0; i<x.nnz(); ++i) {
2171  ret = ret || x->at(i)==1;
2172  }
2173  return ret;
2174  }
2175 
2176  template<typename Scalar>
2177  Matrix<Scalar> Matrix<Scalar>::norm_1(const Matrix<Scalar>& x) {
2178  return casadi_norm_1(x.nnz(), x.ptr());
2179  }
2180 
2181  template<typename Scalar>
2182  Matrix<Scalar> Matrix<Scalar>::norm_2(const Matrix<Scalar>& x) {
2183  if (x.is_vector()) {
2184  return norm_fro(x);
2185  } else {
2186  casadi_error("2-norms currently only supported for vectors. "
2187  "Did you intend to calculate a Frobenius norms (norm_fro)?");
2188  }
2189  }
2190 
2191  template<typename Scalar>
2192  Matrix<Scalar> Matrix<Scalar>::norm_fro(const Matrix<Scalar>& x) {
2193  return casadi_norm_2(x.nnz(), x.ptr());
2194  }
2195 
2196  template<typename Scalar>
2197  Matrix<Scalar> Matrix<Scalar>::norm_inf(const Matrix<Scalar>& x) {
2198  // Get largest element by absolute value
2199  Matrix<Scalar> s = 0;
2200  for (auto i=x.nonzeros().begin(); i!=x.nonzeros().end(); ++i) {
2201  s = fmax(s, fabs(Matrix<Scalar>(*i)));
2202  }
2203  return s;
2204  }
2205 
2206  template<typename Scalar>
2207  void Matrix<Scalar>::
2208  qr_sparse(const Matrix<Scalar>& A,
2209  Matrix<Scalar>& V, Matrix<Scalar> &R, Matrix<Scalar>& beta,
2210  std::vector<casadi_int>& prinv, std::vector<casadi_int>& pc, bool amd) {
2211  // Calculate the pattern
2212  Sparsity spV, spR;
2213  A.sparsity().qr_sparse(spV, spR, prinv, pc, amd);
2214  // Calculate the nonzeros
2215  casadi_int nrow_ext = spV.size1(), ncol = spV.size2();
2216  V = nan(spV);
2217  R = nan(spR);
2218  beta = nan(ncol, 1);
2219  std::vector<Scalar> w(nrow_ext);
2220  casadi_qr(A.sparsity(), A.ptr(), get_ptr(w), spV, V.ptr(),
2221  spR, R.ptr(), beta.ptr(),
2222  get_ptr(prinv), get_ptr(pc));
2223  }
2224 
2225  template<typename Scalar>
2226  Matrix<Scalar> Matrix<Scalar>::
2227  qr_solve(const Matrix<Scalar>& b, const Matrix<Scalar>& v,
2228  const Matrix<Scalar>& r, const Matrix<Scalar>& beta,
2229  const std::vector<casadi_int>& prinv, const std::vector<casadi_int>& pc,
2230  bool tr) {
2231  // Get dimensions, check consistency
2232  casadi_int ncol = v.size2();
2233  casadi_int nrow = b.size1(), nrhs = b.size2();
2234  casadi_assert(r.size()==v.size(), "'r', 'v' dimension mismatch");
2235  casadi_assert(beta.is_vector() && beta.numel()==ncol, "'beta' has wrong dimension");
2236  casadi_assert(prinv.size()==r.size1(), "'pinv' has wrong dimension");
2237  // Work vector
2238  std::vector<Scalar> w(nrow+ncol);
2239  // Return value
2240  Matrix<Scalar> x = densify(b);
2241  casadi_qr_solve(x.ptr(), nrhs, tr, v.sparsity(), v.ptr(), r.sparsity(), r.ptr(),
2242  beta.ptr(), get_ptr(prinv), get_ptr(pc), get_ptr(w));
2243  return x;
2244  }
2245 
2246  template<typename Scalar>
2247  void Matrix<Scalar>::qr(const Matrix<Scalar>& A,
2248  Matrix<Scalar>& Q, Matrix<Scalar> &R) {
2249  // The following algorithm is taken from J. Demmel:
2250  // Applied Numerical Linear Algebra (algorithm 3.1.)
2251  casadi_assert(A.size1()>=A.size2(), "qr: fewer rows than columns");
2252 
2253  // compute Q and R column by column
2254  Q = R = Matrix<Scalar>();
2255  for (casadi_int i=0; i<A.size2(); ++i) {
2256  // Initialize qi to be the i-th column of *this
2257  Matrix<Scalar> ai = A(Slice(), i);
2258  Matrix<Scalar> qi = ai;
2259  // The i-th column of R
2260  Matrix<Scalar> ri = Matrix<Scalar>(A.size2(), 1);
2261 
2262  // subtract the projection of qi in the previous directions from ai
2263  for (casadi_int j=0; j<i; ++j) {
2264 
2265  // Get the j-th column of Q
2266  Matrix<Scalar> qj = Q(Slice(), j); // NOLINT(cppcoreguidelines-slicing)
2267 
2268  ri(j, 0) = mtimes(qi.T(), qj); // Modified Gram-Schmidt
2269  // ri[j] = dot(qj, ai); // Classical Gram-Schmidt
2270 
2271  // Remove projection in direction j
2272  if (ri.has_nz(j, 0))
2273  qi -= ri(j, 0) * qj;
2274  }
2275 
2276  // Normalize qi
2277  ri(i, 0) = norm_2(qi);
2278  qi /= ri(i, 0);
2279 
2280  // Update R and Q
2281  Q = Matrix<Scalar>::horzcat({Q, qi});
2282  R = Matrix<Scalar>::horzcat({R, ri});
2283  }
2284  }
2285 
2286  template<typename Scalar>
2287  void Matrix<Scalar>::ldl(const Matrix<Scalar>& A, Matrix<Scalar> &D,
2288  Matrix<Scalar>& LT, std::vector<casadi_int>& p, bool amd) {
2289  // Symbolic factorization
2290  Sparsity Lt_sp = A.sparsity().ldl(p, amd);
2291 
2292  // Get dimension
2293  casadi_int n=A.size1();
2294 
2295  // Calculate entries in L and D
2296  std::vector<Scalar> D_nz(n), L_nz(Lt_sp.nnz()), w(n);
2297  casadi_ldl(A.sparsity(), get_ptr(A.nonzeros()), Lt_sp,
2298  get_ptr(L_nz), get_ptr(D_nz), get_ptr(p), get_ptr(w));
2299 
2300  // Assemble L and D
2301  LT = Matrix<Scalar>(Lt_sp, L_nz);
2302  D = D_nz;
2303  }
2304 
2305  template<typename Scalar>
2306  Matrix<Scalar> Matrix<Scalar>::
2307  ldl_solve(const Matrix<Scalar>& b, const Matrix<Scalar>& D, const Matrix<Scalar>& LT,
2308  const std::vector<casadi_int>& p) {
2309  // Get dimensions, check consistency
2310  casadi_int n = b.size1(), nrhs = b.size2();
2311  casadi_assert(p.size()==n, "'p' has wrong dimension");
2312  casadi_assert(LT.size1()==n && LT.size2()==n, "'LT' has wrong dimension");
2313  casadi_assert(D.is_vector() && D.numel()==n, "'D' has wrong dimension");
2314  // Solve for all right-hand-sides
2315  Matrix<Scalar> x = densify(b);
2316  std::vector<Scalar> w(n);
2317  casadi_ldl_solve(x.ptr(), nrhs, LT.sparsity(), LT.ptr(), D.ptr(), get_ptr(p), get_ptr(w));
2318  return x;
2319  }
2320 
2321  template<typename Scalar>
2322  Matrix<Scalar> Matrix<Scalar>::nullspace(const Matrix<Scalar>& A) {
2323  Matrix<Scalar> X = A;
2324  casadi_int n = X.size1();
2325  casadi_int m = X.size2();
2326  casadi_assert(m>=n, "nullspace(): expecting a flat matrix (more columns than rows), "
2327  "but got " + str(X.dim()) + ".");
2328 
2329  Matrix<Scalar> seed = DM::eye(m)(Slice(0, m), Slice(n, m)); // NOLINT(cppcoreguidelines-slicing)
2330 
2331  std::vector< Matrix<Scalar> > us;
2332  std::vector< Matrix<Scalar> > betas;
2333 
2334  Matrix<Scalar> beta;
2335 
2336  for (casadi_int i=0;i<n;++i) {
2337  Matrix<Scalar> x = X(i, Slice(i, m)); // NOLINT(cppcoreguidelines-slicing)
2338  Matrix<Scalar> u = Matrix<Scalar>(x);
2339  Matrix<Scalar> sigma = sqrt(sum2(x*x));
2340  const Matrix<Scalar>& x0 = x(0, 0);
2341  u(0, 0) = 1;
2342 
2343  Matrix<Scalar> b = -copysign(sigma, x0);
2344 
2345  u(Slice(0), Slice(1, m-i))*= 1/(x0-b);
2346  beta = 1-x0/b;
2347 
2348  X(Slice(i, n), Slice(i, m)) -=
2349  beta*mtimes(mtimes(X(Slice(i, n), Slice(i, m)), u.T()), u);
2350  us.push_back(u);
2351  betas.push_back(beta);
2352  }
2353 
2354  for (casadi_int i=n-1;i>=0;--i) {
2355  seed(Slice(i, m), Slice(0, m-n)) -=
2356  betas[i]*mtimes(us[i].T(), mtimes(us[i], seed(Slice(i, m), Slice(0, m-n))));
2357  }
2358 
2359  return seed;
2360 
2361  }
2362 
2363  template<typename Scalar>
2364  Matrix<Scalar> Matrix<Scalar>::chol(const Matrix<Scalar>& A) {
2365  // Perform an LDL transformation
2366  Matrix<Scalar> D, LT;
2367  std::vector<casadi_int> p;
2368  ldl(A, D, LT, p, false);
2369  // Add unit diagonal
2370  LT += Matrix<Scalar>::eye(D.size1());
2371  // Get the cholesky factor: R*R' = L*D*L' = (sqrt(D)*L')'*(sqrt(D)*L')
2372  return mtimes(diag(sqrt(D)), LT);
2373  }
2374 
2375  template<typename Scalar>
2376  Matrix<Scalar> Matrix<Scalar>::solve(const Matrix<Scalar>& a, const Matrix<Scalar>& b) {
2377  // check dimensions
2378  casadi_assert(a.size1() == b.size1(), "solve Ax=b: dimension mismatch: b has "
2379  + str(b.size1()) + " rows while A has " + str(a.size1()) + ".");
2380  casadi_assert(a.size1() == a.size2(), "solve: A not square but " + str(a.dim()));
2381 
2382  if (a.is_tril()) {
2383  // forward substitution if lower triangular
2384  Matrix<Scalar> x = b;
2385  const casadi_int* Arow = a.row();
2386  const casadi_int* Acolind = a.colind();
2387  const std::vector<Scalar> & Adata = a.nonzeros();
2388  for (casadi_int i=0; i<a.size2(); ++i) { // loop over columns forwards
2389  for (casadi_int k=0; k<b.size2(); ++k) { // for every right hand side
2390  if (!x.has_nz(i, k)) continue;
2391  x(i, k) /= a(i, i);
2392  for (casadi_int kk=Acolind[i+1]-1; kk>=Acolind[i] && Arow[kk]>i; --kk) {
2393  casadi_int j = Arow[kk];
2394  x(j, k) -= Adata[kk]*x(i, k);
2395  }
2396  }
2397  }
2398  return x;
2399  } else if (a.is_triu()) {
2400  // backward substitution if upper triangular
2401  Matrix<Scalar> x = b;
2402  const casadi_int* Arow = a.row();
2403  const casadi_int* Acolind = a.colind();
2404  const std::vector<Scalar> & Adata = a.nonzeros();
2405  for (casadi_int i=a.size2()-1; i>=0; --i) { // loop over columns backwards
2406  for (casadi_int k=0; k<b.size2(); ++k) { // for every right hand side
2407  if (!x.has_nz(i, k)) continue;
2408  x(i, k) /= a(i, i);
2409  for (casadi_int kk=Acolind[i]; kk<Acolind[i+1] && Arow[kk]<i; ++kk) {
2410  casadi_int j = Arow[kk];
2411  x(j, k) -= Adata[kk]*x(i, k);
2412  }
2413  }
2414  }
2415  return x;
2416  } else if (a.has_zeros()) {
2417 
2418  // If there are structurally nonzero entries that are known to be zero,
2419  // remove these and rerun the algorithm
2420  return solve(sparsify(a), b);
2421 
2422  } else {
2423 
2424  // Make a BLT transformation of A
2425  std::vector<casadi_int> rowperm, colperm, rowblock, colblock;
2426  std::vector<casadi_int> coarse_rowblock, coarse_colblock;
2427  a.sparsity().btf(rowperm, colperm, rowblock, colblock,
2428  coarse_rowblock, coarse_colblock);
2429 
2430  // Permute the right hand side
2431  Matrix<Scalar> bperm = b(rowperm, Slice());
2432 
2433  // Permute the linear system
2434  Matrix<Scalar> Aperm = a(rowperm, colperm);
2435 
2436  // Solution
2437  Matrix<Scalar> xperm;
2438 
2439  // Solve permuted system
2440  if (Aperm.is_tril()) {
2441 
2442  // Forward substitution if lower triangular
2443  xperm = solve(Aperm, bperm);
2444 
2445  } else if (a.size2()<=3) {
2446 
2447  // Form inverse by minor expansion and multiply if very small (up to 3-by-3)
2448  xperm = mtimes(inv_minor(Aperm), bperm);
2449 
2450  } else {
2451 
2452  // Make a QR factorization
2453  Matrix<Scalar> Q, R;
2454  qr(Aperm, Q, R);
2455 
2456  // Solve the factorized system (note that solve will now be fast since it is triangular)
2457  xperm = solve(R, mtimes(Q.T(), bperm));
2458  }
2459 
2460  // get the inverted column permutation
2461  std::vector<casadi_int> inv_colperm(colperm.size());
2462  for (casadi_int k=0; k<colperm.size(); ++k)
2463  inv_colperm[colperm[k]] = k;
2464 
2465  // Permute back the solution and return
2466  Matrix<Scalar> x = xperm(inv_colperm, Slice()); // NOLINT(cppcoreguidelines-slicing)
2467  return x;
2468  }
2469  }
2470 
2471  template<typename Scalar>
2472  Matrix<Scalar> Matrix<Scalar>::
2473  solve(const Matrix<Scalar>& a, const Matrix<Scalar>& b,
2474  const std::string& lsolver, const Dict& dict) {
2475  casadi_error("'solve' with plugin not defined for " + type_name());
2476  return Matrix<Scalar>();
2477  }
2478 
2479  template<typename Scalar>
2480  Matrix<Scalar> Matrix<Scalar>::
2481  inv(const Matrix<Scalar>& a) {
2482  return solve(a, Matrix<Scalar>::eye(a.size1()));
2483  }
2484 
2485  template<typename Scalar>
2486  Matrix<Scalar> Matrix<Scalar>::
2487  inv(const Matrix<Scalar>& a,
2488  const std::string& lsolver, const Dict& dict) {
2489  casadi_error("'inv' with plugin not defined for " + type_name());
2490  return Matrix<Scalar>();
2491  }
2492 
2493  template<typename Scalar>
2494  Matrix<Scalar> Matrix<Scalar>::pinv(const Matrix<Scalar>& A) {
2495  if (A.size2()>=A.size1()) {
2496  return solve(mtimes(A, A.T()), A).T();
2497  } else {
2498  return solve(mtimes(A.T(), A), A.T());
2499  }
2500  }
2501 
2502  template<typename Scalar>
2503  Matrix<Scalar> Matrix<Scalar>::
2504  pinv(const Matrix<Scalar>& A, const std::string& lsolver, const Dict& dict) {
2505  casadi_error("'solve' not defined for " + type_name());
2506  return Matrix<Scalar>();
2507  }
2508 
2509  template<typename Scalar>
2510  Matrix<Scalar> Matrix<Scalar>::
2511  expm_const(const Matrix<Scalar>& A, const Matrix<Scalar>& t) {
2512  casadi_error("'solve' not defined for " + type_name());
2513  return Matrix<Scalar>();
2514  }
2515 
2516  template<typename Scalar>
2517  Matrix<Scalar> Matrix<Scalar>::
2518  expm(const Matrix<Scalar>& A) {
2519  casadi_error("'solve' not defined for " + type_name());
2520  return Matrix<Scalar>();
2521  }
2522 
2523  template<typename Scalar>
2524  Matrix<Scalar> Matrix<Scalar>::kron(const Matrix<Scalar>& a, const Matrix<Scalar>& b) {
2525  std::vector<Scalar> ret(a.nnz()*b.nnz());
2526  casadi_kron(get_ptr(a), a.sparsity(), get_ptr(b), b.sparsity(), get_ptr(ret));
2527 
2528  Sparsity sp_ret = Sparsity::kron(a.sparsity(), b.sparsity());
2529  return Matrix<Scalar>(sp_ret, ret, false);
2530  }
2531 
2532  template<typename Scalar>
2533  Matrix<Scalar> Matrix<Scalar>::diag(const Matrix<Scalar>& A) {
2534  // Nonzero mapping
2535  std::vector<casadi_int> mapping;
2536  // Get the sparsity
2537  Sparsity sp = A.sparsity().get_diag(mapping);
2538 
2539  Matrix<Scalar> ret = zeros(sp);
2540 
2541  for (casadi_int k=0; k<mapping.size(); k++) ret.nz(k) = A.nz(mapping[k]);
2542  return ret;
2543  }
2544 
2548  template<typename Scalar>
2549  Matrix<Scalar> Matrix<Scalar>::diagcat(const std::vector< Matrix<Scalar> > &A) {
2550  std::vector<Scalar> data;
2551 
2552  std::vector<Sparsity> sp;
2553  for (casadi_int i=0;i<A.size();++i) {
2554  data.insert(data.end(), A[i].nonzeros().begin(), A[i].nonzeros().end());
2555  sp.push_back(A[i].sparsity());
2556  }
2557 
2558  return Matrix<Scalar>(Sparsity::diagcat(sp), data, false);
2559  }
2560 
2564  template<typename Scalar>
2565  bool Matrix<Scalar>::simplify_ref_count(std::vector< Matrix<Scalar> >& arg,
2566  std::vector< Matrix<Scalar> >& res,
2567  const Dict& opts) {
2568  casadi_error("'simplify_ref_count' not defined for " + type_name());
2569  }
2570 
2574  template<typename Scalar>
2575  bool Matrix<Scalar>::simplify_const_folding(std::vector< Matrix<Scalar> >& arg,
2576  std::vector< Matrix<Scalar> >& res,
2577  const Dict& opts) {
2578  casadi_error("'simplify_const_folding' not defined for " + type_name());
2579  }
2580 
2581  template<typename Scalar>
2582  bool Matrix<Scalar>::simplify_combine_terms(std::vector< Matrix<Scalar> >& arg,
2583  std::vector< Matrix<Scalar> >& res,
2584  const Dict& opts) {
2585  casadi_error("'simplify_combine_terms' not defined for " + type_name());
2586  }
2587 
2588  template<typename Scalar>
2589  Matrix<Scalar> Matrix<Scalar>::unite(const Matrix<Scalar>& A, const Matrix<Scalar>& B) {
2590  // Join the sparsity patterns
2591  std::vector<unsigned char> mapping;
2592  Sparsity sp = A.sparsity().unite(B.sparsity(), mapping);
2593 
2594  // Create return matrix
2595  Matrix<Scalar> ret = zeros(sp);
2596 
2597  // Copy sparsity
2598  casadi_int elA=0, elB=0;
2599  for (casadi_int k=0; k<mapping.size(); ++k) {
2600  if (mapping[k]==1) {
2601  ret.nonzeros()[k] = A.nonzeros()[elA++];
2602  } else if (mapping[k]==2) {
2603  ret.nonzeros()[k] = B.nonzeros()[elB++];
2604  } else {
2605  casadi_error("Pattern intersection not empty");
2606  }
2607  }
2608 
2609  casadi_assert_dev(A.nnz()==elA);
2610  casadi_assert_dev(B.nnz()==elB);
2611 
2612  return ret;
2613  }
2614 
2615  template<typename Scalar>
2616  Matrix<Scalar> Matrix<Scalar>::polyval(const Matrix<Scalar>& p, const Matrix<Scalar>& x) {
2617  casadi_assert(p.is_dense(), "polynomial coefficients vector must be dense");
2618  casadi_assert(p.is_vector() && p.nnz()>0, "polynomial coefficients must be a vector");
2619  Matrix<Scalar> ret = x;
2620  for (auto&& e : ret.nonzeros()) {
2621  e = casadi_polyval(p.ptr(), p.numel()-1, e);
2622  }
2623  return ret;
2624  }
2625 
2626  template<typename Scalar>
2627  Matrix<Scalar> Matrix<Scalar>::norm_inf_mul(const Matrix<Scalar>& x,
2628  const Matrix<Scalar>& y) {
2629  casadi_assert(y.size1()==x.size2(), "Dimension error. Got " + x.dim()
2630  + " times " + y.dim() + ".");
2631 
2632  // Allocate work vectors
2633  std::vector<Scalar> dwork(x.size1());
2634  std::vector<casadi_int> iwork(x.size1()+1+y.size2());
2635 
2636  // Call C runtime
2637  return casadi_norm_inf_mul(x.ptr(), x.sparsity(), y.ptr(), y.sparsity(),
2638  get_ptr(dwork), get_ptr(iwork));
2639  }
2640 
2641  template<typename Scalar>
2642  void Matrix<Scalar>::expand(const Matrix<Scalar>& ex,
2643  Matrix<Scalar> &weights, Matrix<Scalar>& terms) {
2644  casadi_error("'expand' not defined for " + type_name());
2645  }
2646 
2647  template<typename Scalar>
2648  Matrix<Scalar> Matrix<Scalar>::pw_const(const Matrix<Scalar>& ex,
2649  const Matrix<Scalar>& tval,
2650  const Matrix<Scalar>& val) {
2651  casadi_error("'pw_const' not defined for " + type_name());
2652  return Matrix<Scalar>();
2653  }
2654 
2655  template<typename Scalar>
2656  Matrix<Scalar> Matrix<Scalar>::pw_lin(const Matrix<Scalar>& ex,
2657  const Matrix<Scalar>& tval,
2658  const Matrix<Scalar>& val) {
2659  casadi_error("'pw_lin' not defined for " + type_name());
2660  return Matrix<Scalar>();
2661  }
2662 
2663  template<typename Scalar>
2664  Matrix<Scalar> Matrix<Scalar>::if_else(const Matrix<Scalar> &cond,
2665  const Matrix<Scalar> &if_true,
2666  const Matrix<Scalar> &if_false,
2667  bool short_circuit) {
2668  return if_else_zero(cond, if_true) + if_else_zero(!cond, if_false);
2669  }
2670 
2671  template<typename Scalar>
2672  Matrix<Scalar> Matrix<Scalar>::conditional(const Matrix<Scalar>& ind,
2673  const std::vector<Matrix<Scalar> >& x,
2674  const Matrix<Scalar>& x_default,
2675  bool short_circuit) {
2676  casadi_assert(!short_circuit,
2677  "Short-circuiting 'conditional' not supported for " + type_name());
2678  casadi_assert(ind.is_scalar(true),
2679  "conditional: first argument must be scalar. Got " + ind.dim()+ " instead.");
2680 
2681  Matrix<Scalar> ret = x_default;
2682  for (casadi_int k=0; k<x.size(); ++k) {
2683  ret = if_else(ind==k, x[k], ret, short_circuit);
2684  }
2685  return ret;
2686  }
2687 
2688  template<typename Scalar>
2689  Matrix<Scalar> Matrix<Scalar>::heaviside(const Matrix<Scalar>& x) {
2690  return (1+sign(x))/2;
2691  }
2692 
2693  template<typename Scalar>
2694  Matrix<Scalar> Matrix<Scalar>::rectangle(const Matrix<Scalar>& x) {
2695  return 0.5*(sign(x+0.5)-sign(x-0.5));
2696  }
2697 
2698  template<typename Scalar>
2699  Matrix<Scalar> Matrix<Scalar>::triangle(const Matrix<Scalar>& x) {
2700  return rectangle(x/2)*(1-fabs(x));
2701  }
2702 
2703  template<typename Scalar>
2704  Matrix<Scalar> Matrix<Scalar>::ramp(const Matrix<Scalar>& x) {
2705  return x*heaviside(x);
2706  }
2707 
2708  template<typename Scalar>
2709  Matrix<Scalar> Matrix<Scalar>::
2710  gauss_quadrature(const Matrix<Scalar> &f,
2711  const Matrix<Scalar> &x, const Matrix<Scalar> &a,
2712  const Matrix<Scalar> &b, casadi_int order) {
2713  return gauss_quadrature(f, x, a, b, order, Matrix<Scalar>());
2714  }
2715 
2716  template<typename Scalar>
2717  Matrix<Scalar> Matrix<Scalar>::gauss_quadrature(const Matrix<Scalar>& f,
2718  const Matrix<Scalar>& x,
2719  const Matrix<Scalar>& a,
2720  const Matrix<Scalar>& b, casadi_int order,
2721  const Matrix<Scalar>& w) {
2722  casadi_error("'gauss_quadrature' not defined for " + type_name());
2723  return Matrix<Scalar>();
2724  }
2725 
2726  template<typename Scalar>
2727  Matrix<Scalar> Matrix<Scalar>::simplify(const Matrix<Scalar> &x) {
2728  return x;
2729  }
2730 
2731  template<typename Scalar>
2732  Matrix<Scalar> Matrix<Scalar>::transform(const Matrix<Scalar> &x, const Dict& opts) {
2733  casadi_error("'transform' not defined for " + type_name());
2734  }
2735 
2736  template<typename Scalar>
2737  Matrix<Scalar> Matrix<Scalar>::transform(const Matrix<Scalar> &x,
2738  const std::vector<std::vector<GenericType> >& passes, const Dict& opts) {
2739  casadi_error("'transform' not defined for " + type_name());
2740  }
2741 
2742  template<typename Scalar>
2743  std::vector<Matrix<Scalar> > Matrix<Scalar>::transform(const std::vector<Matrix<Scalar> >& x,
2744  const Dict& opts) {
2745  casadi_error("'transform' not defined for " + type_name());
2746  }
2747 
2748  template<typename Scalar>
2749  std::vector<Matrix<Scalar> > Matrix<Scalar>::transform(const std::vector<Matrix<Scalar> >& x,
2750  const std::vector<std::vector<GenericType> >& passes, const Dict& opts) {
2751  casadi_error("'transform' not defined for " + type_name());
2752  }
2753 
2754  template<typename Scalar>
2755  Matrix<Scalar> Matrix<Scalar>::substitute(const Matrix<Scalar>& ex,
2756  const Matrix<Scalar>& v,
2757  const Matrix<Scalar>& vdef) {
2758  casadi_error("'substitute' not defined for " + type_name());
2759  return Matrix<Scalar>();
2760  }
2761 
2762  template<typename Scalar>
2763  std::vector<Matrix<Scalar> >
2764  Matrix<Scalar>::substitute(const std::vector<Matrix<Scalar> >& ex,
2765  const std::vector<Matrix<Scalar> >& v,
2766  const std::vector<Matrix<Scalar> >& vdef) {
2767  casadi_error("'substitute' not defined for " + type_name());
2768  return std::vector<Matrix<Scalar> >();
2769  }
2770 
2771  template<typename Scalar>
2772  void Matrix<Scalar>::substitute_inplace(const std::vector<Matrix<Scalar> >& v,
2773  std::vector<Matrix<Scalar> >& vdef,
2774  std::vector<Matrix<Scalar> >& ex,
2775  bool reverse) {
2776  casadi_error("'substitute_inplace' not defined for " + type_name());
2777  }
2778 
2779  template<typename Scalar>
2780  void Matrix<Scalar>::extract_parametric(const Matrix<Scalar> &expr,
2781  const Matrix<Scalar>& par,
2782  Matrix<Scalar>& expr_ret,
2783  std::vector<Matrix<Scalar> >& symbols,
2784  std::vector< Matrix<Scalar> >& parametric,
2785  const Dict& opts) {
2786  casadi_error("'extract_parametric' not defined for " + type_name());
2787  }
2788 
2789  template<typename Scalar>
2790  void Matrix<Scalar>::separate_linear(const Matrix<Scalar> &expr,
2791  const Matrix<Scalar> &sym_lin, const Matrix<Scalar> &sym_const,
2792  Matrix<Scalar>& expr_const, Matrix<Scalar>& expr_lin, Matrix<Scalar>& expr_nonlin) {
2793  casadi_error("'separate_linear' not defined for " + type_name());
2794  }
2795 
2796  template<typename Scalar>
2797  bool Matrix<Scalar>::depends_on(const Matrix<Scalar> &x, const Matrix<Scalar> &arg) {
2798  casadi_error("'depends_on' not defined for " + type_name());
2799  return false;
2800  }
2801 
2802  template<typename Scalar>
2803  bool Matrix<Scalar>::contains_all(const std::vector <Matrix<Scalar> >& v,
2804  const std::vector <Matrix<Scalar> > &n) {
2805  casadi_error("'contains_all' not defined for " + type_name());
2806  return false;
2807  }
2808 
2809  template<typename Scalar>
2810  bool Matrix<Scalar>::contains_any(const std::vector<Matrix<Scalar> >& v,
2811  const std::vector <Matrix<Scalar> > &n) {
2812  casadi_error("'contains_any' not defined for " + type_name());
2813  return false;
2814  }
2815 
2816  template<typename Scalar>
2817  std::vector< Matrix<Scalar> > Matrix<Scalar>::cse(const std::vector< Matrix<Scalar> >& e) {
2818  casadi_error("'cse' not defined for " + type_name());
2819  return {};
2820  }
2821 
2822 
2823  template<typename Scalar>
2824  Matrix<Scalar> Matrix<Scalar>::
2825  jacobian(const Matrix<Scalar> &f, const Matrix<Scalar> &x, const Dict& opts) {
2826  casadi_error("'jacobian' not defined for " + type_name());
2827  return Matrix<Scalar>();
2828  }
2829 
2830  template<typename Scalar>
2831  Matrix<Scalar> Matrix<Scalar>::hessian(const Matrix<Scalar> &f,
2832  const Matrix<Scalar> &x,
2833  const Dict& opts) {
2834  casadi_error("'hessian' not defined for " + type_name());
2835  return Matrix<Scalar>();
2836  }
2837 
2838  template<typename Scalar>
2839  Matrix<Scalar> Matrix<Scalar>::hessian(const Matrix<Scalar> &f,
2840  const Matrix<Scalar> &x,
2841  Matrix<Scalar> &g,
2842  const Dict& opts) {
2843  casadi_error("'hessian' not defined for " + type_name());
2844  return Matrix<Scalar>();
2845  }
2846 
2847  template<typename Scalar>
2848  std::vector<std::vector<Matrix<Scalar> > >
2849  Matrix<Scalar>::
2850  forward(const std::vector<Matrix<Scalar> > &ex,
2851  const std::vector<Matrix<Scalar> > &arg,
2852  const std::vector<std::vector<Matrix<Scalar> > > &v,
2853  const Dict& opts) {
2854  casadi_error("'forward' not defined for " + type_name());
2855  }
2856 
2857  template<typename Scalar>
2858  std::vector<std::vector<Matrix<Scalar> > >
2859  Matrix<Scalar>::
2860  reverse(const std::vector<Matrix<Scalar> > &ex,
2861  const std::vector<Matrix<Scalar> > &arg,
2862  const std::vector<std::vector<Matrix<Scalar> > > &v,
2863  const Dict& opts) {
2864  casadi_error("'reverse' not defined for " + type_name());
2865  }
2866 
2867  template<typename Scalar>
2868  std::vector<bool>
2869  Matrix<Scalar>::which_depends(const Matrix<Scalar> &expr, const Matrix<Scalar> &var,
2870  casadi_int order, bool tr) {
2871  casadi_error("'which_depends' not defined for " + type_name());
2872  return std::vector<bool>();
2873  }
2874 
2875  template<typename Scalar>
2876  Sparsity
2877  Matrix<Scalar>::jacobian_sparsity(const Matrix<Scalar> &f, const Matrix<Scalar> &x) {
2878  casadi_error("'jacobian_sparsity' not defined for " + type_name());
2879  return Sparsity();
2880  }
2881 
2882  template<typename Scalar>
2883  Matrix<Scalar> Matrix<Scalar>::taylor(const Matrix<Scalar>& f,
2884  const Matrix<Scalar>& x,
2885  const Matrix<Scalar>& a, casadi_int order) {
2886  casadi_error("'taylor' not defined for " + type_name());
2887  return Matrix<Scalar>();
2888  }
2889 
2890  template<typename Scalar>
2891  Matrix<Scalar> Matrix<Scalar>::mtaylor(const Matrix<Scalar>& f,
2892  const Matrix<Scalar>& x,
2893  const Matrix<Scalar>& a, casadi_int order) {
2894  casadi_error("'mtaylor' not defined for " + type_name());
2895  return Matrix<Scalar>();
2896  }
2897 
2898  template<typename Scalar>
2899  Matrix<Scalar> Matrix<Scalar>::mtaylor(const Matrix<Scalar>& f,
2900  const Matrix<Scalar>& x,
2901  const Matrix<Scalar>& a, casadi_int order,
2902  const std::vector<casadi_int>&order_contributions) {
2903  casadi_error("'mtaylor' not defined for " + type_name());
2904  return Matrix<Scalar>();
2905  }
2906 
2907  template<typename Scalar>
2908  casadi_int Matrix<Scalar>::n_nodes(const Matrix<Scalar>& x) {
2909  casadi_error("'n_nodes' not defined for " + type_name());
2910  return 0;
2911  }
2912 
2913  template<typename Scalar>
2914  std::string
2915  Matrix<Scalar>::print_operator(const Matrix<Scalar>& x,
2916  const std::vector<std::string>& args) {
2917  casadi_error("'print_operator' not defined for " + type_name());
2918  return std::string();
2919  }
2920 
2921  template<typename Scalar>
2922  std::vector<Matrix<Scalar> > Matrix<Scalar>::symvar(const Matrix<Scalar>& x) {
2923  casadi_error("'symvar' not defined for " + type_name());
2924  return std::vector<Matrix<Scalar> >();
2925  }
2926 
2927  template<typename Scalar>
2928  void Matrix<Scalar>::extract(std::vector<Matrix<Scalar>>& ex, std::vector<Matrix<Scalar>>& v,
2929  std::vector<Matrix<Scalar>>& vdef, const Dict& opts) {
2930  casadi_error("'extract' not defined for " + type_name());
2931  }
2932 
2933  template<typename Scalar>
2934  void Matrix<Scalar>::shared(std::vector<Matrix<Scalar> >& ex,
2935  std::vector<Matrix<Scalar> >& v,
2936  std::vector<Matrix<Scalar> >& vdef,
2937  const std::string& v_prefix,
2938  const std::string& v_suffix) {
2939  casadi_error("'shared' not defined for " + type_name());
2940  }
2941 
2942  template<typename Scalar>
2943  Matrix<Scalar> Matrix<Scalar>::poly_coeff(const Matrix<Scalar>& f,
2944  const Matrix<Scalar>&x) {
2945  casadi_error("'poly_coeff' not defined for " + type_name());
2946  }
2947 
2948  template<typename Scalar>
2949  Matrix<Scalar> Matrix<Scalar>::poly_roots(const Matrix<Scalar>& p) {
2950  casadi_error("'poly_roots' not defined for " + type_name());
2951  }
2952 
2953  template<typename Scalar>
2954  Matrix<Scalar> Matrix<Scalar>::eig_symbolic(const Matrix<Scalar>& m) {
2955  casadi_error("'eig_symbolic' not defined for " + type_name());
2956  }
2957 
2958  template<typename Scalar>
2959  DM Matrix<Scalar>::evalf(const Matrix<Scalar>& m) {
2960  Function f("f", std::vector<SX>{}, std::vector<SX>{m});
2961  return f(std::vector<DM>{})[0];
2962  }
2963 
2964  template<typename Scalar>
2965  Matrix<Scalar> Matrix<Scalar>::sparsify(const Matrix<Scalar>& x, double tol) {
2966  // Quick return if there are no entries to be removed
2967  bool remove_nothing = true;
2968  for (auto it=x.nonzeros().begin(); it!=x.nonzeros().end() && remove_nothing; ++it) {
2969  remove_nothing = !casadi_limits<Scalar>::is_almost_zero(*it, tol);
2970  }
2971  if (remove_nothing) return x;
2972 
2973  // Get the current sparsity pattern
2974  casadi_int size1 = x.size1();
2975  casadi_int size2 = x.size2();
2976  const casadi_int* colind = x.colind();
2977  const casadi_int* row = x.row();
2978 
2979  // Construct the new sparsity pattern
2980  std::vector<casadi_int> new_colind(1, 0), new_row;
2981  std::vector<Scalar> new_data;
2982 
2983  // Loop over the columns
2984  for (casadi_int cc=0; cc<size2; ++cc) {
2985  // Loop over existing nonzeros
2986  for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
2987  // If it is not known to be a zero
2988  if (!casadi_limits<Scalar>::is_almost_zero(x->at(el), tol)) {
2989  // Save the nonzero in its new location
2990  new_data.push_back(x->at(el));
2991 
2992  // Add to pattern
2993  new_row.push_back(row[el]);
2994  }
2995  }
2996  // Save the new column offset
2997  new_colind.push_back(new_row.size());
2998  }
2999 
3000  // Construct the sparsity pattern
3001  Sparsity sp(size1, size2, new_colind, new_row);
3002 
3003  // Construct matrix and return
3004  return Matrix<Scalar>(sp, new_data);
3005  }
3006 
3007 
3008  template<typename Scalar>
3009  std::vector<Matrix<Scalar> > Matrix<Scalar>::get_input(const Function& f) {
3010  casadi_error("'get_input' not defined for " + type_name());
3011  }
3012 
3013  template<typename Scalar>
3014  std::vector<Matrix<Scalar> > Matrix<Scalar>::get_free(const Function& f) {
3015  casadi_error("'get_free' not defined for " + type_name());
3016  }
3017 
3018  template<typename Scalar>
3019  Matrix<Scalar>::operator double() const {
3020  casadi_assert_dev(is_scalar());
3021  return static_cast<double>(scalar());
3022  }
3023 
3024  template<typename Scalar>
3025  Matrix<Scalar>::operator casadi_int() const {
3026  casadi_assert_dev(is_scalar());
3027  return static_cast<casadi_int>(scalar());
3028  }
3029 
3030  template<typename Scalar>
3031  Matrix<Scalar> Matrix<Scalar>::_sym(const std::string& name, const Sparsity& sp) {
3032  casadi_error("'sym' not defined for " + type_name());
3033  }
3034 
3035  template<typename Scalar>
3036  Matrix<Scalar> Matrix<Scalar>::rand(const Sparsity& sp) { // NOLINT(runtime/threadsafe_fn)
3037 
3038  casadi_error("'rand' not defined for " + type_name());
3039  }
3040 
3041  template<typename Scalar>
3042  std::string Matrix<Scalar>::serialize() const {
3043  std::stringstream ss;
3044  serialize(ss);
3045  return ss.str();
3046  }
3047 
3048  template<typename Scalar>
3049  void Matrix<Scalar>::serialize(SerializingStream& s) const {
3050  s.pack("Matrix::sparsity", sparsity());
3051  s.pack("Matrix::nonzeros", nonzeros());
3052  }
3053 
3054  template<typename Scalar>
3055  Matrix<Scalar> Matrix<Scalar>::deserialize(DeserializingStream& s) {
3056  Sparsity sp;
3057  s.unpack("Matrix::sparsity", sp);
3058  std::vector<Scalar> nz;
3059  s.unpack("Matrix::nonzeros", nz);
3060  return Matrix<Scalar>(sp, nz, false);
3061  }
3062 
3063  template<typename Scalar>
3064  void Matrix<Scalar>::serialize(std::ostream &stream) const {
3065  SerializingStream s(stream);
3066  serialize(s);
3067  }
3068 
3069  template<typename Scalar>
3070  Matrix<Scalar> Matrix<Scalar>::deserialize(std::istream &stream) {
3071  DeserializingStream s(stream);
3072  return Matrix<Scalar>::deserialize(s);
3073  }
3074 
3075  template<typename Scalar>
3076  Matrix<Scalar> Matrix<Scalar>::deserialize(const std::string& s) {
3077  std::stringstream ss;
3078  ss << s;
3079  return deserialize(ss);
3080  }
3081 
3082 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
3083  template<typename Scalar>
3084  std::mutex& Matrix<Scalar>::get_mutex_temp() {
3085  casadi_error("'get_mutex_temp' not defined for " + type_name());
3086  }
3087 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
3088 
3089 } // namespace casadi
3090 
3091 #endif // CASADI_MATRIX_IMPL_HPP
Function object.
Definition: function.hpp:60
Sparsity sparsity() const
Get the sparsity pattern.
bool is_dense() const
Check if the matrix expression is dense.
bool is_column() const
Check if the matrix is a column vector (i.e. size2()==1)
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) non-zero elements.
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.
bool is_scalar(bool scalar_and_dense=false) const
Check if the matrix expression is scalar.
Sparse matrix class. SX and DM are specializations.
Definition: matrix_decl.hpp:99
bool has_nz(casadi_int rr, casadi_int cc) const
Returns true if the matrix has a non-zero at location rr, cc.
Definition: matrix_impl.hpp:75
void print_split(std::vector< std::string > &nz, std::vector< std::string > &inter) const
Get strings corresponding to the nonzeros and the interdependencies.
Matrix< Scalar > T() const
Transpose the matrix.
static void set_precision(casadi_int precision)
Set the 'precision, width & scientific' used in printing and serializing to streams.
Definition: matrix_impl.hpp:40
static casadi_int get_precision()
Get the 'precision, width & scientific' used in printing and serializing to streams.
Definition: matrix_impl.hpp:49
void get(Matrix< Scalar > &m, bool ind1, const Slice &rr) const
void resize(casadi_int nrow, casadi_int ncol)
void print_sparse(std::ostream &stream, bool truncate=true) const
Print sparse matrix style.
static void set_width(casadi_int width)
Definition: matrix_impl.hpp:43
Matrix()
constructors
void set(const Matrix< Scalar > &m, bool ind1, const Slice &rr)
static casadi_int get_width()
Definition: matrix_impl.hpp:52
static bool get_scientific()
Definition: matrix_impl.hpp:55
static std::string type_name()
Get name of the class.
void to_file(const std::string &filename, const std::string &format="") const
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.
bool __nonzero__() const
Returns the truth value of a Matrix.
Definition: matrix_impl.hpp:80
static void rng(casadi_int seed)
Seed the random number generator.
Definition: matrix_impl.hpp:70
void print_dense(std::ostream &stream, bool truncate=true) const
Print dense matrix-stype.
void reserve(casadi_int nnz)
void set(const Matrix< Scalar > &m, bool ind1, const Slice &rr, const Slice &cc)
void set_nz(const Matrix< Scalar > &m, bool ind1, const Slice &k)
void print_vector(std::ostream &stream, bool truncate=true) const
Print vector-style.
std::string get_str(bool more=false) const
Get string representation.
void get_nz(Matrix< Scalar > &m, bool ind1, const Slice &k) const
void print_scalar(std::ostream &stream) const
Print scalar.
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:106
std::vector< casadi_int > find(bool ind1=SWIG_IND1) const
Get the location of all non-zero elements as they would appear in a Dense matrix.
Sparsity sub(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, std::vector< casadi_int > &mapping, bool ind1=false) const
Get a submatrix.
casadi_int numel() const
The total number of elements, including structural zeros, i.e. size2()*size1()
casadi_int size1() const
Get the number of rows.
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern *.
Sparsity T() const
Transpose the matrix.
bool is_column() const
Check if 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 given the nonzeros in sparse triplet form *.
casadi_int nnz() const
Get the number of (structural) non-zeros.
casadi_int size2() const
Get the number of columns.
casadi_int row(casadi_int el) const
Get the row of a non-zero element.
bool is_empty(bool both=false) const
Check if the sparsity is empty.
std::pair< casadi_int, casadi_int > size() const
Get the shape.
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)
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
bool is_monotone(const std::vector< T > &v)
Check if the vector is monotone.
CASADI_EXPORT std::vector< casadi_int > complement(const std::vector< casadi_int > &v, casadi_int size)
Returns the list of all i in [0, size[ not found in supplied list.
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.