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