GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
symbfact.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2005-2017 David Bateman
4 Copyright (C) 1998-2005 Andy Adler
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 the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 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 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include "oct-locbuf.h"
29 #include "oct-sparse.h"
30 #include "oct-spparms.h"
31 #include "sparse-chol.h"
32 #include "sparse-util.h"
33 
34 #include "ov-re-sparse.h"
35 #include "ov-cx-sparse.h"
36 #include "defun-dld.h"
37 #include "error.h"
38 #include "errwarn.h"
39 #include "ovl.h"
40 #include "utils.h"
41 
42 DEFUN_DLD (symbfact, args, nargout,
43  doc: /* -*- texinfo -*-
44 @deftypefn {} {[@var{count}, @var{h}, @var{parent}, @var{post}, @var{R}] =} symbfact (@var{S})
45 @deftypefnx {} {[@dots{}] =} symbfact (@var{S}, @var{typ})
46 @deftypefnx {} {[@dots{}] =} symbfact (@var{S}, @var{typ}, @var{mode})
47 
48 Perform a symbolic factorization analysis of the sparse matrix @var{S}.
49 
50 The input variables are
51 
52 @table @var
53 @item S
54 @var{S} is a real or complex sparse matrix.
55 
56 @item typ
57 Is the type of the factorization and can be one of
58 
59 @table @asis
60 @item @qcode{"sym"} (default)
61 Factorize @var{S}. Assumes @var{S} is symmetric and uses the upper
62 triangular portion of the matrix.
63 
64 @item @qcode{"col"}
65 Factorize @tcode{@var{S}' * @var{S}}.
66 
67 @item @qcode{"row"}
68 Factorize @tcode{@var{S} * @var{S}'}.
69 
70 @item @qcode{"lo"}
71 Factorize @tcode{@var{S}'}. Assumes @var{S} is symmetric and uses the lower
72 triangular portion of the matrix.
73 @end table
74 
75 @item mode
76 When @var{mode} is unspecified return the Cholesky@tie{}factorization for
77 @var{R}. If @var{mode} is @qcode{"lower"} or @qcode{"L"} then return
78 the conjugate transpose @tcode{@var{R}'} which is a lower triangular factor.
79 The conjugate transpose version is faster and uses less memory, but still
80 returns the same values for all other outputs: @var{count}, @var{h},
81 @var{parent}, and @var{post}.
82 @end table
83 
84 The output variables are:
85 
86 @table @var
87 @item count
88 The row counts of the Cholesky@tie{}factorization as determined by
89 @var{typ}. The computational difficulty of performing the true
90 factorization using @code{chol} is @code{sum (@var{count} .^ 2)}.
91 
92 @item h
93 The height of the elimination tree.
94 
95 @item parent
96 The elimination tree itself.
97 
98 @item post
99 A sparse boolean matrix whose structure is that of the
100 Cholesky@tie{}factorization as determined by @var{typ}.
101 @end table
102 @seealso{chol, etree, treelayout}
103 @end deftypefn */)
104 {
105 #if defined (HAVE_CHOLMOD)
106 
107  int nargin = args.length ();
108 
109  if (nargin < 1 || nargin > 3)
110  print_usage ();
111 
113 
114  double dummy;
115  cholmod_sparse Astore;
116  cholmod_sparse *A = &Astore;
117  A->packed = true;
118  A->sorted = true;
119  A->nz = 0;
120 #if defined (OCTAVE_ENABLE_64)
121  A->itype = CHOLMOD_LONG;
122 #else
123  A->itype = CHOLMOD_INT;
124 #endif
125  A->dtype = CHOLMOD_DOUBLE;
126  A->stype = 1;
127  A->x = &dummy;
128 
129  if (args(0).is_real_type ())
130  {
131  const SparseMatrix a = args(0).sparse_matrix_value ();
132  A->nrow = a.rows ();
133  A->ncol = a.cols ();
134  A->p = a.cidx ();
135  A->i = a.ridx ();
136  A->nzmax = a.nnz ();
137  A->xtype = CHOLMOD_REAL;
138 
139  if (a.rows () > 0 && a.cols () > 0)
140  A->x = a.data ();
141  }
142  else if (args(0).is_complex_type ())
143  {
144  const SparseComplexMatrix a = args(0).sparse_complex_matrix_value ();
145  A->nrow = a.rows ();
146  A->ncol = a.cols ();
147  A->p = a.cidx ();
148  A->i = a.ridx ();
149  A->nzmax = a.nnz ();
150  A->xtype = CHOLMOD_COMPLEX;
151 
152  if (a.rows () > 0 && a.cols () > 0)
153  A->x = a.data ();
154  }
155  else
156  err_wrong_type_arg ("symbfact", args(0));
157 
158  octave_idx_type coletree = false;
159  octave_idx_type n = A->nrow;
160 
161  if (nargin > 1)
162  {
163  std::string str = args(1).xstring_value ("TYP must be a string");
164  // FIXME: The input validation could be improved to use strncmp
165  char ch;
166  ch = tolower (str[0]);
167  if (ch == 'r') // 'row'
168  A->stype = 0;
169  else if (ch == 'c') // 'col'
170  {
171  n = A->ncol;
172  coletree = true;
173  A->stype = 0;
174  }
175  else if (ch == 's') // 'sym' (default)
176  A->stype = 1;
177  else if (ch == 'l') // 'lo'
178  A->stype = -1;
179  else
180  error ("symbfact: unrecognized TYP \"%s\"", str.c_str ());
181  }
182 
183  if (nargin == 3)
184  {
185  std::string str = args(2).xstring_value ("MODE must be a string");
186  // FIXME: The input validation could be improved to use strncmp
187  char ch;
188  ch = toupper (str[0]);
189  if (ch != 'L')
190  error ("symbfact: unrecognized MODE \"%s\"", str.c_str ());
191  }
192 
193  if (A->stype && A->nrow != A->ncol)
194  err_square_matrix_required ("symbfact", "S");
195 
198  OCTAVE_LOCAL_BUFFER (octave_idx_type, ColCount, n);
201 
202  cholmod_common Common;
203  cholmod_common *cm = &Common;
204  CHOLMOD_NAME(start) (cm);
205 
206  double spu = octave_sparse_params::get_key ("spumoni");
207  if (spu == 0.)
208  {
209  cm->print = -1;
210  SUITESPARSE_ASSIGN_FPTR (printf_func, cm->print_function, 0);
211  }
212  else
213  {
214  cm->print = static_cast<int> (spu) + 2;
215  SUITESPARSE_ASSIGN_FPTR (printf_func, cm->print_function, &SparseCholPrint);
216  }
217 
218  cm->error_handler = &SparseCholError;
219  SUITESPARSE_ASSIGN_FPTR2 (divcomplex_func, cm->complex_divide, divcomplex);
220  SUITESPARSE_ASSIGN_FPTR2 (hypot_func, cm->hypotenuse, hypot);
221 
222  cholmod_sparse *F = CHOLMOD_NAME(transpose) (A, 0, cm);
223  cholmod_sparse *Aup, *Alo;
224 
225  if (A->stype == 1 || coletree)
226  {
227  Aup = A;
228  Alo = F;
229  }
230  else
231  {
232  Aup = F;
233  Alo = A;
234  }
235 
236  CHOLMOD_NAME(etree) (Aup, Parent, cm);
237 
238  ColumnVector tmp (n); // Declaration must precede any goto cleanup.
239  std::string err_msg;
240 
241  if (cm->status < CHOLMOD_OK)
242  {
243  err_msg = "symbfact: matrix corrupted";
244  goto cleanup;
245  }
246 
247  if (CHOLMOD_NAME(postorder) (Parent, n, 0, Post, cm) != n)
248  {
249  err_msg = "symbfact: postorder failed";
250  goto cleanup;
251  }
252 
253  CHOLMOD_NAME(rowcolcounts) (Alo, 0, 0, Parent, Post, 0,
254  ColCount, First, Level, cm);
255 
256  if (cm->status < CHOLMOD_OK)
257  {
258  err_msg = "symbfact: matrix corrupted";
259  goto cleanup;
260  }
261 
262  if (nargout > 4)
263  {
264  cholmod_sparse *A1, *A2;
265 
266  if (A->stype == 1)
267  {
268  A1 = A;
269  A2 = 0;
270  }
271  else if (A->stype == -1)
272  {
273  A1 = F;
274  A2 = 0;
275  }
276  else if (coletree)
277  {
278  A1 = F;
279  A2 = A;
280  }
281  else
282  {
283  A1 = A;
284  A2 = F;
285  }
286 
287  // count the total number of entries in L
288  octave_idx_type lnz = 0;
289  for (octave_idx_type j = 0 ; j < n ; j++)
290  lnz += ColCount[j];
291 
292  // allocate the output matrix L (pattern-only)
293  SparseBoolMatrix L (n, n, lnz);
294 
295  // initialize column pointers
296  lnz = 0;
297  for (octave_idx_type j = 0 ; j < n ; j++)
298  {
299  L.xcidx(j) = lnz;
300  lnz += ColCount[j];
301  }
302  L.xcidx(n) = lnz;
303 
304  // create a copy of the column pointers
305  octave_idx_type *W = First;
306  for (octave_idx_type j = 0 ; j < n ; j++)
307  W[j] = L.xcidx (j);
308 
309  // get workspace for computing one row of L
310  cholmod_sparse *R
311  = CHOLMOD_NAME(allocate_sparse) (n, 1, n, false, true,
312  0, CHOLMOD_PATTERN, cm);
313  octave_idx_type *Rp = static_cast<octave_idx_type *> (R->p);
314  octave_idx_type *Ri = static_cast<octave_idx_type *> (R->i);
315 
316  // compute L one row at a time
317  for (octave_idx_type k = 0 ; k < n ; k++)
318  {
319  // get the kth row of L and store in the columns of L
320  CHOLMOD_NAME(row_subtree) (A1, A2, k, Parent, R, cm);
321  for (octave_idx_type p = 0 ; p < Rp[1] ; p++)
322  L.xridx (W[Ri[p]]++) = k;
323 
324  // add the diagonal entry
325  L.xridx (W[k]++) = k;
326  }
327 
328  // free workspace
329  CHOLMOD_NAME(free_sparse) (&R, cm);
330 
331  // transpose L to get R, or leave as is
332  if (nargin < 3)
333  L = L.transpose ();
334 
335  // fill numerical values of L with one's
336  for (octave_idx_type p = 0 ; p < lnz ; p++)
337  L.xdata(p) = true;
338 
339  retval(4) = L;
340  }
341 
342  if (nargout > 3)
343  {
344  for (octave_idx_type i = 0; i < n; i++)
345  tmp(i) = Post[i] + 1;
346  retval(3) = tmp;
347  }
348 
349  if (nargout > 2)
350  {
351  for (octave_idx_type i = 0; i < n; i++)
352  tmp(i) = Parent[i] + 1;
353  retval(2) = tmp;
354  }
355 
356  if (nargout > 1)
357  {
358  // compute the elimination tree height
359  octave_idx_type height = 0;
360  for (int i = 0 ; i < n ; i++)
361  height = std::max (height, Level[i]);
362  height++;
363  retval(1) = static_cast<double> (height);
364  }
365 
366  for (octave_idx_type i = 0; i < n; i++)
367  tmp(i) = ColCount[i];
368  retval(0) = tmp;
369 
370 cleanup:
371  CHOLMOD_NAME(free_sparse) (&F, cm);
372  CHOLMOD_NAME(finish) (cm);
373 
374  if (! err_msg.empty ())
375  error (err_msg.c_str ());
376 
377  return retval;
378 
379 #else
380 
381  octave_unused_parameter (args);
382  octave_unused_parameter (nargout);
383 
384  err_disabled_feature ("symbfact", "CHOLMOD");
385 
386 #endif
387 }
388 
389 /*
390 %!testif HAVE_CHOLMOD
391 %! A = sparse (magic (3));
392 %! [count, h, parent, post, r] = symbfact (A);
393 %! assert (count, [3; 2; 1]);
394 %! assert (h, 3);
395 %! assert (parent, [2; 3; 0]);
396 %! assert (r, sparse (triu (true (3))));
397 
398 %!testif HAVE_CHOLMOD
399 %! ## Test MODE "lower"
400 %! A = sparse (magic (3));
401 %! [~, ~, ~, ~, l] = symbfact (A, "sym", "lower");
402 %! assert (l, sparse (tril (true (3))));
403 
404 %!testif HAVE_CHOLMOD <42587>
405 %! ## singular matrix
406 %! A = sparse ([1 0 8;0 1 8;8 8 1]);
407 %! [count, h, parent, post, r] = symbfact (A);
408 
409 ## Test input validation
410 %!testif HAVE_CHOLMOD
411 %! fail ("symbfact ()");
412 %! fail ("symbfact (1,2,3,4)");
413 %! fail ("symbfact ({1})", "wrong type argument 'cell'");
414 %! fail ("symbfact (sparse (1), {1})", "TYP must be a string");
415 %! fail ("symbfact (sparse (1), 'foobar')", 'unrecognized TYP "foobar"');
416 %! fail ("symbfact (sparse (1), 'sym', {'L'})", "MODE must be a string");
417 %! fail ('symbfact (sparse (1), "sym", "foobar")', 'unrecognized MODE "foobar"');
418 %! fail ("symbfact (sparse ([1, 2; 3, 4; 5, 6]))", "S must be a square matrix");
419 
420 */
octave_idx_type * xridx(void)
Definition: Sparse.h:536
octave_idx_type cols(void) const
Definition: Sparse.h:272
T * data(void)
Definition: Sparse.h:521
octave_idx_type rows(void) const
Definition: Sparse.h:271
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
void SparseCholError(int status, char *file, int line, char *message)
Definition: sparse-util.cc:61
for large enough k
Definition: lu.cc:606
static void transpose(octave_idx_type N, const octave_idx_type *ridx, const octave_idx_type *cidx, octave_idx_type *ridx2, octave_idx_type *cidx2)
Definition: symrcm.cc:382
octave_idx_type * xcidx(void)
Definition: Sparse.h:549
void error(const char *fmt,...)
Definition: error.cc:570
SparseBoolMatrix transpose(void) const
Definition: boolSparse.h:91
octave_idx_type * cidx(void)
Definition: Sparse.h:543
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:112
static void coletree(const octave_idx_type *ridx, const octave_idx_type *colbeg, octave_idx_type *colend, octave_idx_type *parent, octave_idx_type nr, octave_idx_type nc)
Definition: colamd.cc:165
static double get_key(const std::string &key)
Definition: oct-spparms.cc:95
octave_idx_type nnz(void) const
Actual number of nonzero terms.
Definition: Sparse.h:253
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:398
JNIEnv void * args
Definition: ov-java.cc:67
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:935
int nargin
Definition: graphics.cc:10115
std::string str
Definition: hash.cc:118
OCTAVE_EXPORT octave_value_list W
Definition: qz.cc:216
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:156
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
int SparseCholPrint(const char *fmt,...)
Definition: sparse-util.cc:73
octave_idx_type * ridx(void)
Definition: Sparse.h:530
octave::sys::time start
Definition: graphics.cc:11731
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
p
Definition: lu.cc:138
T * xdata(void)
Definition: Sparse.h:523
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:200
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Definition: defun-dld.h:45
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
F77_RET_T const F77_INT F77_CMPLX * A
void F(const TSRC *v, TRES *r, octave_idx_type m, octave_idx_type n)
Definition: mx-inlines.cc:719