GNU Octave  3.8.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-2013 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. This\n\
59 permutation such that the Cholesky@tie{}factorization of @code{@var{S}\n\
60 (@var{p}, @var{p})} tends to be sparser than the Cholesky@tie{}factorization\n\
61 of @var{S} itself. @code{amd} is typically faster than @code{symamd} but\n\
62 serves a similar purpose.\n\
63 \n\
64 The optional parameter @var{opts} is a structure that controls the\n\
65 behavior of @code{amd}. The fields of the structure are\n\
66 \n\
67 @table @asis\n\
68 @item @var{opts}.dense\n\
69 Determines what @code{amd} considers to be a dense row or column of the\n\
70 input matrix. Rows or columns with more than @code{max(16, (dense *\n\
71 sqrt (@var{n})} entries, where @var{n} is the order of the matrix @var{S},\n\
72 are ignored by @code{amd} during the calculation of the permutation\n\
73 The value of dense must be a positive scalar and its default value is 10.0\n\
74 \n\
75 @item @var{opts}.aggressive\n\
76 If this value is a non zero scalar, then @code{amd} performs aggressive\n\
77 absorption. The default is not to perform aggressive absorption.\n\
78 @end table\n\
79 \n\
80 The author of the code itself is Timothy A. Davis\n\
81 @email{davis@@cise.ufl.edu}, University of Florida (see\n\
82 @url{http://www.cise.ufl.edu/research/sparse/amd}).\n\
83 @seealso{symamd, colamd}\n\
84 @end deftypefn")
85 {
86  octave_value_list retval;
87 
88 #ifdef HAVE_AMD
89  int nargin = args.length ();
90 
91  if (nargin < 1 || nargin > 2)
92  print_usage ();
93  else
94  {
95  octave_idx_type n_row, n_col;
96  const octave_idx_type *ridx, *cidx;
97  SparseMatrix sm;
99 
100  if (args(0).is_sparse_type ())
101  {
102  if (args(0).is_complex_type ())
103  {
104  scm = args(0).sparse_complex_matrix_value ();
105  n_row = scm.rows ();
106  n_col = scm.cols ();
107  ridx = scm.xridx ();
108  cidx = scm.xcidx ();
109  }
110  else
111  {
112  sm = args(0).sparse_matrix_value ();
113  n_row = sm.rows ();
114  n_col = sm.cols ();
115  ridx = sm.xridx ();
116  cidx = sm.xcidx ();
117  }
118  }
119  else
120  {
121  if (args(0).is_complex_type ())
122  sm = SparseMatrix (real (args(0).complex_matrix_value ()));
123  else
124  sm = SparseMatrix (args(0).matrix_value ());
125 
126  n_row = sm.rows ();
127  n_col = sm.cols ();
128  ridx = sm.xridx ();
129  cidx = sm.xcidx ();
130  }
131 
132  if (!error_state && n_row != n_col)
133  error ("amd: matrix S must be square");
134 
135  if (!error_state)
136  {
137  OCTAVE_LOCAL_BUFFER (double, Control, AMD_CONTROL);
138  AMD_NAME (_defaults) (Control) ;
139  if (nargin > 1)
140  {
141  octave_scalar_map arg1 = args(1).scalar_map_value ();
142 
143  if (!error_state)
144  {
145  octave_value tmp;
146 
147  tmp = arg1.getfield ("dense");
148  if (tmp.is_defined ())
149  Control[AMD_DENSE] = tmp.double_value ();
150 
151  tmp = arg1.getfield ("aggressive");
152  if (tmp.is_defined ())
153  Control[AMD_AGGRESSIVE] = tmp.double_value ();
154  }
155  else
156  error ("amd: OPTS argument must be a scalar structure");
157  }
158 
159  if (!error_state)
160  {
162  Matrix xinfo (AMD_INFO, 1);
163  double *Info = xinfo.fortran_vec ();
164 
165  // FIXME: how can we manage the memory allocation of amd
166  // in a cleaner manner?
167  amd_malloc = malloc;
168  amd_free = free;
169  amd_calloc = calloc;
170  amd_realloc = realloc;
171  amd_printf = printf;
172 
173  octave_idx_type result = AMD_NAME (_order) (n_col, cidx, ridx, P,
174  Control, Info);
175 
176  switch (result)
177  {
178  case AMD_OUT_OF_MEMORY:
179  error ("amd: out of memory");
180  break;
181  case AMD_INVALID:
182  error ("amd: matrix S is corrupted");
183  break;
184  default:
185  {
186  if (nargout > 1)
187  retval(1) = xinfo;
188 
189  Matrix Pout (1, n_col);
190  for (octave_idx_type i = 0; i < n_col; i++)
191  Pout.xelem (i) = P[i] + 1;
192 
193  retval(0) = Pout;
194  }
195  }
196  }
197  }
198  }
199 #else
200 
201  error ("amd: not available in this version of Octave");
202 
203 #endif
204 
205  return retval;
206 }