GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
sparse-dmsolve.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2016-2018 John W. Eaton
4 Copyright (C) 2006-2018 David Bateman
5 
6 This file is part of Octave.
7 
8 Octave is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <algorithm>
29 
30 #include "CMatrix.h"
31 #include "CSparse.h"
32 #include "MArray.h"
33 #include "MSparse.h"
34 #include "MatrixType.h"
35 #include "dSparse.h"
36 #include "lo-error.h"
37 #include "oct-inttypes.h"
38 #include "oct-locbuf.h"
39 #include "oct-sort.h"
40 #include "oct-sparse.h"
41 #include "quit.h"
42 #include "sparse-dmsolve.h"
43 #include "sparse-qr.h"
44 
45 template <typename T>
46 static MSparse<T>
48  const octave_idx_type *Q, octave_idx_type rst,
50  octave_idx_type cend, octave_idx_type maxnz = -1,
51  bool lazy = false)
52 {
53  octave_idx_type nr = rend - rst;
54  octave_idx_type nc = cend - cst;
55 
56  maxnz = (maxnz < 0 ? A.nnz () : maxnz);
57 
58  octave_idx_type nz;
59 
60  // Cast to uint64 to handle overflow in this multiplication
61  if (octave_uint64 (nr)*octave_uint64 (nc) < octave_uint64 (maxnz))
62  nz = nr*nc;
63  else
64  nz = maxnz;
65 
66  MSparse<T> B (nr, nc, (nz < maxnz ? nz : maxnz));
67 
68  // Some sparse functions can support lazy indexing (where elements
69  // in the row are in no particular order), even though octave in
70  // general can't. For those functions that can using it is a big
71  // win here in terms of speed.
72 
73  if (lazy)
74  {
75  nz = 0;
76 
77  for (octave_idx_type j = cst ; j < cend ; j++)
78  {
79  octave_idx_type qq = (Q ? Q[j] : j);
80 
81  B.xcidx (j - cst) = nz;
82 
83  for (octave_idx_type p = A.cidx (qq) ; p < A.cidx (qq+1) ; p++)
84  {
85  octave_quit ();
86 
87  octave_idx_type r = (Pinv ? Pinv[A.ridx (p)] : A.ridx (p));
88 
89  if (r >= rst && r < rend)
90  {
91  B.xdata (nz) = A.data (p);
92  B.xridx (nz++) = r - rst;
93  }
94  }
95  }
96 
97  B.xcidx (cend - cst) = nz;
98  }
99  else
100  {
101  OCTAVE_LOCAL_BUFFER (T, X, rend - rst);
102 
104  octave_idx_type *ri = B.xridx ();
105 
106  nz = 0;
107 
108  for (octave_idx_type j = cst ; j < cend ; j++)
109  {
110  octave_idx_type qq = (Q ? Q[j] : j);
111 
112  B.xcidx (j - cst) = nz;
113 
114  for (octave_idx_type p = A.cidx (qq) ; p < A.cidx (qq+1) ; p++)
115  {
116  octave_quit ();
117 
118  octave_idx_type r = (Pinv ? Pinv[A.ridx (p)] : A.ridx (p));
119 
120  if (r >= rst && r < rend)
121  {
122  X[r-rst] = A.data (p);
123  B.xridx (nz++) = r - rst;
124  }
125  }
126 
127  sort.sort (ri + B.xcidx (j - cst), nz - B.xcidx (j - cst));
128 
129  for (octave_idx_type p = B.cidx (j - cst); p < nz; p++)
130  B.xdata (p) = X[B.xridx (p)];
131  }
132 
133  B.xcidx (cend - cst) = nz;
134  }
135 
136  return B;
137 }
138 
139 template <typename T>
140 static MArray<T>
142  const octave_idx_type *, octave_idx_type r1,
144  octave_idx_type c2)
145 {
146  r2 -= 1;
147  c2 -= 1;
148 
149  if (r1 > r2)
150  std::swap (r1, r2);
151 
152  if (c1 > c2)
153  std::swap (c1, c2);
154 
155  octave_idx_type new_r = r2 - r1 + 1;
156  octave_idx_type new_c = c2 - c1 + 1;
157 
158  MArray<T> result (dim_vector (new_r, new_c));
159 
160  for (octave_idx_type j = 0; j < new_c; j++)
161  {
162  for (octave_idx_type i = 0; i < new_r; i++)
163  result.xelem (i, j) = m.elem (r1+i, c1+j);
164  }
165 
166  return result;
167 }
168 
169 template <typename T>
170 static void
173 {
174  T *ax = a.fortran_vec ();
175 
176  const T *bx = b.fortran_vec ();
177 
178  octave_idx_type anr = a.rows ();
179 
180  octave_idx_type nr = b.rows ();
181  octave_idx_type nc = b.cols ();
182 
183  for (octave_idx_type j = 0; j < nc; j++)
184  {
185  octave_idx_type aoff = (c + j) * anr;
186  octave_idx_type boff = j * nr;
187 
188  for (octave_idx_type i = 0; i < nr; i++)
189  {
190  octave_quit ();
191  ax[Q[r + i] + aoff] = bx[i + boff];
192  }
193  }
194 }
195 
196 template <typename T>
197 static void
200 {
201  octave_idx_type b_rows = b.rows ();
202  octave_idx_type b_cols = b.cols ();
203 
204  octave_idx_type nr = a.rows ();
205  octave_idx_type nc = a.cols ();
206 
208 
209  for (octave_idx_type i = 0; i < nr; i++)
210  Qinv[Q[i]] = i;
211 
212  // First count the number of elements in the final array
213  octave_idx_type nel = a.xcidx (c) + b.nnz ();
214 
215  if (c + b_cols < nc)
216  nel += a.xcidx (nc) - a.xcidx (c + b_cols);
217 
218  for (octave_idx_type i = c; i < c + b_cols; i++)
219  {
220  for (octave_idx_type j = a.xcidx (i); j < a.xcidx (i+1); j++)
221  {
222  if (Qinv[a.xridx (j)] < r || Qinv[a.xridx (j)] >= r + b_rows)
223  nel++;
224  }
225  }
226 
227  OCTAVE_LOCAL_BUFFER (T, X, nr);
228 
230 
231  MSparse<T> tmp (a);
232 
233  a = MSparse<T> (nr, nc, nel);
234 
235  octave_idx_type *ri = a.xridx ();
236 
237  for (octave_idx_type i = 0; i < tmp.cidx (c); i++)
238  {
239  a.xdata (i) = tmp.xdata (i);
240  a.xridx (i) = tmp.xridx (i);
241  }
242 
243  for (octave_idx_type i = 0; i < c + 1; i++)
244  a.xcidx (i) = tmp.xcidx (i);
245 
246  octave_idx_type ii = a.xcidx (c);
247 
248  for (octave_idx_type i = c; i < c + b_cols; i++)
249  {
250  octave_quit ();
251 
252  for (octave_idx_type j = tmp.xcidx (i); j < tmp.xcidx (i+1); j++)
253  {
254  if (Qinv[tmp.xridx (j)] < r || Qinv[tmp.xridx (j)] >= r + b_rows)
255  {
256  X[tmp.xridx (j)] = tmp.xdata (j);
257  a.xridx (ii++) = tmp.xridx (j);
258  }
259  }
260 
261  octave_quit ();
262 
263  for (octave_idx_type j = b.cidx (i-c); j < b.cidx (i-c+1); j++)
264  {
265  X[Q[r + b.ridx (j)]] = b.data (j);
266  a.xridx (ii++) = Q[r + b.ridx (j)];
267  }
268 
269  sort.sort (ri + a.xcidx (i), ii - a.xcidx (i));
270 
271  for (octave_idx_type p = a.xcidx (i); p < ii; p++)
272  a.xdata (p) = X[a.xridx (p)];
273 
274  a.xcidx (i+1) = ii;
275  }
276 
277  for (octave_idx_type i = c + b_cols; i < nc; i++)
278  {
279  for (octave_idx_type j = tmp.xcidx (i); j < tmp.cidx (i+1); j++)
280  {
281  a.xdata (ii) = tmp.xdata (j);
282  a.xridx (ii++) = tmp.xridx (j);
283  }
284 
285  a.xcidx (i+1) = ii;
286  }
287 }
288 
289 template <typename T, typename RT>
290 static void
292 {
293  octave_idx_type b_nr = b.rows ();
294  octave_idx_type b_nc = b.cols ();
295 
296  const T *Bx = b.fortran_vec ();
297 
298  a.resize (dim_vector (b_nr, b_nc));
299 
300  RT *Btx = a.fortran_vec ();
301 
302  for (octave_idx_type j = 0; j < b_nc; j++)
303  {
304  octave_idx_type off = j * b_nr;
305  for (octave_idx_type i = 0; i < b_nr; i++)
306  {
307  octave_quit ();
308  Btx[p[i] + off] = Bx[ i + off];
309  }
310  }
311 }
312 
313 template <typename T, typename RT>
314 static void
316 {
317  octave_idx_type b_nr = b.rows ();
318  octave_idx_type b_nc = b.cols ();
319  octave_idx_type b_nz = b.nnz ();
320 
321  octave_idx_type nz = 0;
322 
323  a = MSparse<RT> (b_nr, b_nc, b_nz);
325  octave_idx_type *ri = a.xridx ();
326 
327  OCTAVE_LOCAL_BUFFER (RT, X, b_nr);
328 
329  a.xcidx (0) = 0;
330 
331  for (octave_idx_type j = 0; j < b_nc; j++)
332  {
333  for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++)
334  {
335  octave_quit ();
336  octave_idx_type r = p[b.ridx (i)];
337  X[r] = b.data (i);
338  a.xridx (nz++) = p[b.ridx (i)];
339  }
340 
341  sort.sort (ri + a.xcidx (j), nz - a.xcidx (j));
342 
343  for (octave_idx_type i = a.cidx (j); i < nz; i++)
344  {
345  octave_quit ();
346  a.xdata (i) = X[a.xridx (i)];
347  }
348 
349  a.xcidx (j+1) = nz;
350  }
351 }
352 
353 #if defined (HAVE_CXSPARSE)
354 
355 static void
357 {
358  // Dummy singularity handler so that LU solver doesn't flag
359  // an error for numerically rank defficient matrices
360 }
361 
362 #endif
363 
364 template <typename RT, typename ST, typename T>
365 RT
366 dmsolve (const ST& a, const T& b, octave_idx_type& info)
367 {
368  RT retval;
369 
370 #if defined (HAVE_CXSPARSE)
371 
372  octave_idx_type nr = a.rows ();
373  octave_idx_type nc = a.cols ();
374 
375  octave_idx_type b_nr = b.rows ();
376  octave_idx_type b_nc = b.cols ();
377 
378  if (nr < 0 || nc < 0 || nr != b_nr)
379  (*current_liboctave_error_handler)
380  ("matrix dimension mismatch in solution of minimum norm problem");
381 
382  if (nr == 0 || nc == 0 || b_nc == 0)
383  retval = RT (nc, b_nc, 0.0);
384  else
385  {
386  octave_idx_type nnz_remaining = a.nnz ();
387 
388  CXSPARSE_DNAME () csm;
389 
390  csm.m = nr;
391  csm.n = nc;
392  csm.x = nullptr;
393  csm.nz = -1;
394  csm.nzmax = a.nnz ();
395 
396  // Cast away const on A, with full knowledge that CSparse won't touch it.
397  // Prevents the methods below from making a copy of the data.
398  csm.p = const_cast<octave::suitesparse_integer *>
399  (octave::to_suitesparse_intptr (a.cidx ()));
400  csm.i = const_cast<octave::suitesparse_integer *>
401  (octave::to_suitesparse_intptr (a.ridx ()));
402 
403  CXSPARSE_DNAME (d) *dm = CXSPARSE_DNAME(_dmperm) (&csm, 0);
406 
408 
409  for (octave_idx_type i = 0; i < nr; i++)
410  pinv[p[i]] = i;
411 
412  RT btmp;
413  dmsolve_permute (btmp, b, pinv);
414  info = 0;
415 
416  retval.resize (nc, b_nc);
417 
418  // Leading over-determined block
419  if (dm->rr[2] < nr && dm->cc[3] < nc)
420  {
421  ST m = dmsolve_extract (a, pinv, q, dm->rr[2], nr, dm->cc[3], nc,
422  nnz_remaining, true);
423  nnz_remaining -= m.nnz ();
424  RT mtmp = octave::math::qrsolve (m, dmsolve_extract (btmp,
425  nullptr, nullptr,
426  dm->rr[2], b_nr,
427  0, b_nc),
428  info);
429  dmsolve_insert (retval, mtmp, q, dm->cc[3], 0);
430 
431  if (dm->rr[2] > 0 && ! info)
432  {
433  m = dmsolve_extract (a, pinv, q, 0, dm->rr[2],
434  dm->cc[3], nc, nnz_remaining, true);
435  nnz_remaining -= m.nnz ();
436  RT ctmp = dmsolve_extract (btmp, nullptr, nullptr,
437  0, dm->rr[2], 0, b_nc);
438  btmp.insert (ctmp - m * mtmp, 0, 0);
439  }
440  }
441 
442  // Structurally non-singular blocks
443  // FIXME: Should use fine Dulmange-Mendelsohn decomposition here.
444  if (dm->rr[1] < dm->rr[2] && dm->cc[2] < dm->cc[3] && ! info)
445  {
446  ST m = dmsolve_extract (a, pinv, q, dm->rr[1], dm->rr[2],
447  dm->cc[2], dm->cc[3], nnz_remaining, false);
448  nnz_remaining -= m.nnz ();
449  RT btmp2 = dmsolve_extract (btmp, nullptr, nullptr,
450  dm->rr[1], dm->rr[2],
451  0, b_nc);
452  double rcond = 0.0;
454  RT mtmp = m.solve (mtyp, btmp2, info, rcond,
456  if (info != 0)
457  {
458  info = 0;
459  mtmp = octave::math::qrsolve (m, btmp2, info);
460  }
461 
462  dmsolve_insert (retval, mtmp, q, dm->cc[2], 0);
463  if (dm->rr[1] > 0 && ! info)
464  {
465  m = dmsolve_extract (a, pinv, q, 0, dm->rr[1], dm->cc[2],
466  dm->cc[3], nnz_remaining, true);
467  nnz_remaining -= m.nnz ();
468  RT ctmp = dmsolve_extract (btmp, nullptr, nullptr,
469  0, dm->rr[1], 0, b_nc);
470  btmp.insert (ctmp - m * mtmp, 0, 0);
471  }
472  }
473 
474  // Trailing under-determined block
475  if (dm->rr[1] > 0 && dm->cc[2] > 0 && ! info)
476  {
477  ST m = dmsolve_extract (a, pinv, q, 0, dm->rr[1], 0,
478  dm->cc[2], nnz_remaining, true);
479  RT mtmp = octave::math::qrsolve (m, dmsolve_extract (btmp, nullptr,
480  nullptr, 0,
481  dm->rr[1], 0,
482  b_nc),
483  info);
484  dmsolve_insert (retval, mtmp, q, 0, 0);
485  }
486 
487  CXSPARSE_DNAME (_dfree) (dm);
488  }
489 
490 #else
491 
492  octave_unused_parameter (a);
493  octave_unused_parameter (b);
494  octave_unused_parameter (info);
495 
496  (*current_liboctave_error_handler)
497  ("support for CXSparse was unavailable or disabled when liboctave was built");
498 
499 #endif
500 
501  return retval;
502 }
503 
504 // Instantiations we need.
505 
506 template ComplexMatrix
508  (const SparseComplexMatrix&, const Matrix&, octave_idx_type&);
509 
510 template SparseComplexMatrix
513 
514 template ComplexMatrix
517 
518 template SparseComplexMatrix
521 
522 template Matrix
524  (const SparseMatrix&, const Matrix&, octave_idx_type&);
525 
526 template SparseMatrix
528  (const SparseMatrix&, const SparseMatrix&, octave_idx_type&);
529 
530 template ComplexMatrix
532  (const SparseMatrix&, const ComplexMatrix&, octave_idx_type&);
533 
534 template SparseComplexMatrix
template Matrix dmsolve< Matrix, SparseMatrix, Matrix >(const SparseMatrix &, const Matrix &, octave_idx_type &)
octave_int< uint64_t > octave_uint64
Template for N-dimensional array classes with like-type math operators.
Definition: MArray.h:32
F77_RET_T const F77_INT F77_CMPLX const F77_INT F77_CMPLX * B
Matrix qrsolve(const SparseMatrix &a, const MArray< double > &b, octave_idx_type &info)
Definition: sparse-qr.cc:2301
static void solve_singularity_warning(double)
template SparseComplexMatrix dmsolve< SparseComplexMatrix, SparseComplexMatrix, SparseMatrix >(const SparseComplexMatrix &, const SparseMatrix &, octave_idx_type &)
template SparseMatrix dmsolve< SparseMatrix, SparseMatrix, SparseMatrix >(const SparseMatrix &, const SparseMatrix &, octave_idx_type &)
static void dmsolve_insert(MArray< T > &a, const MArray< T > &b, const octave_idx_type *Q, octave_idx_type r, octave_idx_type c)
Sparse< T > sort(octave_idx_type dim=0, sortmode mode=ASCENDING) const
Definition: Sparse.cc:2231
octave_idx_type b_nr
Definition: sylvester.cc:76
template SparseComplexMatrix dmsolve< SparseComplexMatrix, SparseMatrix, SparseComplexMatrix >(const SparseMatrix &, const SparseComplexMatrix &, octave_idx_type &)
T & elem(octave_idx_type n)
Definition: Array.h:488
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:511
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:400
bool swap
Definition: load-save.cc:738
octave_idx_type * to_octave_idx_type_ptr(suitesparse_integer *i)
Definition: oct-sparse.cc:64
template ComplexMatrix dmsolve< ComplexMatrix, SparseComplexMatrix, ComplexMatrix >(const SparseComplexMatrix &, const ComplexMatrix &, octave_idx_type &)
F77_RET_T const F77_INT F77_CMPLX * A
int suitesparse_integer
Definition: oct-sparse.h:168
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
Definition: dMatrix.h:36
With real return the complex result
Definition: data.cc:3260
static void dmsolve_permute(MArray< RT > &a, const MArray< T > &b, const octave_idx_type *p)
#define CXSPARSE_DNAME(name)
Definition: oct-sparse.h:144
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * Q
void sort(T *data, octave_idx_type nel)
Definition: oct-sort.cc:1506
octave_idx_type b_nc
Definition: sylvester.cc:77
p
Definition: lu.cc:138
b
Definition: cellfun.cc:400
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:41
template ComplexMatrix dmsolve< ComplexMatrix, SparseMatrix, ComplexMatrix >(const SparseMatrix &, const ComplexMatrix &, octave_idx_type &)
static MSparse< T > dmsolve_extract(const MSparse< T > &A, const octave_idx_type *Pinv, const octave_idx_type *Q, octave_idx_type rst, octave_idx_type rend, octave_idx_type cst, octave_idx_type cend, octave_idx_type maxnz=-1, bool lazy=false)
for i
Definition: data.cc:5264
template SparseComplexMatrix dmsolve< SparseComplexMatrix, SparseComplexMatrix, SparseComplexMatrix >(const SparseComplexMatrix &, const SparseComplexMatrix &, octave_idx_type &)
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
template ComplexMatrix dmsolve< ComplexMatrix, SparseComplexMatrix, Matrix >(const SparseComplexMatrix &, const Matrix &, octave_idx_type &)
RT dmsolve(const ST &a, const T &b, octave_idx_type &info)
suitesparse_integer * to_suitesparse_intptr(octave_idx_type *i)
Definition: oct-sparse.cc:48