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