GNU Octave  4.0.0
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
amd.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2008-2015 David Bateman
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 // This is the octave interface to amd, which bore the copyright given
24 // in the help of the functions.
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 
30 #include <cstdlib>
31 
32 #include <string>
33 #include <vector>
34 
35 #include "ov.h"
36 #include "defun-dld.h"
37 #include "pager.h"
38 #include "ov-re-mat.h"
39 
40 #include "ov-re-sparse.h"
41 #include "ov-cx-sparse.h"
42 #include "oct-map.h"
43 
44 #include "oct-sparse.h"
45 #include "oct-locbuf.h"
46 
47 #ifdef USE_64_BIT_IDX_T
48 #define AMD_NAME(name) amd_l ## name
49 #else
50 #define AMD_NAME(name) amd ## name
51 #endif
52 
53 DEFUN_DLD (amd, args, nargout,
54  "-*- texinfo -*-\n\
55 @deftypefn {Loadable Function} {@var{p} =} amd (@var{S})\n\
56 @deftypefnx {Loadable Function} {@var{p} =} amd (@var{S}, @var{opts})\n\
57 \n\
58 Return the approximate minimum degree permutation of a matrix.\n\
59 \n\
60 This is a permutation such that the Cholesky@tie{}factorization of\n\
61 @code{@var{S} (@var{p}, @var{p})} tends to be sparser than the\n\
62 Cholesky@tie{}factorization of @var{S} itself. @code{amd} is typically\n\
63 faster than @code{symamd} but serves a similar purpose.\n\
64 \n\
65 The optional parameter @var{opts} is a structure that controls the behavior\n\
66 of @code{amd}. The fields of the structure are\n\
67 \n\
68 @table @asis\n\
69 @item @var{opts}.dense\n\
70 Determines what @code{amd} considers to be a dense row or column of the\n\
71 input matrix. Rows or columns with more than @code{max (16, (dense *\n\
72 sqrt (@var{n})))} entries, where @var{n} is the order of the matrix @var{S},\n\
73 are ignored by @code{amd} during the calculation of the permutation.\n\
74 The value of dense must be a positive scalar and the default value is 10.0\n\
75 \n\
76 @item @var{opts}.aggressive\n\
77 If this value is a nonzero scalar, then @code{amd} performs aggressive\n\
78 absorption. The default is not to perform aggressive absorption.\n\
79 @end table\n\
80 \n\
81 The author of the code itself is Timothy A. Davis\n\
82 @email{davis@@cise.ufl.edu}, University of Florida\n\
83 (see @url{http://www.cise.ufl.edu/research/sparse/amd}).\n\
84 @seealso{symamd, colamd}\n\
85 @end deftypefn")
86 {
87  octave_value_list retval;
88 
89 #ifdef HAVE_AMD
90  int nargin = args.length ();
91 
92  if (nargin < 1 || nargin > 2)
93  print_usage ();
94  else
95  {
96  octave_idx_type n_row, n_col;
97  const octave_idx_type *ridx, *cidx;
98  SparseMatrix sm;
100 
101  if (args(0).is_sparse_type ())
102  {
103  if (args(0).is_complex_type ())
104  {
105  scm = args(0).sparse_complex_matrix_value ();
106  n_row = scm.rows ();
107  n_col = scm.cols ();
108  ridx = scm.xridx ();
109  cidx = scm.xcidx ();
110  }
111  else
112  {
113  sm = args(0).sparse_matrix_value ();
114  n_row = sm.rows ();
115  n_col = sm.cols ();
116  ridx = sm.xridx ();
117  cidx = sm.xcidx ();
118  }
119  }
120  else
121  {
122  if (args(0).is_complex_type ())
123  sm = SparseMatrix (real (args(0).complex_matrix_value ()));
124  else
125  sm = SparseMatrix (args(0).matrix_value ());
126 
127  n_row = sm.rows ();
128  n_col = sm.cols ();
129  ridx = sm.xridx ();
130  cidx = sm.xcidx ();
131  }
132 
133  if (!error_state && n_row != n_col)
134  error ("amd: matrix S must be square");
135 
136  if (!error_state)
137  {
138  OCTAVE_LOCAL_BUFFER (double, Control, AMD_CONTROL);
139  AMD_NAME (_defaults) (Control) ;
140  if (nargin > 1)
141  {
142  octave_scalar_map arg1 = args(1).scalar_map_value ();
143 
144  if (!error_state)
145  {
146  octave_value tmp;
147 
148  tmp = arg1.getfield ("dense");
149  if (tmp.is_defined ())
150  Control[AMD_DENSE] = tmp.double_value ();
151 
152  tmp = arg1.getfield ("aggressive");
153  if (tmp.is_defined ())
154  Control[AMD_AGGRESSIVE] = tmp.double_value ();
155  }
156  else
157  error ("amd: OPTS argument must be a scalar structure");
158  }
159 
160  if (!error_state)
161  {
163  Matrix xinfo (AMD_INFO, 1);
164  double *Info = xinfo.fortran_vec ();
165 
166  // FIXME: how can we manage the memory allocation of amd
167  // in a cleaner manner?
168  SUITESPARSE_ASSIGN_FPTR (malloc_func, amd_malloc, malloc);
169  SUITESPARSE_ASSIGN_FPTR (free_func, amd_free, free);
170  SUITESPARSE_ASSIGN_FPTR (calloc_func, amd_calloc, calloc);
171  SUITESPARSE_ASSIGN_FPTR (realloc_func, amd_realloc, realloc);
172  SUITESPARSE_ASSIGN_FPTR (printf_func, amd_printf, printf);
173 
174  octave_idx_type result = AMD_NAME (_order) (n_col, cidx, ridx, P,
175  Control, Info);
176 
177  switch (result)
178  {
179  case AMD_OUT_OF_MEMORY:
180  error ("amd: out of memory");
181  break;
182  case AMD_INVALID:
183  error ("amd: matrix S is corrupted");
184  break;
185  default:
186  {
187  if (nargout > 1)
188  retval(1) = xinfo;
189 
190  Matrix Pout (1, n_col);
191  for (octave_idx_type i = 0; i < n_col; i++)
192  Pout.xelem (i) = P[i] + 1;
193 
194  retval(0) = Pout;
195  }
196  }
197  }
198  }
199  }
200 #else
201 
202  error ("amd: not available in this version of Octave");
203 
204 #endif
205 
206  return retval;
207 }
208 /*
209 %!shared A, A2, opts
210 %! A = ones (20, 30);
211 %! A2 = ones (30, 30);
212 %!
213 %!testif HAVE_AMD
214 %! assert(amd (A2), [1:30])
215 %! opts.dense = 25;
216 %! assert(amd (A2, opts), [1:30])
217 %! opts.aggressive = 1;
218 %! assert(amd (A2, opts), [1:30])
219 
220 %!error <matrix S must be square|not available in this version> amd (A)
221 %!error amd (A2, 2)
222 %!error <matrix S is corrupted|not available in this version> amd ([])
223 */
octave_idx_type * xridx(void)
Definition: Sparse.h:524
octave_idx_type cols(void) const
Definition: Sparse.h:264
octave_idx_type rows(void) const
Definition: Sparse.h:263
OCTINTERP_API void print_usage(void)
Definition: defun.cc:51
octave_idx_type length(void) const
Definition: oct-obj.h:89
bool is_defined(void) const
Definition: ov.h:520
octave_idx_type * xcidx(void)
Definition: Sparse.h:537
void error(const char *fmt,...)
Definition: error.cc:476
#define AMD_NAME(name)
Definition: amd.cc:50
int error_state
Definition: error.cc:101
Definition: dMatrix.h:35
T & xelem(octave_idx_type n)
Definition: Array.h:353
void free(void *)
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:197
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:164
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Definition: defun-dld.h:59
void * malloc(size_t)
const T * fortran_vec(void) const
Definition: Array.h:481
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:156
double double_value(bool frc_str_conv=false) const
Definition: ov.h:759