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
sparse-chol.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2016-2017 John W. Eaton
4 Copyright (C) 2005-2016 David Bateman
5 Copyright (C) 1998-2005 Andy Adler
6 
7 This file is part of Octave.
8 
9 Octave is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13 
14 Octave is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Octave; see the file COPYING. If not, see
21 <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 #if defined (HAVE_CONFIG_H)
26 # include "config.h"
27 #endif
28 
29 #include "sparse-chol.h"
30 #include "sparse-util.h"
31 #include "lo-error.h"
32 #include "oct-sparse.h"
33 #include "oct-spparms.h"
34 #include "quit.h"
35 #include "MatrixType.h"
36 
37 namespace octave
38 {
39  namespace math
40  {
41  template <typename chol_type>
42  class sparse_chol<chol_type>::sparse_chol_rep
43  {
44  public:
45 
47  : count (1), is_pd (false), minor_p (0), perms (), cond (0)
48 #if defined (HAVE_CHOLMOD)
49  , Lsparse (0), Common ()
50 #endif
51  { }
52 
53  sparse_chol_rep (const chol_type& a, bool natural, bool force)
54  : count (1), is_pd (false), minor_p (0), perms (), cond (0)
55 #if defined (HAVE_CHOLMOD)
56  , Lsparse (0), Common ()
57 #endif
58  {
59  init (a, natural, force);
60  }
61 
62  sparse_chol_rep (const chol_type& a, octave_idx_type& info,
63  bool natural, bool force)
64  : count (1), is_pd (false), minor_p (0), perms (), cond (0)
65 #if defined (HAVE_CHOLMOD)
66  , Lsparse (0), Common ()
67 #endif
68  {
69  info = init (a, natural, force);
70  }
71 
73  {
74 #if defined (HAVE_CHOLMOD)
75  if (Lsparse)
76  CHOLMOD_NAME (free_sparse) (&Lsparse, &Common);
77 
78  CHOLMOD_NAME(finish) (&Common);
79 #endif
80  }
81 
82 #if defined (HAVE_CHOLMOD)
83  cholmod_sparse *L (void) const
84  {
85  return Lsparse;
86  }
87 #endif
88 
89  octave_idx_type P (void) const
90  {
91 #if defined (HAVE_CHOLMOD)
92  return (minor_p == static_cast<octave_idx_type>(Lsparse->ncol) ?
93  0 : minor_p + 1);
94 #else
95  return 0;
96 #endif
97  }
98 
99  RowVector perm (void) const { return perms + 1; }
100 
101  SparseMatrix Q (void) const;
102 
103  bool is_positive_definite (void) const { return is_pd; }
104 
105  double rcond (void) const { return cond; }
106 
108 
109  private:
110 
111  bool is_pd;
112 
114 
116 
117  double cond;
118 
119 #if defined (HAVE_CHOLMOD)
120  cholmod_sparse *Lsparse;
121 
122  cholmod_common Common;
123 
124  void drop_zeros (const cholmod_sparse *S);
125 #endif
126 
127  octave_idx_type init (const chol_type& a, bool natural, bool force);
128 
129  // No copying!
130 
132 
134  };
135 
136 #if defined (HAVE_CHOLMOD)
137 
138  // Can't use CHOLMOD_NAME(drop)(0.0, S, cm) because it doesn't treat
139  // complex matrices.
140 
141  template <typename chol_type>
142  void
144  {
145  if (! S)
146  return;
147 
148  octave_idx_type *Sp = static_cast<octave_idx_type *>(S->p);
149  octave_idx_type *Si = static_cast<octave_idx_type *>(S->i);
150  chol_elt *Sx = static_cast<chol_elt *>(S->x);
151 
152  octave_idx_type pdest = 0;
153  octave_idx_type ncol = S->ncol;
154 
155  for (octave_idx_type k = 0; k < ncol; k++)
156  {
157  octave_idx_type p = Sp[k];
158  octave_idx_type pend = Sp[k+1];
159  Sp[k] = pdest;
160 
161  for (; p < pend; p++)
162  {
163  chol_elt sik = Sx[p];
164 
165  if (CHOLMOD_IS_NONZERO (sik))
166  {
167  if (p != pdest)
168  {
169  Si[pdest] = Si[p];
170  Sx[pdest] = sik;
171  }
172 
173  pdest++;
174  }
175  }
176  }
177 
178  Sp[ncol] = pdest;
179  }
180 
181  // Must provide a specialization for this function.
182  template <typename T>
183  int
184  get_xtype (void);
185 
186  template <>
187  inline int
189  {
190  return CHOLMOD_REAL;
191  }
192 
193  template <>
194  inline int
196  {
197  return CHOLMOD_COMPLEX;
198  }
199 
200 #endif
201 
202  template <typename chol_type>
205  bool natural, bool force)
206  {
207  volatile octave_idx_type info = 0;
208 
209 #if defined (HAVE_CHOLMOD)
210 
211  octave_idx_type a_nr = a.rows ();
212  octave_idx_type a_nc = a.cols ();
213 
214  if (a_nr != a_nc)
215  (*current_liboctave_error_handler) ("sparse_chol requires square matrix");
216 
217  cholmod_common *cm = &Common;
218 
219  // Setup initial parameters
220 
221  CHOLMOD_NAME(start) (cm);
222  cm->prefer_zomplex = false;
223 
224  double spu = octave_sparse_params::get_key ("spumoni");
225 
226  if (spu == 0.)
227  {
228  cm->print = -1;
229  SUITESPARSE_ASSIGN_FPTR (printf_func, cm->print_function, 0);
230  }
231  else
232  {
233  cm->print = static_cast<int> (spu) + 2;
234  SUITESPARSE_ASSIGN_FPTR (printf_func, cm->print_function, &SparseCholPrint);
235  }
236 
237  cm->error_handler = &SparseCholError;
238 
239  SUITESPARSE_ASSIGN_FPTR2 (divcomplex_func, cm->complex_divide, divcomplex);
240  SUITESPARSE_ASSIGN_FPTR2 (hypot_func, cm->hypotenuse, hypot);
241 
242  cm->final_asis = false;
243  cm->final_super = false;
244  cm->final_ll = true;
245  cm->final_pack = true;
246  cm->final_monotonic = true;
247  cm->final_resymbol = false;
248 
249  cholmod_sparse A;
250  cholmod_sparse *ac = &A;
251  double dummy;
252 
253  ac->nrow = a_nr;
254  ac->ncol = a_nc;
255 
256  ac->p = a.cidx ();
257  ac->i = a.ridx ();
258  ac->nzmax = a.nnz ();
259  ac->packed = true;
260  ac->sorted = true;
261  ac->nz = 0;
262 #if defined (OCTAVE_ENABLE_64)
263  ac->itype = CHOLMOD_LONG;
264 #else
265  ac->itype = CHOLMOD_INT;
266 #endif
267  ac->dtype = CHOLMOD_DOUBLE;
268  ac->stype = 1;
269  ac->xtype = get_xtype<chol_elt> ();
270 
271  if (a_nr < 1)
272  ac->x = &dummy;
273  else
274  ac->x = a.data ();
275 
276  // use natural ordering if no q output parameter
277  if (natural)
278  {
279  cm->nmethods = 1;
280  cm->method[0].ordering = CHOLMOD_NATURAL;
281  cm->postorder = false;
282  }
283 
284  cholmod_factor *Lfactor;
286  Lfactor = CHOLMOD_NAME(analyze) (ac, cm);
287  CHOLMOD_NAME(factorize) (ac, Lfactor, cm);
289 
290  is_pd = cm->status == CHOLMOD_OK;
291  info = (is_pd ? 0 : cm->status);
292 
293  if (is_pd || force)
294  {
296  cond = CHOLMOD_NAME(rcond) (Lfactor, cm);
298 
299  minor_p = Lfactor->minor;
300 
302  Lsparse = CHOLMOD_NAME(factor_to_sparse) (Lfactor, cm);
304 
305  if (minor_p > 0 && minor_p < a_nr)
306  {
307  size_t n1 = a_nr + 1;
308  Lsparse->p = CHOLMOD_NAME(realloc) (minor_p+1,
309  sizeof(octave_idx_type),
310  Lsparse->p, &n1, cm);
312  CHOLMOD_NAME(reallocate_sparse)
313  (static_cast<octave_idx_type *>(Lsparse->p)[minor_p], Lsparse, cm);
315 
316  Lsparse->ncol = minor_p;
317  }
318 
319  drop_zeros (Lsparse);
320 
321  if (! natural)
322  {
323  perms.resize (a_nr);
324  for (octave_idx_type i = 0; i < a_nr; i++)
325  perms(i) = static_cast<octave_idx_type *>(Lfactor->Perm)[i];
326  }
327  }
328 
329  // NAME used to prefix statistics report from print_common
330  static char blank_name[] = " ";
331 
333  CHOLMOD_NAME(print_common) (blank_name, cm);
334  CHOLMOD_NAME(free_factor) (&Lfactor, cm);
336 
337  return info;
338 
339 #else
340 
341  octave_unused_parameter (a);
342  octave_unused_parameter (natural);
343  octave_unused_parameter (force);
344 
345  (*current_liboctave_error_handler)
346  ("support for CHOLMOD was unavailable or disabled when liboctave was built");
347 
348  return info;
349 
350 #endif
351  }
352 
353  template <typename chol_type>
356  {
357 #if defined (HAVE_CHOLMOD)
358 
359  octave_idx_type n = Lsparse->nrow;
360  SparseMatrix p (n, n, n);
361 
362  for (octave_idx_type i = 0; i < n; i++)
363  {
364  p.xcidx (i) = i;
365  p.xridx (i) = static_cast<octave_idx_type>(perms (i));
366  p.xdata (i) = 1;
367  }
368 
369  p.xcidx (n) = n;
370 
371  return p;
372 
373 #else
374 
375  return SparseMatrix ();
376 
377 #endif
378  }
379 
380  template <typename chol_type>
382  : rep (new typename sparse_chol<chol_type>::sparse_chol_rep ())
383  { }
384 
385  template <typename chol_type>
386  sparse_chol<chol_type>::sparse_chol (const chol_type& a, bool natural,
387  bool force)
388  : rep (new typename
389  sparse_chol<chol_type>::sparse_chol_rep (a, natural, force))
390  { }
391 
392  template <typename chol_type>
394  bool natural, bool force)
395  : rep (new typename
396  sparse_chol<chol_type>::sparse_chol_rep (a, info, natural, force))
397  { }
398 
399  template <typename chol_type>
401  bool natural)
402  : rep (new typename
403  sparse_chol<chol_type>::sparse_chol_rep (a, info, natural, false))
404  { }
405 
406  template <typename chol_type>
408  : rep (new typename
409  sparse_chol<chol_type>::sparse_chol_rep (a, info, false, false))
410  { }
411 
412  template <typename chol_type>
414  : rep (a.rep)
415  {
416  rep->count++;
417  }
418 
419  template <typename chol_type>
421  {
422  if (--rep->count == 0)
423  delete rep;
424  }
425 
426  template <typename chol_type>
429  {
430  if (this != &a)
431  {
432  if (--rep->count == 0)
433  delete rep;
434 
435  rep = a.rep;
436  rep->count++;
437  }
438 
439  return *this;
440  }
441 
442  template <typename chol_type>
443  chol_type
445  {
446 #if defined (HAVE_CHOLMOD)
447 
448  cholmod_sparse *m = rep->L ();
449 
450  octave_idx_type nc = m->ncol;
451  octave_idx_type nnz = m->nzmax;
452 
453  chol_type ret (m->nrow, nc, nnz);
454 
455  for (octave_idx_type j = 0; j < nc+1; j++)
456  ret.xcidx (j) = static_cast<octave_idx_type *>(m->p)[j];
457 
458  for (octave_idx_type i = 0; i < nnz; i++)
459  {
460  ret.xridx (i) = static_cast<octave_idx_type *>(m->i)[i];
461  ret.xdata (i) = static_cast<chol_elt *>(m->x)[i];
462  }
463 
464  return ret;
465 
466 #else
467 
468  return chol_type ();
469 
470 #endif
471  }
472 
473  template <typename chol_type>
476  {
477  return rep->P ();
478  }
479 
480  template <typename chol_type>
481  RowVector
483  {
484  return rep->perm ();
485  }
486 
487  template <typename chol_type>
490  {
491  return rep->Q ();
492  }
493 
494  template <typename chol_type>
495  bool
497  {
498  return rep->is_positive_definite ();
499  }
500 
501  template <typename chol_type>
502  double
504  {
505  return rep->rcond ();
506  }
507 
508  template <typename chol_type>
509  chol_type
511  {
512  chol_type retval;
513 
514 #if defined (HAVE_CHOLMOD)
515 
516  cholmod_sparse *m = rep->L ();
517  octave_idx_type n = m->ncol;
518  RowVector perms = rep->perm ();
519  double rcond2;
520  octave_idx_type info;
521  MatrixType mattype (MatrixType::Upper);
522  chol_type linv = L ().hermitian ().inverse (mattype, info, rcond2, 1, 0);
523 
524  if (perms.numel () == n)
525  {
526  SparseMatrix Qc = Q ();
527 
528  retval = Qc * linv * linv.hermitian () * Qc.transpose ();
529  }
530  else
531  retval = linv * linv.hermitian ();
532 
533 #endif
534 
535  return retval;
536  }
537 
538  template <typename chol_type>
539  chol_type
540  chol2inv (const chol_type& r)
541  {
542  octave_idx_type r_nr = r.rows ();
543  octave_idx_type r_nc = r.cols ();
544  chol_type retval;
545 
546  if (r_nr != r_nc)
547  (*current_liboctave_error_handler) ("U must be a square matrix");
548 
549  MatrixType mattype (r);
550  int typ = mattype.type (false);
551  double rcond;
552  octave_idx_type info;
553  chol_type rtra, multip;
554 
555  if (typ == MatrixType::Upper)
556  {
557  rtra = r.transpose ();
558  multip = (rtra*r);
559  }
560  else if (typ == MatrixType::Lower)
561  {
562  rtra = r.transpose ();
563  multip = (r*rtra);
564  }
565  else
566  (*current_liboctave_error_handler) ("U must be a triangular matrix");
567 
568  MatrixType mattypenew (multip);
569  retval = multip.inverse (mattypenew, info, rcond, true, false);
570  return retval;
571  }
572 
573  // SparseComplexMatrix specialization (the value for the NATURAL
574  // parameter in the sparse_chol<T>::sparse_chol_rep constructor is
575  // different from the default).
576 
577  template <>
579  octave_idx_type& info)
580  : rep (new sparse_chol<SparseComplexMatrix>::sparse_chol_rep (a, info,
581  true,
582  false))
583  { }
584 
585  // Instantiations we need.
586 
587  template class sparse_chol<SparseMatrix>;
588 
589  template class sparse_chol<SparseComplexMatrix>;
590 
591  template SparseMatrix
593 
594  template SparseComplexMatrix
596  }
597 }
octave_idx_type * xridx(void)
Definition: Sparse.h:536
octave_idx_type P(void) const
Definition: sparse-chol.cc:475
sparse_chol_rep(const chol_type &a, bool natural, bool force)
Definition: sparse-chol.cc:53
Octave interface to the compression and uncompression libraries.
Definition: aepbalance.cc:47
SparseMatrix Q(void) const
Definition: sparse-chol.cc:489
SparseMatrix transpose(void) const
Definition: dSparse.h:141
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
chol_type::element_type chol_elt
Definition: sparse-chol.h:84
void SparseCholError(int status, char *file, int line, char *message)
Definition: sparse-util.cc:61
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
Definition: lo-error.c:38
chol_type L(void) const
Definition: sparse-chol.cc:444
for large enough k
Definition: lu.cc:606
RowVector perm(void) const
Definition: sparse-chol.cc:482
octave_idx_type * xcidx(void)
Definition: Sparse.h:549
chol_type inverse(void) const
Definition: sparse-chol.cc:510
SparseMatrix hermitian(void) const
Definition: dSparse.h:145
sparse_chol_rep(const chol_type &a, octave_idx_type &info, bool natural, bool force)
Definition: sparse-chol.cc:62
octave_idx_type a_nc
Definition: sylvester.cc:72
static double get_key(const std::string &key)
Definition: oct-spparms.cc:95
int get_xtype< Complex >(void)
Definition: sparse-chol.cc:195
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
octave_idx_type init(const chol_type &a, bool natural, bool force)
Definition: sparse-chol.cc:204
int get_xtype(void)
octave_idx_type a_nr
Definition: sylvester.cc:71
T chol2inv(const T &r)
Definition: chol.cc:247
if(nargin< 2) print_usage()
Definition: cellfun.cc:405
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
sparse_chol & operator=(const sparse_chol &a)
Definition: sparse-chol.cc:428
is false
Definition: cellfun.cc:398
octave_value retval
Definition: data.cc:6294
bool is_positive_definite(void) const
Definition: sparse-chol.cc:496
template SparseMatrix chol2inv< SparseMatrix >(const SparseMatrix &r)
cholmod_sparse * L(void) const
Definition: sparse-chol.cc:83
sparse_chol_rep * rep
Definition: sparse-chol.h:86
void drop_zeros(const cholmod_sparse *S)
Definition: sparse-chol.cc:143
int get_xtype< double >(void)
Definition: sparse-chol.cc:188
defaults to zero A value of zero computes the digamma a value the trigamma and so on The digamma function is defined
Definition: psi.cc:68
int SparseCholPrint(const char *fmt,...)
Definition: sparse-util.cc:73
octave::sys::time start
Definition: graphics.cc:11731
virtual ~sparse_chol(void)
Definition: sparse-chol.cc:420
#define END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE
Definition: quit.h:262
=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
template SparseComplexMatrix chol2inv< SparseComplexMatrix >(const SparseComplexMatrix &r)
#define BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE
Definition: quit.h:240
octave_idx_type P(void) const
Definition: sparse-chol.cc:89
double rcond(void) const
Definition: sparse-chol.cc:503
F77_RET_T const F77_INT F77_CMPLX * A
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