sparsity.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  * Copyright (C) 2005-2013 Timothy A. Davis
9  *
10  * CasADi is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 3 of the License, or (at your option) any later version.
14  *
15  * CasADi is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with CasADi; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 
26 
27 #include "sparsity_internal.hpp"
28 #include "im.hpp"
29 #include "casadi_misc.hpp"
30 #include "serializing_stream.hpp"
31 #include "filesystem_impl.hpp"
32 #include <climits>
33 
34 #define CASADI_THROW_ERROR(FNAME, WHAT) \
35 throw CasadiException("Error in Sparsity::" FNAME " at " + CASADI_WHERE + ":\n"\
36  + std::string(WHAT));
37 
38 namespace casadi {
40  // Singletons
41  class EmptySparsity : public Sparsity {
42  public:
43  EmptySparsity() {
44  const casadi_int colind[1] = {0};
45  own(new SparsityInternal(0, 0, colind, nullptr));
46  }
47  };
48 
49  class ScalarSparsity : public Sparsity {
50  public:
51  ScalarSparsity() {
52  const casadi_int colind[2] = {0, 1};
53  const casadi_int row[1] = {0};
54  own(new SparsityInternal(1, 1, colind, row));
55  }
56  };
57 
58  class ScalarSparseSparsity : public Sparsity {
59  public:
60  ScalarSparseSparsity() {
61  const casadi_int colind[2] = {0, 0};
62  const casadi_int row[1] = {0};
63  own(new SparsityInternal(1, 1, colind, row));
64  }
65  };
67 
68  Sparsity::Sparsity(casadi_int dummy) {
69  casadi_assert_dev(dummy==0);
70  }
71 
73  Sparsity ret;
74  ret.own(node);
75  return ret;
76  }
77 
78  Sparsity::Sparsity(casadi_int nrow, casadi_int ncol) {
79  casadi_assert_dev(nrow>=0);
80  casadi_assert_dev(ncol>=0);
81  std::vector<casadi_int> row, colind(ncol+1, 0);
82  assign_cached(nrow, ncol, colind, row);
83  }
84 
85  Sparsity::Sparsity(const std::pair<casadi_int, casadi_int>& rc) {
86  casadi_assert_dev(rc.first>=0);
87  casadi_assert_dev(rc.second>=0);
88  std::vector<casadi_int> row, colind(rc.second+1, 0);
89  assign_cached(rc.first, rc.second, colind, row);
90  }
91 
92  Sparsity::Sparsity(casadi_int nrow, casadi_int ncol, const std::vector<casadi_int>& colind,
93  const std::vector<casadi_int>& row, bool order_rows) {
94  casadi_assert_dev(nrow>=0);
95  casadi_assert_dev(ncol>=0);
96  assign_cached(nrow, ncol, colind, row, order_rows);
97  }
98 
99  Sparsity::Sparsity(casadi_int nrow, casadi_int ncol,
100  const casadi_int* colind, const casadi_int* row, bool order_rows) {
101  casadi_assert_dev(nrow>=0);
102  casadi_assert_dev(ncol>=0);
103  if (colind==nullptr || colind[ncol]==nrow*ncol) {
104  *this = dense(nrow, ncol);
105  } else {
106  std::vector<casadi_int> colindv(colind, colind+ncol+1);
107  std::vector<casadi_int> rowv(row, row+colind[ncol]);
108  assign_cached(nrow, ncol, colindv, rowv, order_rows);
109  }
110  }
111 
113  return static_cast<const SparsityInternal*>(SharedObject::operator->());
114  }
115 
117  return *static_cast<const SparsityInternal*>(get());
118  }
119 
121  return dynamic_cast<const SparsityInternal*>(ptr)!=nullptr;
122  }
123 
124  casadi_int Sparsity::size1() const {
125  return (*this)->size1();
126  }
127 
128  casadi_int Sparsity::size2() const {
129  return (*this)->size2();
130  }
131 
132  casadi_int Sparsity::numel() const {
133  return (*this)->numel();
134  }
135 
136  double Sparsity::density() const {
137  double r = 100;
138  r *= static_cast<double>(nnz());
139  r /= static_cast<double>(size1());
140  r /= static_cast<double>(size2());
141  return r;
142  }
143 
144  bool Sparsity::is_empty(bool both) const {
145  return (*this)->is_empty(both);
146  }
147 
148  casadi_int Sparsity::nnz() const {
149  return (*this)->nnz();
150  }
151 
152  std::pair<casadi_int, casadi_int> Sparsity::size() const {
153  return (*this)->size();
154  }
155 
156  casadi_int Sparsity::size(casadi_int axis) const {
157  switch (axis) {
158  case 1: return size1();
159  case 2: return size2();
160  }
161  casadi_error("Axis must be 1 or 2.");
162  }
163 
164  const casadi_int* Sparsity::row() const {
165  return (*this)->row();
166  }
167 
168  const casadi_int* Sparsity::colind() const {
169  return (*this)->colind();
170  }
171 
172  casadi_int Sparsity::row(casadi_int el) const {
173  if (el<0 || el>=nnz()) {
174  throw std::out_of_range("Sparsity::row: Index " + str(el)
175  + " out of range [0," + str(nnz()) + ")");
176  }
177  return row()[el];
178  }
179 
180  casadi_int Sparsity::colind(casadi_int cc) const {
181  if (cc<0 || cc>size2()) {
182  throw std::out_of_range("Sparsity::colind: Index "
183  + str(cc) + " out of range [0," + str(size2()) + "]");
184  }
185  return colind()[cc];
186  }
187 
188  void Sparsity::resize(casadi_int nrow, casadi_int ncol) {
189  if (size1()!=nrow || size2() != ncol) {
190  *this = (*this)->_resize(nrow, ncol);
191  }
192  }
193 
194  casadi_int Sparsity::add_nz(casadi_int rr, casadi_int cc) {
195  // If negative index, count from the back
196  if (rr<0) rr += size1();
197  if (cc<0) cc += size2();
198 
199  // Check consistency
200  casadi_assert(rr>=0 && rr<size1(), "Row index out of bounds");
201  casadi_assert(cc>=0 && cc<size2(), "Column index out of bounds");
202 
203  // Quick return if matrix is dense
204  if (is_dense()) return rr+cc*size1();
205 
206  // Get sparsity pattern
207  casadi_int size1=this->size1(), size2=this->size2(), nnz=this->nnz();
208  const casadi_int *colind = this->colind(), *row = this->row();
209 
210  // Quick return if we are adding an element to the end
211  if (colind[cc]==nnz || (colind[cc+1]==nnz && row[nnz-1]<rr)) {
212  std::vector<casadi_int> rowv(nnz+1);
213  std::copy(row, row+nnz, rowv.begin());
214  rowv[nnz] = rr;
215  std::vector<casadi_int> colindv(colind, colind+size2+1);
216  for (casadi_int c=cc; c<size2; ++c) colindv[c+1]++;
217  assign_cached(size1, size2, colindv, rowv);
218  return rowv.size()-1;
219  }
220 
221  // go to the place where the element should be
222  casadi_int ind;
223  for (ind=colind[cc]; ind<colind[cc+1]; ++ind) { // better: loop from the back to the front
224  if (row[ind] == rr) {
225  return ind; // element exists
226  } else if (row[ind] > rr) {
227  break; // break at the place where the element should be added
228  }
229  }
230 
231  // insert the element
232  std::vector<casadi_int> rowv = get_row(), colindv = get_colind();
233  rowv.insert(rowv.begin()+ind, rr);
234  for (casadi_int c=cc+1; c<size2+1; ++c) colindv[c]++;
235 
236  // Return the location of the new element
237  assign_cached(size1, size2, colindv, rowv);
238  return ind;
239  }
240 
241  bool Sparsity::has_nz(casadi_int rr, casadi_int cc) const {
242  return get_nz(rr, cc)!=-1;
243  }
244 
245 
246  casadi_int Sparsity::get_nz(casadi_int rr, casadi_int cc) const {
247  return (*this)->get_nz(rr, cc);
248  }
249 
251  casadi_assert_dev(x.is_reshape(sp));
252  return sp;
253  }
254 
256  casadi_assert_dev(x.nnz()==sp.nnz());
257  return sp;
258  }
259 
260  Sparsity Sparsity::reshape(const Sparsity& x, casadi_int nrow, casadi_int ncol) {
261  return x->_reshape(nrow, ncol);
262  }
263 
264  std::vector<casadi_int> Sparsity::get_nz(const std::vector<casadi_int>& rr,
265  const std::vector<casadi_int>& cc) const {
266  return (*this)->get_nz(rr, cc);
267  }
268 
269  bool Sparsity::is_scalar(bool scalar_and_dense) const {
270  return (*this)->is_scalar(scalar_and_dense);
271  }
272 
273  bool Sparsity::is_dense() const {
274  return (*this)->is_dense();
275  }
276 
277  bool Sparsity::is_diag() const {
278  return (*this)->is_diag();
279  }
280 
281  bool Sparsity::is_row() const {
282  return (*this)->is_row();
283  }
284 
285  bool Sparsity::is_column() const {
286  return (*this)->is_column();
287  }
288 
289  bool Sparsity::is_vector() const {
290  return (*this)->is_vector();
291  }
292 
293  bool Sparsity::is_square() const {
294  return (*this)->is_square();
295  }
296 
298  return (*this)->is_permutation();
299  }
300 
301  bool Sparsity::is_selection(bool allow_empty) const {
302  return (*this)->is_selection(allow_empty);
303  }
304 
305  bool Sparsity::is_orthonormal(bool allow_empty) const {
306  return (*this)->is_orthonormal(allow_empty);
307  }
308 
309  bool Sparsity::is_orthonormal_rows(bool allow_empty) const {
310  return (*this)->is_orthonormal_rows(allow_empty);
311  }
312 
313  bool Sparsity::is_orthonormal_columns(bool allow_empty) const {
314  return (*this)->is_orthonormal_columns(allow_empty);
315  }
316 
317  bool Sparsity::is_symmetric() const {
318  return (*this)->is_symmetric();
319  }
320 
321  bool Sparsity::is_tril(bool strictly) const {
322  return (*this)->is_tril(strictly);
323  }
324 
325  bool Sparsity::is_triu(bool strictly) const {
326  return (*this)->is_triu(strictly);
327  }
328 
329  Sparsity Sparsity::sub(const std::vector<casadi_int>& rr, const Sparsity& sp,
330  std::vector<casadi_int>& mapping, bool ind1) const {
331  return (*this)->sub(rr, *sp, mapping, ind1);
332  }
333 
334  Sparsity Sparsity::sub(const std::vector<casadi_int>& rr, const std::vector<casadi_int>& cc,
335  std::vector<casadi_int>& mapping, bool ind1) const {
336  return (*this)->sub(rr, cc, mapping, ind1);
337  }
338 
339  std::vector<casadi_int> Sparsity::erase(const std::vector<casadi_int>& rr,
340  const std::vector<casadi_int>& cc, bool ind1) {
341  std::vector<casadi_int> mapping;
342  *this = (*this)->_erase(rr, cc, ind1, mapping);
343  return mapping;
344  }
345 
346  std::vector<casadi_int> Sparsity::erase(const std::vector<casadi_int>& rr, bool ind1) {
347  std::vector<casadi_int> mapping;
348  *this = (*this)->_erase(rr, ind1, mapping);
349  return mapping;
350  }
351 
352  casadi_int Sparsity::nnz_lower(bool strictly) const {
353  return (*this)->nnz_lower(strictly);
354  }
355 
356  casadi_int Sparsity::nnz_upper(bool strictly) const {
357  return (*this)->nnz_upper(strictly);
358  }
359 
360  casadi_int Sparsity::nnz_diag() const {
361  return (*this)->nnz_diag();
362  }
363 
364  std::vector<casadi_int> Sparsity::get_colind() const {
365  return (*this)->get_colind();
366  }
367 
368  std::vector<casadi_int> Sparsity::get_col() const {
369  return (*this)->get_col();
370  }
371 
372  std::vector<casadi_int> Sparsity::get_row() const {
373  return (*this)->get_row();
374  }
375 
376  void Sparsity::get_ccs(std::vector<casadi_int>& colind, std::vector<casadi_int>& row) const {
377  colind = get_colind();
378  row = get_row();
379  }
380 
381  void Sparsity::get_crs(std::vector<casadi_int>& rowind, std::vector<casadi_int>& col) const {
382  T().get_ccs(rowind, col);
383  }
384 
385  void Sparsity::get_triplet(std::vector<casadi_int>& row, std::vector<casadi_int>& col) const {
386  row = get_row();
387  col = get_col();
388  }
389 
390  Sparsity Sparsity::transpose(std::vector<casadi_int>& mapping, bool invert_mapping) const {
391  return (*this)->transpose(mapping, invert_mapping);
392  }
393 
395  return (*this)->T();
396  }
397 
398  Sparsity Sparsity::combine(const Sparsity& y, bool f0x_is_zero,
399  bool fx0_is_zero,
400  std::vector<unsigned char>& mapping) const {
401  return (*this)->combine(y, f0x_is_zero, fx0_is_zero, mapping);
402  }
403 
404  Sparsity Sparsity::combine(const Sparsity& y, bool f0x_is_zero,
405  bool fx0_is_zero) const {
406  return (*this)->combine(y, f0x_is_zero, fx0_is_zero);
407  }
408 
409  Sparsity Sparsity::unite(const Sparsity& y, std::vector<unsigned char>& mapping) const {
410  return (*this)->combine(y, false, false, mapping);
411  }
412 
414  return (*this)->combine(y, false, false);
415  }
416 
418  std::vector<unsigned char>& mapping) const {
419  return (*this)->combine(y, true, true, mapping);
420  }
421 
423  return (*this)->combine(y, true, true);
424  }
425 
426  bool Sparsity::is_subset(const Sparsity& rhs) const {
427  return (*this)->is_subset(rhs);
428  }
429 
431  // Check matching dimensions
432  casadi_assert(x.size2()==y.size1(),
433  "Matrix product with incompatible dimensions. Lhs is "
434  + x.dim() + " and rhs is " + y.dim() + ".");
435 
436  return x->_mtimes(y);
437  }
438 
439  bool Sparsity::is_stacked(const Sparsity& y, casadi_int n) const {
440  return (*this)->is_stacked(y, n);
441  }
442 
443  bool Sparsity::is_equal(const Sparsity& y) const {
444  return (*this)->is_equal(y);
445  }
446 
447  bool Sparsity::is_equal(casadi_int nrow, casadi_int ncol, const std::vector<casadi_int>& colind,
448  const std::vector<casadi_int>& row) const {
449  return (*this)->is_equal(nrow, ncol, colind, row);
450  }
451 
452  bool Sparsity::is_equal(casadi_int nrow, casadi_int ncol,
453  const casadi_int* colind, const casadi_int* row) const {
454  return (*this)->is_equal(nrow, ncol, colind, row);
455  }
456 
458  return unite(b);
459  }
460 
462  std::vector< unsigned char > mapping;
463  return intersect(b, mapping);
464  }
465 
467  return (*this)->pattern_inverse();
468  }
469 
470  void Sparsity::append(const Sparsity& sp) {
471  if (sp.size1()==0 && sp.size2()==0) {
472  // Appending pattern is empty
473  return;
474  } else if (size1()==0 && size2()==0) {
475  // This is empty
476  *this = sp;
477  } else {
478  casadi_assert(size2()==sp.size2(),
479  "Sparsity::append: Dimension mismatch. "
480  "You attempt to append a shape " + sp.dim()
481  + " to a shape " + dim()
482  + ". The number of columns must match.");
483  if (sp.size1()==0) {
484  // No rows to add
485  return;
486  } else if (size1()==0) {
487  // No rows before
488  *this = sp;
489  } else if (is_column()) {
490  // Append to vector (inefficient)
491  *this = (*this)->_appendVector(*sp);
492  } else {
493  // Append to matrix (inefficient)
494  *this = vertcat({*this, sp});
495  }
496  }
497  }
498 
500  if (sp.size1()==0 && sp.size2()==0) {
501  // Appending pattern is empty
502  return;
503  } else if (size1()==0 && size2()==0) {
504  // This is empty
505  *this = sp;
506  } else {
507  casadi_assert(size1()==sp.size1(),
508  "Sparsity::appendColumns: Dimension mismatch. You attempt to "
509  "append a shape " + sp.dim() + " to a shape "
510  + dim() + ". The number of rows must match.");
511  if (sp.size2()==0) {
512  // No columns to add
513  return;
514  } else if (size2()==0) {
515  // No columns before
516  *this = sp;
517  } else {
518  // Append to matrix (expensive)
519  *this = (*this)->_appendColumns(*sp);
520  }
521  }
522  }
523 
525  static CachingMap ret;
526  return ret;
527  }
528 
530  static ScalarSparsity ret;
531  return ret;
532  }
533 
535  static ScalarSparseSparsity ret;
536  return ret;
537  }
538 
540  static EmptySparsity ret;
541  return ret;
542  }
543 
544  void Sparsity::enlarge(casadi_int nrow, casadi_int ncol, const std::vector<casadi_int>& rr,
545  const std::vector<casadi_int>& cc, bool ind1) {
546  enlargeColumns(ncol, cc, ind1);
547  enlargeRows(nrow, rr, ind1);
548  }
549 
550  void Sparsity::enlargeColumns(casadi_int ncol, const std::vector<casadi_int>& cc, bool ind1) {
551  casadi_assert_dev(cc.size() == size2());
552  if (cc.empty()) {
553  *this = Sparsity(size1(), ncol);
554  } else {
555  *this = (*this)->_enlargeColumns(ncol, cc, ind1);
556  }
557  }
558 
559  void Sparsity::enlargeRows(casadi_int nrow, const std::vector<casadi_int>& rr, bool ind1) {
560  casadi_assert_dev(rr.size() == size1());
561  if (rr.empty()) {
562  *this = Sparsity(nrow, size2());
563  } else {
564  *this = (*this)->_enlargeRows(nrow, rr, ind1);
565  }
566  }
567 
568  Sparsity Sparsity::diag(casadi_int nrow, casadi_int ncol) {
569  // Smallest dimension
570  casadi_int n = std::min(nrow, ncol);
571 
572  // Column offset
573  std::vector<casadi_int> colind(ncol+1, n);
574  for (casadi_int cc=0; cc<n; ++cc) colind[cc] = cc;
575 
576  // Row
577  std::vector<casadi_int> row = range(n);
578 
579  // Create pattern from vectors
580  return Sparsity(nrow, ncol, colind, row);
581  }
582 
583  Sparsity Sparsity::makeDense(std::vector<casadi_int>& mapping) const {
584  return (*this)->makeDense(mapping);
585  }
586 
587  std::string Sparsity::dim(bool with_nz) const {
588  return (*this)->dim(with_nz);
589  }
590 
591  std::string Sparsity::postfix_dim() const {
592  if (is_dense()) {
593  if (is_scalar()) {
594  return "";
595  } else if (is_empty(true)) {
596  return "[]";
597  } else if (is_column()) {
598  return "[" + str(size1()) + "]";
599  } else {
600  return "[" + dim(false) + "]";
601  }
602  } else {
603  return "[" + dim(true) + "]";
604  }
605  }
606 
607  std::string Sparsity::repr_el(casadi_int k) const {
608  return (*this)->repr_el(k);
609  }
610 
611  Sparsity Sparsity::get_diag(std::vector<casadi_int>& mapping) const {
612  return (*this)->get_diag(mapping);
613  }
614 
615  std::vector<casadi_int> Sparsity::etree(bool ata) const {
616  std::vector<casadi_int> parent(size2()), w(size1() + size2());
617  SparsityInternal::etree(*this, get_ptr(parent), get_ptr(w), ata);
618  return parent;
619  }
620 
621  Sparsity Sparsity::ldl(std::vector<casadi_int>& p, bool amd) const {
622  casadi_assert(is_symmetric(),
623  "LDL factorization requires a symmetric matrix");
624  // Recursive call if AMD
625  if (amd) {
626  // Get AMD reordering
627  p = this->amd();
628  // Permute sparsity pattern
629  std::vector<casadi_int> tmp;
630  Sparsity Aperm = sub(p, p, tmp);
631  // Call recursively
632  return Aperm.ldl(tmp, false);
633  }
634  // Dimension
635  casadi_int n=size1();
636  // Natural ordering
637  p = range(n);
638  // Work vector
639  std::vector<casadi_int> w(3*n);
640  // Elimination tree
641  std::vector<casadi_int> parent(n);
642  // Calculate colind in L (strictly lower entries only)
643  std::vector<casadi_int> L_colind(1+n);
644  SparsityInternal::ldl_colind(*this, get_ptr(parent), get_ptr(L_colind), get_ptr(w));
645  // Get rows in L (strictly lower entries only)
646  std::vector<casadi_int> L_row(L_colind.back());
647  SparsityInternal::ldl_row(*this, get_ptr(parent), get_ptr(L_colind), get_ptr(L_row),
648  get_ptr(w));
649  // Sparsity of L^T
650  return Sparsity(n, n, L_colind, L_row, true).T();
651  }
652 
654  qr_sparse(Sparsity& V, Sparsity& R, std::vector<casadi_int>& prinv,
655  std::vector<casadi_int>& pc, bool amd) const {
656  // Dimensions
657  casadi_int size1=this->size1(), size2=this->size2();
658 
659  // Recursive call if AMD
660  if (amd) {
661  // Get AMD reordering
662  pc = mtimes(T(), *this).amd();
663  // Permute sparsity pattern
664  std::vector<casadi_int> tmp;
665  Sparsity Aperm = sub(range(size1), pc, tmp);
666  // Call recursively
667  return Aperm.qr_sparse(V, R, prinv, tmp, false);
668  }
669 
670  // No column permutation
671  pc = range(size2);
672 
673  // Allocate memory
674  std::vector<casadi_int> leftmost(size1);
675  std::vector<casadi_int> parent(size2);
676  prinv.resize(size1 + size2);
677  std::vector<casadi_int> iw(size1 + 7*size2 + 1);
678 
679  // Initialize QP solve
680  casadi_int nrow_ext, v_nnz, r_nnz;
681  SparsityInternal::qr_init(*this, T(),
682  get_ptr(leftmost), get_ptr(parent), get_ptr(prinv),
683  &nrow_ext, &v_nnz, &r_nnz, get_ptr(iw));
684 
685  // Calculate sparsities
686  std::vector<casadi_int> sp_v(2 + size2 + 1 + v_nnz);
687  std::vector<casadi_int> sp_r(2 + size2 + 1 + r_nnz);
688  SparsityInternal::qr_sparsities(*this, nrow_ext, get_ptr(sp_v), get_ptr(sp_r),
689  get_ptr(leftmost), get_ptr(parent), get_ptr(prinv),
690  get_ptr(iw));
691  prinv.resize(nrow_ext);
692  V = compressed(sp_v, true);
693  R = compressed(sp_r, true);
694  }
695 
696  casadi_int Sparsity::dfs(casadi_int j, casadi_int top, std::vector<casadi_int>& xi,
697  std::vector<casadi_int>& pstack,
698  const std::vector<casadi_int>& pinv,
699  std::vector<bool>& marked) const {
700  return (*this)->dfs(j, top, xi, pstack, pinv, marked);
701  }
702 
703  casadi_int Sparsity::scc(std::vector<casadi_int>& index, std::vector<casadi_int>& offset) const {
704  return (*this)->scc(index, offset);
705  }
706 
707  std::vector<casadi_int> Sparsity::amd() const {
708  return (*this)->amd();
709  }
710 
711  casadi_int Sparsity::btf(std::vector<casadi_int>& rowperm, std::vector<casadi_int>& colperm,
712  std::vector<casadi_int>& rowblock, std::vector<casadi_int>& colblock,
713  std::vector<casadi_int>& coarse_rowblock,
714  std::vector<casadi_int>& coarse_colblock) const {
715  try {
716  return (*this)->btf(rowperm, colperm, rowblock, colblock,
717  coarse_rowblock, coarse_colblock);
718  } catch (std::exception &e) {
719  CASADI_THROW_ERROR("btf", e.what());
720  }
721  }
722 
723  void Sparsity::spsolve(bvec_t* X, bvec_t* B, bool tr) const {
724  (*this)->spsolve(X, B, tr);
725  }
726 
727  bool Sparsity::rowsSequential(bool strictly) const {
728  return (*this)->rowsSequential(strictly);
729  }
730 
731  void Sparsity::removeDuplicates(std::vector<casadi_int>& mapping) {
732  *this = (*this)->_removeDuplicates(mapping);
733  }
734 
735  std::vector<casadi_int> Sparsity::find(bool ind1) const {
736  std::vector<casadi_int> loc;
737  find(loc, ind1);
738  return loc;
739  }
740 
741  void Sparsity::find(std::vector<casadi_int>& loc, bool ind1) const {
742  (*this)->find(loc, ind1);
743  }
744 
745  void Sparsity::get_nz(std::vector<casadi_int>& indices) const {
746  (*this)->get_nz(indices);
747  }
748 
749  Sparsity Sparsity::uni_coloring(const Sparsity& AT, casadi_int cutoff) const {
750  if (AT.is_null()) {
751  return (*this)->uni_coloring(T(), cutoff);
752  } else {
753  return (*this)->uni_coloring(AT, cutoff);
754  }
755  }
756 
757  Sparsity Sparsity::star_coloring(casadi_int ordering, casadi_int cutoff) const {
758  return (*this)->star_coloring(ordering, cutoff);
759  }
760 
761  Sparsity Sparsity::star_coloring2(casadi_int ordering, casadi_int cutoff) const {
762  return (*this)->star_coloring2(ordering, cutoff);
763  }
764 
765  std::vector<casadi_int> Sparsity::largest_first() const {
766  return (*this)->largest_first();
767  }
768 
769  Sparsity Sparsity::pmult(const std::vector<casadi_int>& p, bool permute_rows,
770  bool permute_columns, bool invert_permutation) const {
771  return (*this)->pmult(p, permute_rows, permute_columns, invert_permutation);
772  }
773 
774  void Sparsity::spy_matlab(const std::string& mfile) const {
775  (*this)->spy_matlab(mfile);
776  }
777 
778  void Sparsity::export_code(const std::string& lang, std::ostream &stream,
779  const Dict& options) const {
780  (*this)->export_code(lang, stream, options);
781  }
782 
783  void Sparsity::spy(std::ostream &stream) const {
784  (*this)->spy(stream);
785  }
786 
787  bool Sparsity::is_transpose(const Sparsity& y) const {
788  return (*this)->is_transpose(*y);
789  }
790 
791  bool Sparsity::is_reshape(const Sparsity& y) const {
792  return (*this)->is_reshape(*y);
793  }
794 
795  std::size_t Sparsity::hash() const {
796  return (*this)->hash();
797  }
798 
799  void Sparsity::assign_cached(casadi_int nrow, casadi_int ncol,
800  const std::vector<casadi_int>& colind,
801  const std::vector<casadi_int>& row, bool order_rows) {
802  casadi_assert_dev(colind.size()==ncol+1);
803  casadi_assert_dev(row.size()==colind.back());
804  assign_cached(nrow, ncol, get_ptr(colind), get_ptr(row), order_rows);
805  }
806 
807  void Sparsity::assign_cached(casadi_int nrow, casadi_int ncol,
808  const casadi_int* colind, const casadi_int* row, bool order_rows) {
809  // Scalars and empty patterns are handled separately
810  if (ncol==0 && nrow==0) {
811  // If empty
812  *this = getEmpty();
813  return;
814  } else if (ncol==1 && nrow==1) {
815  if (colind[ncol]==0) {
816  // If sparse scalar
817  *this = getScalarSparse();
818  return;
819  } else {
820  // If dense scalar
821  *this = getScalar();
822  return;
823  }
824  }
825 
826  // Make sure colind starts with zero
827  casadi_assert(colind[0]==0,
828  "Compressed Column Storage is not sane. "
829  "First element of colind must be zero.");
830 
831  // Make sure colind is montone
832  for (casadi_int c=0; c<ncol; c++) {
833  casadi_assert(colind[c+1]>=colind[c],
834  "Compressed Column Storage is not sane. "
835  "colind must be monotone.");
836  }
837 
838  // Check if rows correct and ordered without duplicates
839  bool rows_ordered = true;
840  for (casadi_int c=0; c<ncol; ++c) {
841  casadi_int last_r = -1;
842  for (casadi_int k=colind[c]; k<colind[c+1]; ++k) {
843  casadi_int r = row[k];
844  // Make sure values are in within the [0,ncol) range
845  casadi_assert(r>=0 && r<nrow,
846  "Compressed Column Storage is not sane.\n"
847  "row[ " + str(k) + " == " + str(r) + " not in range "
848  "[0, " + str(nrow) + ")");
849  // Check if ordered
850  if (r<=last_r) rows_ordered = false;
851  last_r = r;
852  }
853  }
854 
855  // If unordered, need to order
856  if (!rows_ordered) {
857  casadi_assert(order_rows,
858  "Compressed Column Storage is not sane.\n"
859  "Row indices not strictly monotonically increasing for each "
860  "column and reordering is not enabled.");
861  // Number of nonzeros
862  casadi_int nnz = colind[ncol];
863  // Get all columns
864  std::vector<casadi_int> col(nnz);
865  for (casadi_int c=0; c<ncol; ++c) {
866  for (casadi_int k=colind[c]; k<colind[c+1]; ++k) col[k] = c;
867  }
868  // Make sane via triplet format
869  *this = triplet(nrow, ncol, std::vector<casadi_int>(row, row+nnz), col);
870  return;
871  }
872 
873  // Hash the pattern
874  std::size_t h = hash_sparsity(nrow, ncol, colind, row);
875 
876 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
877  // Safe access to CachingMap
878  std::lock_guard<std::mutex> lock(cachingmap_mtx);
879 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
880 
881  // Get a reference to the cache
882  CachingMap& cache = getCache();
883 
884  // Record the current number of buckets (for garbage collection below)
885  casadi_int bucket_count_before = cache.bucket_count();
886 
887  // WORKAROUND, functions do not appear to work when bucket_count==0
888  if (bucket_count_before>0) {
889 
890  // Find the range of patterns equal to the key (normally only zero or one)
891  std::pair<CachingMap::iterator, CachingMap::iterator> eq = cache.equal_range(h);
892 
893  // Loop over maching patterns
894  for (CachingMap::iterator i=eq.first; i!=eq.second; ++i) {
895 
896  // Get a weak reference to the cached sparsity pattern
897  WeakRef& wref = i->second;
898 
899  // Reference to the cached pattern
900  SharedObject ref_shared;
901 
902  // Check if the pattern still exists
903  if (wref.shared_if_alive(ref_shared)) {
904 
905  // Get an owning reference to the cached pattern
906  Sparsity ref = shared_cast<Sparsity>(ref_shared);
907 
908  // Check if the pattern matches
909  if (ref.is_equal(nrow, ncol, colind, row)) {
910 
911  // Found match!
912  own(ref.get());
913  return;
914 
915  } else { // There is a hash rowision (unlikely, but possible)
916  // Leave the pattern alone, continue to the next matching pattern
917  continue;
918  }
919  } else {
920 
921  // Check if one of the other cache entries indeed has a matching sparsity
922  CachingMap::iterator j=i;
923  j++; // Start at the next matching key
924  for (; j!=eq.second; ++j) {
925 
926  // Reference to the cached pattern
927  SharedObject ref_shared;
928  if (j->second.shared_if_alive(ref_shared)) {
929 
930  // Recover cached sparsity
931  Sparsity ref = shared_cast<Sparsity>(ref_shared);
932 
933  // Match found if sparsity matches
934  if (ref.is_equal(nrow, ncol, colind, row)) {
935  own(ref.get());
936  return;
937  }
938  }
939  }
940 
941  // The cached entry has been deleted, create a new one
942  own(new SparsityInternal(nrow, ncol, colind, row));
943 
944  // Cache this pattern
945  wref = *this;
946 
947  // Return
948  return;
949  }
950  }
951  }
952 
953  // No matching sparsity pattern could be found, create a new one
954  own(new SparsityInternal(nrow, ncol, colind, row));
955 
956  // Cache this pattern
957  cache.insert(std::pair<std::size_t, WeakRef>(h, *this));
958 
959  // Garbage collection (currently only supported for unordered_multimap)
960  casadi_int bucket_count_after = cache.bucket_count();
961 
962  // We we increased the number of buckets, take time to garbage-collect deleted references
963  if (bucket_count_before!=bucket_count_after) {
964  CachingMap::const_iterator i=cache.begin();
965  while (i!=cache.end()) {
966  if (!i->second.alive()) {
967  i = cache.erase(i);
968  } else {
969  i++;
970  }
971  }
972  }
973  }
974 
975 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
976  std::mutex Sparsity::cachingmap_mtx;
977 #endif //CASADI_WITH_THREADSAFE_SYMBOLICS
978 
979  Sparsity Sparsity::tril(const Sparsity& x, bool includeDiagonal) {
980  return x->_tril(includeDiagonal);
981  }
982 
983  Sparsity Sparsity::triu(const Sparsity& x, bool includeDiagonal) {
984  return x->_triu(includeDiagonal);
985  }
986 
987  std::vector<casadi_int> Sparsity::get_lower() const {
988  return (*this)->get_lower();
989  }
990 
991  std::vector<casadi_int> Sparsity::get_upper() const {
992  return (*this)->get_upper();
993  }
994 
995 
996  std::size_t hash_sparsity(casadi_int nrow, casadi_int ncol, const std::vector<casadi_int>& colind,
997  const std::vector<casadi_int>& row) {
998  return hash_sparsity(nrow, ncol, get_ptr(colind), get_ptr(row));
999  }
1000 
1001  std::size_t hash_sparsity(casadi_int nrow, casadi_int ncol,
1002  const casadi_int* colind, const casadi_int* row) {
1003  // Condense the sparsity pattern to a single, deterministric number
1004  std::size_t ret=0;
1005  hash_combine(ret, nrow);
1006  hash_combine(ret, ncol);
1007  hash_combine(ret, colind, ncol+1);
1008  hash_combine(ret, row, colind[ncol]);
1009  return ret;
1010  }
1011 
1012  Sparsity Sparsity::dense(casadi_int nrow, casadi_int ncol) {
1013  casadi_assert_dev(nrow>=0);
1014  casadi_assert_dev(ncol>=0);
1015  // Column offset
1016  std::vector<casadi_int> colind(ncol+1);
1017  for (casadi_int cc=0; cc<ncol+1; ++cc) colind[cc] = cc*nrow;
1018 
1019  // Row
1020  std::vector<casadi_int> row(ncol*nrow);
1021  for (casadi_int cc=0; cc<ncol; ++cc)
1022  for (casadi_int rr=0; rr<nrow; ++rr)
1023  row[rr+cc*nrow] = rr;
1024 
1025  return Sparsity(nrow, ncol, colind, row);
1026  }
1027 
1028  Sparsity Sparsity::upper(casadi_int n) {
1029  casadi_assert(n>=0, "Sparsity::upper expects a positive integer as argument");
1030  casadi_int nrow=n, ncol=n;
1031  std::vector<casadi_int> colind, row;
1032  colind.reserve(ncol+1);
1033  row.reserve((n*(n+1))/2);
1034 
1035  // Loop over columns
1036  colind.push_back(0);
1037  for (casadi_int cc=0; cc<ncol; ++cc) {
1038  // Loop over rows for the upper triangular half
1039  for (casadi_int rr=0; rr<=cc; ++rr) {
1040  row.push_back(rr);
1041  }
1042  colind.push_back(row.size());
1043  }
1044 
1045  // Return the pattern
1046  return Sparsity(nrow, ncol, colind, row);
1047  }
1048 
1049  Sparsity Sparsity::lower(casadi_int n) {
1050  casadi_assert(n>=0, "Sparsity::lower expects a positive integer as argument");
1051  casadi_int nrow=n, ncol=n;
1052  std::vector<casadi_int> colind, row;
1053  colind.reserve(ncol+1);
1054  row.reserve((n*(n+1))/2);
1055 
1056  // Loop over columns
1057  colind.push_back(0);
1058  for (casadi_int cc=0; cc<ncol; ++cc) {
1059  // Loop over rows for the lower triangular half
1060  for (casadi_int rr=cc; rr<nrow; ++rr) {
1061  row.push_back(rr);
1062  }
1063  colind.push_back(row.size());
1064  }
1065 
1066  // Return the pattern
1067  return Sparsity(nrow, ncol, colind, row);
1068  }
1069 
1070  Sparsity Sparsity::band(casadi_int n, casadi_int p) {
1071  casadi_assert(n>=0, "Sparsity::band expects a positive integer as argument");
1072  casadi_assert((p<0? -p : p)<n,
1073  "Sparsity::band: position of band schould be smaller then size argument");
1074 
1075  casadi_int nc = n-(p<0? -p : p);
1076 
1077  std::vector< casadi_int > row(nc);
1078 
1079  casadi_int offset = std::max(p, casadi_int(0));
1080  for (casadi_int i=0;i<nc;i++) {
1081  row[i]=i+offset;
1082  }
1083 
1084  std::vector< casadi_int > colind(n+1);
1085 
1086  offset = std::min(p, casadi_int(0));
1087  for (casadi_int i=0;i<n+1;i++) {
1088  colind[i] = std::max(std::min(i+offset, nc), casadi_int(0));
1089  }
1090 
1091  return Sparsity(n, n, colind, row);
1092 
1093  }
1094 
1095  Sparsity Sparsity::banded(casadi_int n, casadi_int p) {
1096  // This is not an efficient implementation
1097  Sparsity ret = Sparsity(n, n);
1098  for (casadi_int i=-p;i<=p;++i) {
1099  ret = ret + Sparsity::band(n, i);
1100  }
1101  return ret;
1102  }
1103 
1104  Sparsity Sparsity::unit(casadi_int n, casadi_int el) {
1105  std::vector<casadi_int> row(1, el), colind(2);
1106  colind[0] = 0;
1107  colind[1] = 1;
1108  return Sparsity(n, 1, colind, row);
1109  }
1110 
1111  Sparsity Sparsity::rowcol(const std::vector<casadi_int>& row, const std::vector<casadi_int>& col,
1112  casadi_int nrow, casadi_int ncol) {
1113  std::vector<casadi_int> all_rows, all_cols;
1114  all_rows.reserve(row.size()*col.size());
1115  all_cols.reserve(row.size()*col.size());
1116  for (std::vector<casadi_int>::const_iterator c_it=col.begin(); c_it!=col.end(); ++c_it) {
1117  casadi_assert(*c_it>=0 && *c_it<ncol, "Sparsity::rowcol: Column index out of bounds");
1118  for (std::vector<casadi_int>::const_iterator r_it=row.begin(); r_it!=row.end(); ++r_it) {
1119  casadi_assert(*r_it>=0 && *r_it<nrow, "Sparsity::rowcol: Row index out of bounds");
1120  all_rows.push_back(*r_it);
1121  all_cols.push_back(*c_it);
1122  }
1123  }
1124  return Sparsity::triplet(nrow, ncol, all_rows, all_cols);
1125  }
1126 
1127  Sparsity Sparsity::triplet(casadi_int nrow, casadi_int ncol, const std::vector<casadi_int>& row,
1128  const std::vector<casadi_int>& col, std::vector<casadi_int>& mapping,
1129  bool invert_mapping) {
1130  // Assert dimensions
1131  casadi_assert_dev(nrow>=0);
1132  casadi_assert_dev(ncol>=0);
1133  casadi_assert(col.size()==row.size(), "inconsistent lengths");
1134 
1135  // Create the return sparsity pattern and access vectors
1136  std::vector<casadi_int> r_colind(ncol+1, 0);
1137  std::vector<casadi_int> r_row;
1138  r_row.reserve(row.size());
1139 
1140  // Consistency check and check if elements are already perfectly ordered with no duplicates
1141  casadi_int last_col=-1, last_row=-1;
1142  bool perfectly_ordered=true;
1143  for (casadi_int k=0; k<col.size(); ++k) {
1144  // Consistency check
1145  casadi_assert(col[k]>=0 && col[k]<ncol,
1146  "Column index (" + str(col[k]) + ") out of bounds [0," + str(ncol) + "[");
1147  casadi_assert(row[k]>=0 && row[k]<nrow,
1148  "Row index out of bounds (" + str(row[k]) + ") out of bounds [0," + str(nrow) + "[");
1149 
1150  // Check if ordering is already perfect
1151  perfectly_ordered = perfectly_ordered && (col[k]<last_col ||
1152  (col[k]==last_col && row[k]<=last_row));
1153  last_col = col[k];
1154  last_row = row[k];
1155  }
1156 
1157  // Quick return if perfectly ordered
1158  if (perfectly_ordered) {
1159  // Save rows
1160  r_row.resize(row.size());
1161  std::copy(row.begin(), row.end(), r_row.begin());
1162 
1163  // Find offset index
1164  casadi_int el=0;
1165  for (casadi_int i=0; i<ncol; ++i) {
1166  while (el<col.size() && col[el]==i) el++;
1167  r_colind[i+1] = el;
1168  }
1169 
1170  // Identity mapping
1171  mapping.resize(row.size());
1172  for (casadi_int k=0; k<row.size(); ++k) mapping[k] = k;
1173 
1174  // Quick return
1175  return Sparsity(nrow, ncol, r_colind, r_row);
1176  }
1177 
1178  // Reuse data
1179  std::vector<casadi_int>& mapping1 = invert_mapping ? r_row : mapping;
1180  std::vector<casadi_int>& mapping2 = invert_mapping ? mapping : r_row;
1181 
1182  // Make sure that enough memory is allocated to use as a work vector
1183  mapping1.reserve(std::max(nrow+1, static_cast<casadi_int>(col.size())));
1184 
1185  // Number of elements in each row
1186  std::vector<casadi_int>& rowcount = mapping1; // reuse memory
1187  rowcount.resize(nrow+1);
1188  std::fill(rowcount.begin(), rowcount.end(), 0);
1189  for (std::vector<casadi_int>::const_iterator it=row.begin(); it!=row.end(); ++it) {
1190  rowcount[*it+1]++;
1191  }
1192 
1193  // Cumsum to get index offset for each row
1194  for (casadi_int i=0; i<nrow; ++i) {
1195  rowcount[i+1] += rowcount[i];
1196  }
1197 
1198  // New row for each old row
1199  mapping2.resize(row.size());
1200  for (casadi_int k=0; k<row.size(); ++k) {
1201  mapping2[rowcount[row[k]]++] = k;
1202  }
1203 
1204  // Number of elements in each col
1205  // reuse memory, r_colind is already the right size
1206  std::vector<casadi_int>& colcount = r_colind;
1207  // and is filled with zeros
1208  for (std::vector<casadi_int>::const_iterator it=mapping2.begin(); it!=mapping2.end(); ++it) {
1209  colcount[col[*it]+1]++;
1210  }
1211 
1212  // Cumsum to get index offset for each col
1213  for (casadi_int i=0; i<ncol; ++i) {
1214  colcount[i+1] += colcount[i];
1215  }
1216 
1217  // New col for each old col
1218  mapping1.resize(col.size());
1219  for (std::vector<casadi_int>::const_iterator it=mapping2.begin(); it!=mapping2.end(); ++it) {
1220  mapping1[colcount[col[*it]]++] = *it;
1221  }
1222 
1223  // Current element in the return matrix
1224  casadi_int r_el = 0;
1225  r_row.resize(col.size());
1226 
1227  // Current nonzero
1228  std::vector<casadi_int>::const_iterator it=mapping1.begin();
1229 
1230  // Loop over columns
1231  r_colind[0] = 0;
1232  for (casadi_int i=0; i<ncol; ++i) {
1233 
1234  // Previous row (to detect duplicates)
1235  casadi_int j_prev = -1;
1236 
1237  // Loop over nonzero elements of the col
1238  while (it!=mapping1.end() && col[*it]==i) {
1239 
1240  // Get the element
1241  casadi_int el = *it;
1242  it++;
1243 
1244  // Get the row
1245  casadi_int j = row[el];
1246 
1247  // If not a duplicate, save to return matrix
1248  if (j!=j_prev)
1249  r_row[r_el++] = j;
1250 
1251  if (invert_mapping) {
1252  // Save to the inverse mapping
1253  mapping2[el] = r_el-1;
1254  } else {
1255  // If not a duplicate, save to the mapping vector
1256  if (j!=j_prev)
1257  mapping1[r_el-1] = el;
1258  }
1259 
1260  // Save row
1261  j_prev = j;
1262  }
1263 
1264  // Update col offset
1265  r_colind[i+1] = r_el;
1266  }
1267 
1268  // Resize the row vector
1269  r_row.resize(r_el);
1270 
1271  // Resize mapping matrix
1272  if (!invert_mapping) {
1273  mapping1.resize(r_el);
1274  }
1275 
1276  return Sparsity(nrow, ncol, r_colind, r_row);
1277  }
1278 
1279  Sparsity Sparsity::triplet(casadi_int nrow, casadi_int ncol, const std::vector<casadi_int>& row,
1280  const std::vector<casadi_int>& col) {
1281  std::vector<casadi_int> mapping;
1282  return Sparsity::triplet(nrow, ncol, row, col, mapping, false);
1283  }
1284 
1285  Sparsity Sparsity::nonzeros(casadi_int nrow, casadi_int ncol,
1286  const std::vector<casadi_int>& nz, bool ind1) {
1287  casadi_assert(nrow>0, "nrow must be >0.");
1288  std::vector<casadi_int> row(nz.size());
1289  std::vector<casadi_int> col(nz.size());
1290  for (casadi_int i=0;i<nz.size();++i) {
1291  casadi_int k = nz[i];
1292  k-= ind1;
1293  row[i] = k % nrow;
1294  col[i] = k / nrow;
1295  }
1296  return triplet(nrow, ncol, row, col);
1297  }
1298 
1299  bool Sparsity::is_singular() const {
1300  casadi_assert(is_square(),
1301  "is_singular: only defined for square matrices, but got " + dim());
1302  return sprank(*this)!=size2();
1303  }
1304 
1305  std::vector<casadi_int> Sparsity::compress(bool canonical) const {
1306  if (canonical) {
1307  // fallback
1308  } else if (is_dense()) {
1309  return {size1(), size2(), 1};
1310  }
1311  return (*this)->sp();
1312  }
1313 
1314  Sparsity::operator const std::vector<casadi_int>&() const {
1315  return (*this)->sp();
1316  }
1317 
1318  Sparsity::operator SparsityStruct() const {
1319  const casadi_int* sp = *this;
1320  casadi_int nrow = sp[0], ncol = sp[1];
1321  const casadi_int* colind = sp+2, *row = sp+2+ncol+1;
1322  return SparsityStruct{nrow, ncol, colind, row};
1323  }
1324 
1325  Sparsity Sparsity::compressed(const std::vector<casadi_int>& v, bool order_rows) {
1326  // Check consistency
1327  casadi_assert_dev(v.size() >= 2);
1328  casadi_int nrow = v[0];
1329  casadi_int ncol = v[1];
1330  casadi_assert_dev(v.size() >= 2 + ncol+1);
1331  casadi_int nnz = v[2 + ncol];
1332  bool dense = v.size() == 2 + ncol+1 && nrow*ncol==nnz;
1333  bool sparse = v.size() == 2 + ncol+1 + nnz;
1334  casadi_assert_dev(dense || sparse);
1335 
1336  // Call array version
1337  return compressed(&v.front(), order_rows);
1338  }
1339 
1340  Sparsity Sparsity::compressed(const casadi_int* v, bool order_rows) {
1341  casadi_assert_dev(v!=nullptr);
1342 
1343  // Get sparsity pattern
1344  casadi_int nrow = v[0];
1345  casadi_int ncol = v[1];
1346  const casadi_int *colind = v+2;
1347  if (colind[0]==1) {
1348  // Dense matrix - deviation from canonical form
1349  return Sparsity::dense(nrow, ncol);
1350  }
1351  casadi_int nnz = colind[ncol];
1352  if (nrow*ncol == nnz) {
1353  // Dense matrix
1354  return Sparsity::dense(nrow, ncol);
1355  } else {
1356  // Sparse matrix
1357  const casadi_int *row = v + 2 + ncol+1;
1358  return Sparsity(nrow, ncol,
1359  std::vector<casadi_int>(colind, colind+ncol+1),
1360  std::vector<casadi_int>(row, row+nnz), order_rows);
1361  }
1362  }
1363 
1364  Sparsity Sparsity::permutation(const std::vector<casadi_int>& p, bool invert) {
1365  casadi_assert(casadi::is_permutation(p),
1366  "Sparsity::permutation supplied list is not a permutation.");
1367  std::vector<casadi_int> colind = range(p.size()+1);
1368  if (invert) {
1369  return Sparsity(p.size(), p.size(), colind, p);
1370  } else {
1371  return Sparsity(p.size(), p.size(), colind, invert_permutation(p));
1372  }
1373  }
1374 
1375  const std::vector<casadi_int> Sparsity::permutation_vector(bool invert) const {
1376  casadi_assert(is_permutation(), "Sparsity::permutation called on non-permutation matrix.");
1377  if (invert) {
1378  return get_row();
1379  } else {
1380  return invert_permutation(get_row());
1381  }
1382  }
1383 
1384  casadi_int Sparsity::bw_upper() const {
1385  return (*this)->bw_upper();
1386  }
1387 
1388  casadi_int Sparsity::bw_lower() const {
1389  return (*this)->bw_lower();
1390  }
1391 
1392  Sparsity Sparsity::horzcat(const std::vector<Sparsity> & sp) {
1393  // Quick return if possible
1394  if (sp.empty()) return Sparsity(1, 0);
1395  if (sp.size()==1) return sp.front();
1396 
1397  // Count total nnz
1398  casadi_int nnz_total = 0;
1399  for (casadi_int i=0; i<sp.size(); ++i) nnz_total += sp[i].nnz();
1400 
1401  // Construct from vectors (triplet format)
1402  std::vector<casadi_int> ret_row, ret_col;
1403  ret_row.reserve(nnz_total);
1404  ret_col.reserve(nnz_total);
1405  casadi_int ret_ncol = 0;
1406  casadi_int ret_nrow = 0;
1407  for (casadi_int i=0; i<sp.size() && ret_nrow==0; ++i)
1408  ret_nrow = sp[i].size1();
1409 
1410  // Append all patterns
1411  for (std::vector<Sparsity>::const_iterator i=sp.begin(); i!=sp.end(); ++i) {
1412  // Get sparsity pattern
1413  casadi_int sp_nrow = i->size1();
1414  casadi_int sp_ncol = i->size2();
1415  const casadi_int* sp_colind = i->colind();
1416  const casadi_int* sp_row = i->row();
1417  casadi_assert(sp_nrow==ret_nrow || sp_nrow==0,
1418  "Sparsity::horzcat: Mismatching number of rows");
1419 
1420  // Add entries to pattern
1421  for (casadi_int cc=0; cc<sp_ncol; ++cc) {
1422  for (casadi_int k=sp_colind[cc]; k<sp_colind[cc+1]; ++k) {
1423  ret_row.push_back(sp_row[k]);
1424  ret_col.push_back(cc + ret_ncol);
1425  }
1426  }
1427 
1428  // Update offset
1429  ret_ncol += sp_ncol;
1430  }
1431  return Sparsity::triplet(ret_nrow, ret_ncol, ret_row, ret_col);
1432  }
1433 
1435  casadi_int a_ncol = a.size2();
1436  casadi_int b_ncol = b.size2();
1437  casadi_int a_nrow = a.size1();
1438  casadi_int b_nrow = b.size1();
1439  if (a.is_dense() && b.is_dense()) return Sparsity::dense(a_nrow*b_nrow, a_ncol*b_ncol);
1440 
1441  const casadi_int* a_colind = a.colind();
1442  const casadi_int* a_row = a.row();
1443  const casadi_int* b_colind = b.colind();
1444  const casadi_int* b_row = b.row();
1445 
1446  std::vector<casadi_int> r_colind(a_ncol*b_ncol+1, 0);
1447  std::vector<casadi_int> r_row(a.nnz()*b.nnz());
1448 
1449  casadi_int* r_colind_ptr = get_ptr(r_colind);
1450  casadi_int* r_row_ptr = get_ptr(r_row);
1451 
1452  casadi_int i=0;
1453  casadi_int j=0;
1454  // Loop over the columns
1455  for (casadi_int a_cc=0; a_cc<a_ncol; ++a_cc) {
1456  casadi_int a_start = a_colind[a_cc];
1457  casadi_int a_stop = a_colind[a_cc+1];
1458  // Loop over the columns
1459  for (casadi_int b_cc=0; b_cc<b_ncol; ++b_cc) {
1460  casadi_int b_start = b_colind[b_cc];
1461  casadi_int b_stop = b_colind[b_cc+1];
1462  // Loop over existing nonzeros
1463  for (casadi_int a_el=a_start; a_el<a_stop; ++a_el) {
1464  casadi_int a_r = a_row[a_el];
1465  // Loop over existing nonzeros
1466  for (casadi_int b_el=b_start; b_el<b_stop; ++b_el) {
1467  casadi_int b_r = b_row[b_el];
1468  r_row_ptr[i++] = a_r*b_nrow+b_r;
1469  }
1470  }
1471  j+=1;
1472  r_colind_ptr[j] = r_colind_ptr[j-1] + (b_stop-b_start)*(a_stop-a_start);
1473  }
1474  }
1475  return Sparsity(a_nrow*b_nrow, a_ncol*b_ncol, r_colind, r_row);
1476  }
1477 
1478  Sparsity Sparsity::vertcat(const std::vector<Sparsity> & sp) {
1479  // Quick return if possible
1480  if (sp.empty()) return Sparsity(0, 1);
1481  if (sp.size()==1) return sp.front();
1482 
1483  // Count total nnz
1484  casadi_int nnz_total = 0;
1485  for (casadi_int i=0; i<sp.size(); ++i) nnz_total += sp[i].nnz();
1486 
1487  // Construct from vectors (triplet format)
1488  std::vector<casadi_int> ret_row, ret_col;
1489  ret_row.reserve(nnz_total);
1490  ret_col.reserve(nnz_total);
1491  casadi_int ret_nrow = 0;
1492  casadi_int ret_ncol = 0;
1493  for (casadi_int i=0; i<sp.size() && ret_ncol==0; ++i)
1494  ret_ncol = sp[i].size2();
1495 
1496  // Append all patterns
1497  for (std::vector<Sparsity>::const_iterator i=sp.begin(); i!=sp.end(); ++i) {
1498  // Get sparsity pattern
1499  casadi_int sp_nrow = i->size1();
1500  casadi_int sp_ncol = i->size2();
1501  const casadi_int* sp_colind = i->colind();
1502  const casadi_int* sp_row = i->row();
1503  casadi_assert(sp_ncol==ret_ncol || sp_ncol==0,
1504  "Sparsity::vertcat: Mismatching number of columns");
1505 
1506  // Add entries to pattern
1507  for (casadi_int cc=0; cc<sp_ncol; ++cc) {
1508  for (casadi_int k=sp_colind[cc]; k<sp_colind[cc+1]; ++k) {
1509  ret_row.push_back(sp_row[k] + ret_nrow);
1510  ret_col.push_back(cc);
1511  }
1512  }
1513 
1514  // Update offset
1515  ret_nrow += sp_nrow;
1516  }
1517  return Sparsity::triplet(ret_nrow, ret_ncol, ret_row, ret_col);
1518  }
1519 
1520  Sparsity Sparsity::diagcat(const std::vector< Sparsity > &v) {
1521  casadi_int n = 0;
1522  casadi_int m = 0;
1523 
1524  std::vector<casadi_int> colind(1, 0);
1525  std::vector<casadi_int> row;
1526 
1527  casadi_int nz = 0;
1528  for (casadi_int i=0;i<v.size();++i) {
1529  const casadi_int* colind_ = v[i].colind();
1530  casadi_int ncol = v[i].size2();
1531  const casadi_int* row_ = v[i].row();
1532  casadi_int sz = v[i].nnz();
1533  for (casadi_int k=1; k<ncol+1; ++k) {
1534  colind.push_back(colind_[k]+nz);
1535  }
1536  for (casadi_int k=0; k<sz; ++k) {
1537  row.push_back(row_[k]+m);
1538  }
1539  n+= v[i].size2();
1540  m+= v[i].size1();
1541  nz+= v[i].nnz();
1542  }
1543 
1544  return Sparsity(m, n, colind, row);
1545  }
1546 
1547  std::vector<Sparsity> Sparsity::horzsplit(const Sparsity& x,
1548  const std::vector<casadi_int>& offset) {
1549  // Consistency check
1550  casadi_assert_dev(!offset.empty());
1551  casadi_assert_dev(offset.front()==0);
1552  casadi_assert(offset.back()==x.size2(),
1553  "horzsplit(Sparsity, std::vector<casadi_int>): Last elements of offset "
1554  "(" + str(offset.back()) + ") must equal the number of columns "
1555  "(" + str(x.size2()) + ")");
1556  casadi_assert_dev(is_monotone(offset));
1557 
1558  // Number of outputs
1559  casadi_int n = offset.size()-1;
1560 
1561  // Get the sparsity of the input
1562  const casadi_int* colind_x = x.colind();
1563  const casadi_int* row_x = x.row();
1564 
1565  // Allocate result
1566  std::vector<Sparsity> ret;
1567  ret.reserve(n);
1568 
1569  // Sparsity pattern as CCS vectors
1570  std::vector<casadi_int> colind, row;
1571  casadi_int ncol, nrow = x.size1();
1572 
1573  // Get the sparsity patterns of the outputs
1574  for (casadi_int i=0; i<n; ++i) {
1575  casadi_int first_col = offset[i];
1576  casadi_int last_col = offset[i+1];
1577  ncol = last_col - first_col;
1578 
1579  // Construct the sparsity pattern
1580  colind.resize(ncol+1);
1581  std::copy(colind_x+first_col, colind_x+last_col+1, colind.begin());
1582  for (std::vector<casadi_int>::iterator it=colind.begin()+1; it!=colind.end(); ++it)
1583  *it -= colind[0];
1584  colind[0] = 0;
1585  row.resize(colind.back());
1586  std::copy(row_x+colind_x[first_col], row_x+colind_x[last_col], row.begin());
1587 
1588  // Append to the list
1589  ret.push_back(Sparsity(nrow, ncol, colind, row));
1590  }
1591 
1592  // Return (RVO)
1593  return ret;
1594  }
1595 
1596  std::vector<Sparsity> Sparsity::vertsplit(const Sparsity& x,
1597  const std::vector<casadi_int>& offset) {
1598  std::vector<Sparsity> ret = horzsplit(x.T(), offset);
1599  for (std::vector<Sparsity>::iterator it=ret.begin(); it!=ret.end(); ++it) {
1600  *it = it->T();
1601  }
1602  return ret;
1603  }
1604 
1605  Sparsity Sparsity::blockcat(const std::vector< std::vector< Sparsity > > &v) {
1606  std::vector< Sparsity > ret;
1607  for (casadi_int i=0; i<v.size(); ++i)
1608  ret.push_back(horzcat(v[i]));
1609  return vertcat(ret);
1610  }
1611 
1612  std::vector<Sparsity> Sparsity::diagsplit(const Sparsity& x,
1613  const std::vector<casadi_int>& offset1,
1614  const std::vector<casadi_int>& offset2) {
1615  // Consistency check
1616  casadi_assert_dev(!offset1.empty());
1617  casadi_assert_dev(offset1.front()==0);
1618  casadi_assert(offset1.back()==x.size1(),
1619  "diagsplit(Sparsity, offset1, offset2): Last elements of offset1 "
1620  "(" + str(offset1.back()) + ") must equal the number of rows "
1621  "(" + str(x.size1()) + ")");
1622  casadi_assert(offset2.back()==x.size2(),
1623  "diagsplit(Sparsity, offset1, offset2): Last elements of offset2 "
1624  "(" + str(offset2.back()) + ") must equal the number of rows "
1625  "(" + str(x.size2()) + ")");
1626  casadi_assert_dev(is_monotone(offset1));
1627  casadi_assert_dev(is_monotone(offset2));
1628  casadi_assert_dev(offset1.size()==offset2.size());
1629 
1630  // Number of outputs
1631  casadi_int n = offset1.size()-1;
1632 
1633  // Return value
1634  std::vector<Sparsity> ret;
1635 
1636  // Caveat: this is a very silly implementation
1637  IM x2 = IM::zeros(x);
1638 
1639  for (casadi_int i=0; i<n; ++i) {
1640  ret.push_back(x2(Slice(offset1[i], offset1[i+1]),
1641  Slice(offset2[i], offset2[i+1])).sparsity());
1642  }
1643 
1644  return ret;
1645  }
1646 
1648  return mtimes(x, Sparsity::dense(x.size2(), 1));
1649 
1650  }
1652  return mtimes(Sparsity::dense(1, x.size1()), x);
1653  }
1654 
1655  casadi_int Sparsity::sprank(const Sparsity& x) {
1656  std::vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
1657  x.btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
1658  return coarse_colblock.at(3);
1659  }
1660 
1661  Sparsity::operator const casadi_int*() const {
1662  return &(*this)->sp().front();
1663  }
1664 
1665  casadi_int Sparsity::norm_0_mul(const Sparsity& x, const Sparsity& A) {
1666  // Implementation borrowed from Scipy's sparsetools/csr.h
1667  casadi_assert(A.size1()==x.size2(), "Dimension error. Got " + x.dim()
1668  + " times " + A.dim() + ".");
1669 
1670  casadi_int n_row = A.size2();
1671  casadi_int n_col = x.size1();
1672 
1673  // Allocate work vectors
1674  std::vector<bool> Bwork(n_col);
1675  std::vector<casadi_int> Iwork(n_row+1+n_col);
1676 
1677  const casadi_int* Aj = A.row();
1678  const casadi_int* Ap = A.colind();
1679  const casadi_int* Bj = x.row();
1680  const casadi_int* Bp = x.colind();
1681  casadi_int *Cp = get_ptr(Iwork);
1682  casadi_int *mask = Cp+n_row+1;
1683 
1684  // Pass 1
1685  // method that uses O(n) temp storage
1686  std::fill(mask, mask+n_col, -1);
1687 
1688  Cp[0] = 0;
1689  casadi_int nnz = 0;
1690  for (casadi_int i = 0; i < n_row; i++) {
1691  casadi_int row_nnz = 0;
1692  for (casadi_int jj = Ap[i]; jj < Ap[i+1]; jj++) {
1693  casadi_int j = Aj[jj];
1694  for (casadi_int kk = Bp[j]; kk < Bp[j+1]; kk++) {
1695  casadi_int k = Bj[kk];
1696  if (mask[k] != i) {
1697  mask[k] = i;
1698  row_nnz++;
1699  }
1700  }
1701  }
1702  casadi_int next_nnz = nnz + row_nnz;
1703  nnz = next_nnz;
1704  Cp[i+1] = nnz;
1705  }
1706 
1707  // Pass 2
1708  casadi_int *next = get_ptr(Iwork) + n_row+1;
1709  std::fill(next, next+n_col, -1);
1710  std::vector<bool> & sums = Bwork;
1711  std::fill(sums.begin(), sums.end(), false);
1712  nnz = 0;
1713  Cp[0] = 0;
1714  for (casadi_int i = 0; i < n_row; i++) {
1715  casadi_int head = -2;
1716  casadi_int length = 0;
1717  casadi_int jj_start = Ap[i];
1718  casadi_int jj_end = Ap[i+1];
1719  for (casadi_int jj = jj_start; jj < jj_end; jj++) {
1720  casadi_int j = Aj[jj];
1721  casadi_int kk_start = Bp[j];
1722  casadi_int kk_end = Bp[j+1];
1723  for (casadi_int kk = kk_start; kk < kk_end; kk++) {
1724  casadi_int k = Bj[kk];
1725  sums[k] = true;
1726  if (next[k] == -1) {
1727  next[k] = head;
1728  head = k;
1729  length++;
1730  }
1731  }
1732  }
1733  for (casadi_int jj = 0; jj < length; jj++) {
1734  if (sums[head]) {
1735  nnz++;
1736  }
1737  casadi_int temp = head;
1738  head = next[head];
1739  next[temp] = -1; //clear arrays
1740  sums[temp] = 0;
1741  }
1742  Cp[i+1] = nnz;
1743  }
1744  return nnz;
1745  }
1746 
1747  void Sparsity::mul_sparsityF(const bvec_t* x, const Sparsity& x_sp,
1748  const bvec_t* y, const Sparsity& y_sp,
1749  bvec_t* z, const Sparsity& z_sp,
1750  bvec_t* w) {
1751  // Assert dimensions
1752  casadi_assert(z_sp.size1()==x_sp.size1() && x_sp.size2()==y_sp.size1()
1753  && y_sp.size2()==z_sp.size2(),
1754  "Dimension error. Got x=" + x_sp.dim() + ", y=" + y_sp.dim()
1755  + " and z=" + z_sp.dim() + ".");
1756 
1757  // Direct access to the arrays
1758  const casadi_int* y_colind = y_sp.colind();
1759  const casadi_int* y_row = y_sp.row();
1760  const casadi_int* x_colind = x_sp.colind();
1761  const casadi_int* x_row = x_sp.row();
1762  const casadi_int* z_colind = z_sp.colind();
1763  const casadi_int* z_row = z_sp.row();
1764 
1765  // Loop over the columns of y and z
1766  casadi_int ncol = z_sp.size2();
1767  for (casadi_int cc=0; cc<ncol; ++cc) {
1768  // Get the dense column of z
1769  for (casadi_int kk=z_colind[cc]; kk<z_colind[cc+1]; ++kk) {
1770  w[z_row[kk]] = z[kk];
1771  }
1772 
1773  // Loop over the nonzeros of y
1774  for (casadi_int kk=y_colind[cc]; kk<y_colind[cc+1]; ++kk) {
1775  casadi_int rr = y_row[kk];
1776 
1777  // Loop over corresponding columns of x
1778  bvec_t yy = y[kk];
1779  for (casadi_int kk1=x_colind[rr]; kk1<x_colind[rr+1]; ++kk1) {
1780  w[x_row[kk1]] |= x[kk1] | yy;
1781  }
1782  }
1783 
1784  // Get the sparse column of z
1785  for (casadi_int kk=z_colind[cc]; kk<z_colind[cc+1]; ++kk) {
1786  z[kk] = w[z_row[kk]];
1787  }
1788  }
1789  }
1790 
1792  bvec_t* y, const Sparsity& y_sp,
1793  bvec_t* z, const Sparsity& z_sp,
1794  bvec_t* w) {
1795  // Assert dimensions
1796  casadi_assert(z_sp.size1()==x_sp.size1() && x_sp.size2()==y_sp.size1()
1797  && y_sp.size2()==z_sp.size2(),
1798  "Dimension error. Got x=" + x_sp.dim() + ", y=" + y_sp.dim()
1799  + " and z=" + z_sp.dim() + ".");
1800 
1801  // Direct access to the arrays
1802  const casadi_int* y_colind = y_sp.colind();
1803  const casadi_int* y_row = y_sp.row();
1804  const casadi_int* x_colind = x_sp.colind();
1805  const casadi_int* x_row = x_sp.row();
1806  const casadi_int* z_colind = z_sp.colind();
1807  const casadi_int* z_row = z_sp.row();
1808 
1809  // Clear residual work vector data from preceding operations (not necessary
1810  // for data from this method if conditional clear code is made unconditional
1811  // in loop)
1812  casadi_int nrow = z_sp.size1();
1813  casadi_fill(w, nrow, static_cast<bvec_t>(0));
1814 
1815  // Loop over the columns of y and z
1816  casadi_int ncol = z_sp.size2();
1817  for (casadi_int cc=0; cc<ncol; ++cc) {
1818  // Get the dense column of z
1819  for (casadi_int kk=z_colind[cc]; kk<z_colind[cc+1]; ++kk) {
1820  w[z_row[kk]] = z[kk];
1821  }
1822 
1823  // Loop over the nonzeros of y
1824  for (casadi_int kk=y_colind[cc]; kk<y_colind[cc+1]; ++kk) {
1825  casadi_int rr = y_row[kk];
1826 
1827  // Loop over corresponding columns of x
1828  bvec_t yy = 0;
1829  for (casadi_int kk1=x_colind[rr]; kk1<x_colind[rr+1]; ++kk1) {
1830  yy |= w[x_row[kk1]];
1831  x[kk1] |= w[x_row[kk1]];
1832  }
1833  y[kk] |= yy;
1834  }
1835 
1836  // Get the sparse column of z, clear work vector for next column
1837  for (casadi_int kk=z_colind[cc]; kk<z_colind[cc+1]; ++kk) {
1838  z[kk] = w[z_row[kk]];
1839  w[z_row[kk]] = 0;
1840  }
1841  }
1842  }
1843 
1845  const Sparsity& x = *this;
1846  if (X==x) return Y;
1847  if (X==Y) return x;
1848  std::vector<unsigned char> mapping;
1849  X.unite(x, mapping);
1850 
1851 
1852  const casadi_int* Y_colind = Y.colind();
1853  const casadi_int* Y_row = Y.row();
1854  std::vector<casadi_int> y_colind(Y.size2()+1, 0);
1855  std::vector<casadi_int> y_row;
1856  y_row.reserve(Y.nnz());
1857  casadi_assert_dev(Y.nnz()==mapping.size());
1858 
1859  casadi_int i = 0;
1860  // Loop over columns of Y
1861  for (casadi_int cc=0; cc<Y.size2(); ++cc) {
1862  y_colind[cc+1] = y_colind[cc];
1863  // Loop over nonzeros of Y in column cc
1864  for (casadi_int kk=Y_colind[cc]; kk<Y_colind[cc+1]; ++kk) {
1865  // Get corresponding map entry
1866  casadi_int e = mapping[i++];
1867  if (e==3) {
1868  // Preserve element
1869  y_colind[cc+1]++;
1870  y_row.push_back(Y_row[kk]);
1871  } else {
1872  casadi_assert_dev(e==1);
1873  }
1874  }
1875  }
1876 
1877  Sparsity ret(Y.size1(), Y.size2(), y_colind, y_row, true);
1878  return ret;
1879  }
1880 
1882  if (is_null()) return Dict();
1883  return {{"nrow", size1()}, {"ncol", size2()}, {"colind", get_colind()}, {"row", get_row()}};
1884  }
1885 
1886  std::set<std::string> Sparsity::file_formats = {"mtx"};
1887 
1888  std::string Sparsity::file_format(const std::string& filename,
1889  const std::string& format_hint, const std::set<std::string>& file_formats) {
1890  if (format_hint.empty()) {
1891  std::string extension = filename.substr(filename.rfind(".")+1);
1892  auto it = file_formats.find(extension);
1893  casadi_assert(it!=file_formats.end(),
1894  "Extension '" + extension + "' not recognised. "
1895  "Valid options: " + str(file_formats) + ".");
1896  return extension;
1897  } else {
1898  auto it = file_formats.find(format_hint);
1899  casadi_assert(it!=file_formats.end(),
1900  "File format hint '" + format_hint + "' not recognised. "
1901  "Valid options: " + str(file_formats) + ".");
1902  return format_hint;
1903  }
1904 
1905  }
1906  void Sparsity::to_file(const std::string& filename, const std::string& format_hint) const {
1907  std::string format = file_format(filename, format_hint, file_formats);
1908  std::ofstream out;
1909  Filesystem::open(out, filename);
1910  if (format=="mtx") {
1911  out << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1);
1912  out << "%%MatrixMarket matrix coordinate pattern general" << std::endl;
1913  out << size1() << " " << size2() << " " << nnz() << std::endl;
1914  std::vector<casadi_int> row = get_row();
1915  std::vector<casadi_int> col = get_col();
1916 
1917  for (casadi_int k=0;k<row.size();++k) {
1918  out << row[k]+1 << " " << col[k]+1 << std::endl;
1919  }
1920  } else {
1921  casadi_error("Unknown format '" + format + "'");
1922  }
1923  }
1924 
1925  Sparsity Sparsity::from_file(const std::string& filename, const std::string& format_hint) {
1926  std::string format = file_format(filename, format_hint, file_formats);
1927  std::ifstream in(filename);
1928  casadi_assert(in.good(), "Could not open '" + filename + "'.");
1929  if (format=="mtx") {
1930  std::string line;
1931  std::vector<casadi_int> row, col;
1932  casadi_int size1, size2, nnz;
1933  int line_num = 0;
1934  while (std::getline(in, line)) {
1935  if (line_num==0) {
1936  casadi_assert(line=="%%MatrixMarket matrix coordinate pattern general", "Wrong header");
1937  line_num = 1;
1938  } else if (line_num==1) {
1939  std::stringstream stream(line);
1940  stream >> size1;
1941  stream >> size2;
1942  stream >> nnz;
1943  row.reserve(nnz);
1944  col.reserve(nnz);
1945  line_num = 2;
1946  } else {
1947  std::stringstream stream(line);
1948  casadi_int r, c;
1949  stream >> r;
1950  stream >> c;
1951  row.push_back(r-1);
1952  col.push_back(c-1);
1953  }
1954  }
1955  return triplet(size1, size2, row, col);
1956  } else {
1957  casadi_error("Unknown format '" + format + "'");
1958  }
1959  }
1960 
1962  bool with_x_diag, bool with_lam_g_diag) {
1963  // Consistency check
1964  casadi_assert(H.is_square(), "H must be square");
1965  casadi_assert(H.size1() == J.size2(), "Dimension mismatch");
1966 
1967  // Add diagonal to H recursively
1968  if (with_x_diag) return kkt(H + diag(H.size()), J, false, with_lam_g_diag);
1969 
1970  // Lower right entry
1971  int ng = J.size1();
1972  Sparsity B = with_lam_g_diag ? diag(ng, ng) : Sparsity(ng, ng);
1973 
1974  // Concatenate
1975  return blockcat({{H, J.T()}, {J, B}});
1976  }
1977 
1978  void Sparsity::serialize(std::ostream &stream) const {
1979  SerializingStream s(stream);
1980  serialize(s);
1981  }
1982 
1983  Sparsity Sparsity::deserialize(std::istream &stream) {
1984  DeserializingStream s(stream);
1985  return Sparsity::deserialize(s);
1986  }
1987 
1989  if (is_null()) {
1990  s.pack("SparsityInternal::compressed", std::vector<casadi_int>{});
1991  } else {
1992  s.pack("SparsityInternal::compressed", compress());
1993  }
1994  }
1995 
1997  std::vector<casadi_int> i;
1998  s.unpack("SparsityInternal::compressed", i);
1999  if (i.empty()) {
2000  return Sparsity();
2001  } else {
2002  return Sparsity::compressed(i);
2003  }
2004  }
2005 
2006  std::string Sparsity::serialize() const {
2007  std::stringstream ss;
2008  serialize(ss);
2009  return ss.str();
2010  }
2011 
2012  Sparsity Sparsity::deserialize(const std::string& s) {
2013  std::stringstream ss;
2014  ss << s;
2015  return deserialize(ss);
2016  }
2017 
2019  return static_cast<SparsityInternal*>(SharedObject::get());
2020  }
2021 } // namespace casadi
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
static void open(std::ofstream &, const std::string &path, std::ios_base::openmode mode=std::ios_base::out)
Definition: filesystem.cpp:115
static MatType zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
SharedObjectInternal * get() const
Get a const pointer to the node.
bool is_null() const
Is a null pointer?
SharedObjectInternal * operator->() const
Access a member function or object.
Helper class for Serialization.
void pack(const Sparsity &e)
Serializes an object to the output stream.
Class representing a Slice.
Definition: slice.hpp:48
static std::vector< casadi_int > offset(const std::vector< Sparsity > &v, bool vert=true)
Sparsity get_diag(std::vector< casadi_int > &mapping) const
Get the diagonal of the matrix/create a diagonal matrix.
static void ldl_colind(const casadi_int *sp, casadi_int *parent, casadi_int *l_colind, casadi_int *w)
Calculate the column offsets for the L factor of an LDL^T factorization.
Sparsity makeDense(std::vector< casadi_int > &mapping) const
Make a patten dense.
Sparsity _mtimes(const Sparsity &y) const
Sparsity pattern for a matrix-matrix product (details in public class)
Sparsity pattern_inverse() const
Take the inverse of a sparsity pattern; flip zeros and non-zeros.
static void ldl_row(const casadi_int *sp, const casadi_int *parent, casadi_int *l_colind, casadi_int *l_row, casadi_int *w)
Calculate the row indices for the L factor of an LDL^T factorization.
Sparsity pmult(const std::vector< casadi_int > &p, bool permute_rows=true, bool permute_cols=true, bool invert_permutation=false) const
Permute rows and/or columns.
Sparsity transpose(std::vector< casadi_int > &mapping, bool invert_mapping=false) const
Transpose the matrix and get the reordering of the non-zero entries,.
Sparsity _appendColumns(const SparsityInternal &sp) const
Append another sparsity patten horizontally.
Sparsity sub(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, std::vector< casadi_int > &mapping, bool ind1) const
Get a submatrix.
Sparsity star_coloring2(casadi_int ordering, casadi_int cutoff) const
An improved distance-2 coloring algorithm.
Sparsity _tril(bool includeDiagonal) const
Get lower triangular part.
Sparsity _appendVector(const SparsityInternal &sp) const
Append another sparsity patten vertically (vectors only)
static void qr_init(const casadi_int *sp, const casadi_int *sp_tr, casadi_int *leftmost, casadi_int *parent, casadi_int *pinv, casadi_int *nrow_ext, casadi_int *v_nnz, casadi_int *r_nnz, casadi_int *w)
Setup QP solver.
Sparsity _triu(bool includeDiagonal) const
Get upper triangular part.
Sparsity uni_coloring(const Sparsity &AT, casadi_int cutoff) const
Perform a unidirectional coloring.
Sparsity T() const
Transpose the matrix.
Sparsity _reshape(casadi_int nrow, casadi_int ncol) const
Reshape a sparsity, order of nonzeros remains the same.
static void qr_sparsities(const casadi_int *sp_a, casadi_int nrow_ext, casadi_int *sp_v, casadi_int *sp_r, const casadi_int *leftmost, const casadi_int *parent, const casadi_int *pinv, casadi_int *iw)
Get the row indices for V and R in QR factorization.
Sparsity combine(const Sparsity &y, bool f0x_is_zero, bool function0_is_zero, std::vector< unsigned char > &mapping) const
Sparsity star_coloring(casadi_int ordering, casadi_int cutoff) const
A greedy distance-2 coloring algorithm.
static void etree(const casadi_int *sp, casadi_int *parent, casadi_int *w, casadi_int ata)
Calculate the elimination tree for a matrix.
General sparsity class.
Definition: sparsity.hpp:106
std::vector< casadi_int > get_upper() const
Get nonzeros in upper triangular part.
Definition: sparsity.cpp:991
casadi_int get_nz(casadi_int rr, casadi_int cc) const
Get the index of an existing non-zero element.
Definition: sparsity.cpp:246
Sparsity pmult(const std::vector< casadi_int > &p, bool permute_rows=true, bool permute_columns=true, bool invert_permutation=false) const
Permute rows and/or columns.
Definition: sparsity.cpp:769
Sparsity(casadi_int dummy=0)
Default constructor.
Definition: sparsity.cpp:68
static Sparsity banded(casadi_int n, casadi_int p)
Create banded square sparsity pattern.
Definition: sparsity.cpp:1095
bool is_subset(const Sparsity &rhs) const
Is subset?
Definition: sparsity.cpp:426
static Sparsity upper(casadi_int n)
Create a upper triangular square sparsity pattern *.
Definition: sparsity.cpp:1028
static const Sparsity & getScalar()
(Dense) scalar
Definition: sparsity.cpp:529
bool is_stacked(const Sparsity &y, casadi_int n) const
Check if pattern is horizontal repeat of another.
Definition: sparsity.cpp:439
Sparsity makeDense(std::vector< casadi_int > &mapping) const
Make a patten dense.
Definition: sparsity.cpp:583
Sparsity intersect(const Sparsity &y, std::vector< unsigned char > &mapping) const
Intersection of two sparsity patterns.
Definition: sparsity.cpp:417
static Sparsity vertcat(const std::vector< Sparsity > &sp)
Enlarge matrix.
Definition: sparsity.cpp:1478
bool is_vector() const
Check if the pattern is a row or column vector.
Definition: sparsity.cpp:289
std::vector< casadi_int > erase(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, bool ind1=false)
Erase rows and/or columns of a matrix.
Definition: sparsity.cpp:339
Sparsity sub(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, std::vector< casadi_int > &mapping, bool ind1=false) const
Get a submatrix.
Definition: sparsity.cpp:334
casadi_int numel() const
The total number of elements, including structural zeros, i.e. size2()*size1()
Definition: sparsity.cpp:132
static CachingMap & getCache()
Cached sparsity patterns.
Definition: sparsity.cpp:524
std::unordered_multimap< std::size_t, WeakRef > CachingMap
Enlarge matrix.
Definition: sparsity.hpp:881
casadi_int size1() const
Get the number of rows.
Definition: sparsity.cpp:124
void enlarge(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, bool ind1=false)
Enlarge matrix.
Definition: sparsity.cpp:544
std::vector< casadi_int > find(bool ind1=SWIG_IND1) const
Get the location of all non-zero elements as they would appear in a Dense matrix.
Definition: sparsity.cpp:735
static Sparsity permutation(const std::vector< casadi_int > &p, bool invert=false)
Construct a permutation matrix P from a permutation vector p.
Definition: sparsity.cpp:1364
casadi_int dfs(casadi_int j, casadi_int top, std::vector< casadi_int > &xi, std::vector< casadi_int > &pstack, const std::vector< casadi_int > &pinv, std::vector< bool > &marked) const
Depth-first search on the adjacency graph of the sparsity.
Definition: sparsity.cpp:696
static std::set< std::string > file_formats
Enlarge matrix.
Definition: sparsity.hpp:1183
Dict info() const
Definition: sparsity.cpp:1881
static const Sparsity & getScalarSparse()
(Sparse) scalar
Definition: sparsity.cpp:534
Sparsity star_coloring(casadi_int ordering=1, casadi_int cutoff=std::numeric_limits< casadi_int >::max()) const
Perform a star coloring of a symmetric matrix:
Definition: sparsity.cpp:757
static Sparsity rowcol(const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, casadi_int nrow, casadi_int ncol)
Construct a block sparsity pattern from (row, col) vectors.
Definition: sparsity.cpp:1111
Sparsity pattern_inverse() const
Take the inverse of a sparsity pattern; flip zeros and non-zeros.
Definition: sparsity.cpp:466
static Sparsity diag(casadi_int nrow)
Create diagonal sparsity pattern *.
Definition: sparsity.hpp:190
static Sparsity sum2(const Sparsity &x)
Enlarge matrix.
Definition: sparsity.cpp:1647
bool is_orthonormal(bool allow_empty=false) const
Are both rows and columns orthonormal ?
Definition: sparsity.cpp:305
const std::vector< casadi_int > permutation_vector(bool invert=false) const
Construct permutation vector from permutation matrix.
Definition: sparsity.cpp:1375
casadi_int nnz_lower(bool strictly=false) const
Number of non-zeros in the lower triangular half,.
Definition: sparsity.cpp:352
casadi_int scc(std::vector< casadi_int > &index, std::vector< casadi_int > &offset) const
Find the strongly connected components of the bigraph defined by the sparsity pattern.
Definition: sparsity.cpp:703
std::string dim(bool with_nz=false) const
Get the dimension as a string.
Definition: sparsity.cpp:587
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern *.
Definition: sparsity.cpp:1012
static Sparsity triu(const Sparsity &x, bool includeDiagonal=true)
Enlarge matrix.
Definition: sparsity.cpp:983
Sparsity transpose(std::vector< casadi_int > &mapping, bool invert_mapping=false) const
Transpose the matrix and get the reordering of the non-zero entries.
Definition: sparsity.cpp:390
Sparsity T() const
Transpose the matrix.
Definition: sparsity.cpp:394
bool is_column() const
Check if the pattern is a column vector (i.e. size2()==1)
Definition: sparsity.cpp:285
Sparsity unite(const Sparsity &y, std::vector< unsigned char > &mapping) const
Union of two sparsity patterns.
Definition: sparsity.cpp:409
void spsolve(bvec_t *X, bvec_t *B, bool tr) const
Propagate sparsity through a linear solve.
Definition: sparsity.cpp:723
void spy(std::ostream &stream=casadi::uout()) const
Print a textual representation of sparsity.
Definition: sparsity.cpp:783
bool is_reshape(const Sparsity &y) const
Check if the sparsity is a reshape of another.
Definition: sparsity.cpp:791
void get_crs(std::vector< casadi_int > &rowind, std::vector< casadi_int > &col) const
Get the sparsity in compressed row storage (CRS) format.
Definition: sparsity.cpp:381
static std::string file_format(const std::string &filename, const std::string &format_hint, const std::set< std::string > &file_formats)
Enlarge matrix.
Definition: sparsity.cpp:1888
SparsityInternal * get() const
Definition: sparsity.cpp:2018
void removeDuplicates(std::vector< casadi_int > &mapping)
Remove duplicate entries.
Definition: sparsity.cpp:731
static Sparsity deserialize(std::istream &stream)
Build Sparsity from serialization.
Definition: sparsity.cpp:1983
bool is_scalar(bool scalar_and_dense=false) const
Is scalar?
Definition: sparsity.cpp:269
std::vector< casadi_int > get_lower() const
Get nonzeros in lower triangular part.
Definition: sparsity.cpp:987
bool has_nz(casadi_int rr, casadi_int cc) const
Returns true if the pattern has a non-zero at location rr, cc.
Definition: sparsity.cpp:241
bool is_orthonormal_rows(bool allow_empty=false) const
Are the rows of the pattern orthonormal ?
Definition: sparsity.cpp:309
static Sparsity blockcat(const std::vector< std::vector< Sparsity > > &v)
Enlarge matrix.
Definition: sparsity.cpp:1605
void enlargeColumns(casadi_int ncol, const std::vector< casadi_int > &cc, bool ind1=false)
Enlarge the matrix along the second dimension (i.e. insert columns)
Definition: sparsity.cpp:550
static Sparsity create(SparsityInternal *node)
Create from node.
Definition: sparsity.cpp:72
const SparsityInternal * operator->() const
Access a member function or object.
Definition: sparsity.cpp:112
void append(const Sparsity &sp)
Append another sparsity patten vertically (NOTE: only efficient if vector)
Definition: sparsity.cpp:470
casadi_int add_nz(casadi_int rr, casadi_int cc)
Get the index of a non-zero element.
Definition: sparsity.cpp:194
bool is_row() const
Check if the pattern is a row vector (i.e. size1()==1)
Definition: sparsity.cpp:281
Sparsity get_diag(std::vector< casadi_int > &mapping) const
Definition: sparsity.cpp:611
static Sparsity mtimes(const Sparsity &x, const Sparsity &y)
Enlarge matrix.
Definition: sparsity.cpp:430
static Sparsity tril(const Sparsity &x, bool includeDiagonal=true)
Enlarge matrix.
Definition: sparsity.cpp:979
std::vector< casadi_int > etree(bool ata=false) const
Calculate the elimination tree.
Definition: sparsity.cpp:615
static Sparsity unit(casadi_int n, casadi_int el)
Create the sparsity pattern for a unit vector of length n and a nonzero on.
Definition: sparsity.cpp:1104
bool is_diag() const
Is diagonal?
Definition: sparsity.cpp:277
std::vector< casadi_int > get_col() const
Get the column for each non-zero entry.
Definition: sparsity.cpp:368
static std::vector< Sparsity > vertsplit(const Sparsity &x, const std::vector< casadi_int > &offset)
Enlarge matrix.
Definition: sparsity.cpp:1596
static Sparsity reshape(const Sparsity &x, casadi_int nrow, casadi_int ncol)
Enlarge matrix.
Definition: sparsity.cpp:260
bool is_equal(const Sparsity &y) const
Definition: sparsity.cpp:443
static const Sparsity & getEmpty()
Empty zero-by-zero.
Definition: sparsity.cpp:539
static void mul_sparsityR(bvec_t *x, const Sparsity &x_sp, bvec_t *y, const Sparsity &y_sp, bvec_t *z, const Sparsity &z_sp, bvec_t *w)
Propagate sparsity using 0-1 logic through a matrix product,.
Definition: sparsity.cpp:1791
static std::vector< Sparsity > horzsplit(const Sparsity &x, const std::vector< casadi_int > &offset)
Enlarge matrix.
Definition: sparsity.cpp:1547
void enlargeRows(casadi_int nrow, const std::vector< casadi_int > &rr, bool ind1=false)
Enlarge the matrix along the first dimension (i.e. insert rows)
Definition: sparsity.cpp:559
bool is_tril(bool strictly=false) const
Is lower triangular?
Definition: sparsity.cpp:321
Sparsity combine(const Sparsity &y, bool f0x_is_zero, bool function0_is_zero, std::vector< unsigned char > &mapping) const
Combine two sparsity patterns.
Definition: sparsity.cpp:398
std::vector< casadi_int > amd() const
Approximate minimal degree preordering.
Definition: sparsity.cpp:707
void spy_matlab(const std::string &mfile) const
Generate a script for Matlab or Octave which visualizes.
Definition: sparsity.cpp:774
casadi_int nnz_upper(bool strictly=false) const
Number of non-zeros in the upper triangular half,.
Definition: sparsity.cpp:356
casadi_int nnz() const
Get the number of (structural) non-zeros.
Definition: sparsity.cpp:148
casadi_int size2() const
Get the number of columns.
Definition: sparsity.cpp:128
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:164
casadi_int btf(std::vector< casadi_int > &rowperm, std::vector< casadi_int > &colperm, std::vector< casadi_int > &rowblock, std::vector< casadi_int > &colblock, std::vector< casadi_int > &coarse_rowblock, std::vector< casadi_int > &coarse_colblock) const
Calculate the block triangular form (BTF)
Definition: sparsity.cpp:711
std::string serialize() const
Serialize.
Definition: sparsity.cpp:2006
bool is_selection(bool allow_empty=false) const
Is this a selection matrix?
Definition: sparsity.cpp:301
std::pair< casadi_int, casadi_int > size() const
Get the shape.
Definition: sparsity.cpp:152
static Sparsity sparsity_cast(const Sparsity &x, const Sparsity &sp)
Enlarge matrix.
Definition: sparsity.cpp:255
Sparsity sparsity_cast_mod(const Sparsity &X, const Sparsity &Y) const
Propagates subset according to sparsity cast.
Definition: sparsity.cpp:1844
bool is_permutation() const
Is this a permutation matrix?
Definition: sparsity.cpp:297
std::vector< casadi_int > get_colind() const
Get the column index for each column.
Definition: sparsity.cpp:364
Sparsity ldl(std::vector< casadi_int > &p, bool amd=true) const
Symbolic LDL factorization.
Definition: sparsity.cpp:621
static casadi_int sprank(const Sparsity &x)
Enlarge matrix.
Definition: sparsity.cpp:1655
bool is_empty(bool both=false) const
Check if the sparsity is empty.
Definition: sparsity.cpp:144
casadi_int bw_upper() const
Upper half-bandwidth.
Definition: sparsity.cpp:1384
const SparsityInternal & operator*() const
Reference to internal structure.
Definition: sparsity.cpp:116
static Sparsity sum1(const Sparsity &x)
Enlarge matrix.
Definition: sparsity.cpp:1651
static Sparsity kron(const Sparsity &a, const Sparsity &b)
Enlarge matrix.
Definition: sparsity.cpp:1434
bool is_singular() const
Check whether the sparsity-pattern indicates structural singularity.
Definition: sparsity.cpp:1299
void export_code(const std::string &lang, std::ostream &stream=casadi::uout(), const Dict &options=Dict()) const
Export matrix in specific language.
Definition: sparsity.cpp:778
void to_file(const std::string &filename, const std::string &format_hint="") const
Definition: sparsity.cpp:1906
std::vector< casadi_int > compress(bool canonical=true) const
Compress a sparsity pattern.
Definition: sparsity.cpp:1305
static std::vector< Sparsity > diagsplit(const Sparsity &x, const std::vector< casadi_int > &offset1, const std::vector< casadi_int > &offset2)
Enlarge matrix.
Definition: sparsity.cpp:1612
void get_triplet(std::vector< casadi_int > &row, std::vector< casadi_int > &col) const
Get the sparsity in sparse triplet format.
Definition: sparsity.cpp:385
static Sparsity horzcat(const std::vector< Sparsity > &sp)
Accessed by SparsityInterface.
Definition: sparsity.cpp:1392
static casadi_int norm_0_mul(const Sparsity &x, const Sparsity &A)
Enlarge matrix.
Definition: sparsity.cpp:1665
double density() const
The percentage of nonzero.
Definition: sparsity.cpp:136
Sparsity uni_coloring(const Sparsity &AT=Sparsity(), casadi_int cutoff=std::numeric_limits< casadi_int >::max()) const
Perform a unidirectional coloring: A greedy distance-2 coloring algorithm.
Definition: sparsity.cpp:749
Sparsity operator+(const Sparsity &b) const
Union of two sparsity patterns.
Definition: sparsity.cpp:457
static Sparsity diagcat(const std::vector< Sparsity > &v)
Enlarge matrix.
Definition: sparsity.cpp:1520
casadi_int nnz_diag() const
Number of non-zeros on the diagonal, i.e. the number of elements (i, j) with j==i.
Definition: sparsity.cpp:360
bool is_transpose(const Sparsity &y) const
Check if the sparsity is the transpose of another.
Definition: sparsity.cpp:787
std::size_t hash() const
Enlarge matrix.
Definition: sparsity.cpp:795
std::vector< casadi_int > get_row() const
Get the row for each non-zero entry.
Definition: sparsity.cpp:372
void appendColumns(const Sparsity &sp)
Append another sparsity patten horizontally.
Definition: sparsity.cpp:499
void get_ccs(std::vector< casadi_int > &colind, std::vector< casadi_int > &row) const
Get the sparsity in compressed column storage (CCS) format.
Definition: sparsity.cpp:376
static Sparsity nonzeros(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &nz, bool ind1=SWIG_IND1)
Create a sparsity from nonzeros.
Definition: sparsity.cpp:1285
static bool test_cast(const SharedObjectInternal *ptr)
Check if a particular cast is allowed.
Definition: sparsity.cpp:120
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:168
static Sparsity lower(casadi_int n)
Create a lower triangular square sparsity pattern *.
Definition: sparsity.cpp:1049
bool is_dense() const
Is dense?
Definition: sparsity.cpp:273
bool is_orthonormal_columns(bool allow_empty=false) const
Are the columns of the pattern orthonormal ?
Definition: sparsity.cpp:313
static void mul_sparsityF(const bvec_t *x, const Sparsity &x_sp, const bvec_t *y, const Sparsity &y_sp, bvec_t *z, const Sparsity &z_sp, bvec_t *w)
Propagate sparsity using 0-1 logic through a matrix product,.
Definition: sparsity.cpp:1747
static Sparsity triplet(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, std::vector< casadi_int > &mapping, bool invert_mapping)
Create a sparsity pattern given the nonzeros in sparse triplet form *.
Definition: sparsity.cpp:1127
static Sparsity band(casadi_int n, casadi_int p)
Create a single band in a square sparsity pattern.
Definition: sparsity.cpp:1070
static Sparsity kkt(const Sparsity &H, const Sparsity &J, bool with_x_diag=true, bool with_lam_g_diag=true)
Get KKT system sparsity.
Definition: sparsity.cpp:1961
void resize(casadi_int nrow, casadi_int ncol)
Resize.
Definition: sparsity.cpp:188
std::string postfix_dim() const
Dimension string as a postfix to a name.
Definition: sparsity.cpp:591
bool is_square() const
Is square?
Definition: sparsity.cpp:293
void qr_sparse(Sparsity &V, Sparsity &R, std::vector< casadi_int > &prinv, std::vector< casadi_int > &pc, bool amd=true) const
Symbolic QR factorization.
Definition: sparsity.cpp:654
static Sparsity from_file(const std::string &filename, const std::string &format_hint="")
Definition: sparsity.cpp:1925
static Sparsity compressed(const std::vector< casadi_int > &v, bool order_rows=false)
Definition: sparsity.cpp:1325
bool rowsSequential(bool strictly=true) const
Do the rows appear sequentially on each column.
Definition: sparsity.cpp:727
bool is_triu(bool strictly=false) const
Is upper triangular?
Definition: sparsity.cpp:325
std::vector< casadi_int > largest_first() const
Order the columns by decreasing degree.
Definition: sparsity.cpp:765
std::string repr_el(casadi_int k) const
Describe the nonzero location k as a string.
Definition: sparsity.cpp:607
Sparsity star_coloring2(casadi_int ordering=1, casadi_int cutoff=std::numeric_limits< casadi_int >::max()) const
Perform a star coloring of a symmetric matrix:
Definition: sparsity.cpp:761
bool is_symmetric() const
Is symmetric?
Definition: sparsity.cpp:317
casadi_int bw_lower() const
Lower half-bandwidth.
Definition: sparsity.cpp:1388
The casadi namespace.
Definition: archiver.cpp:28
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
std::vector< casadi_int > invert_permutation(const std::vector< casadi_int > &a)
inverse a permutation vector
unsigned long long bvec_t
void casadi_fill(T1 *x, casadi_int n, T1 alpha)
FILL: x <- alpha.
bool is_monotone(const std::vector< T > &v)
Check if the vector is monotone.
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void hash_combine(std::size_t &seed, T v)
Generate a hash value incrementally (function taken from boost)
Definition: sparsity.hpp:1207
std::size_t hash_sparsity(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &colind, const std::vector< casadi_int > &row)
Hash a sparsity pattern.
Definition: sparsity.cpp:996
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
bool is_permutation(const std::vector< casadi_int > &order)
Does the list represent a permutation?
std::string filename(const std::string &path)
Definition: ghc.cpp:55
Compact representation of a sparsity pattern.
Definition: sparsity.hpp:57