GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
amd.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2008-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://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 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <cstdlib>
31 
32 #include "CSparse.h"
33 #include "Sparse.h"
34 #include "dMatrix.h"
35 #include "oct-locbuf.h"
36 #include "oct-sparse.h"
37 
38 #include "defun-dld.h"
39 #include "error.h"
40 #include "errwarn.h"
41 #include "oct-map.h"
42 #include "ov.h"
43 #include "ovl.h"
44 
45 DEFUN_DLD (amd, args, nargout,
46  doc: /* -*- texinfo -*-
47 @deftypefn {} {@var{p} =} amd (@var{S})
48 @deftypefnx {} {@var{p} =} amd (@var{S}, @var{opts})
49 
50 Return the approximate minimum degree permutation of a matrix.
51 
52 This is a permutation such that the Cholesky@tie{}factorization of
53 @code{@var{S} (@var{p}, @var{p})} tends to be sparser than the
54 Cholesky@tie{}factorization of @var{S} itself. @code{amd} is typically
55 faster than @code{symamd} but serves a similar purpose.
56 
57 The optional parameter @var{opts} is a structure that controls the behavior
58 of @code{amd}. The fields of the structure are
59 
60 @table @asis
61 @item @var{opts}.dense
62 Determines what @code{amd} considers to be a dense row or column of the
63 input matrix. Rows or columns with more than @code{max (16, (dense *
64 sqrt (@var{n})))} entries, where @var{n} is the order of the matrix @var{S},
65 are ignored by @code{amd} during the calculation of the permutation.
66 The value of dense must be a positive scalar and the default value is 10.0
67 
68 @item @var{opts}.aggressive
69 If this value is a nonzero scalar, then @code{amd} performs aggressive
70 absorption. The default is not to perform aggressive absorption.
71 @end table
72 
73 The author of the code itself is Timothy A. Davis
74 (see @url{http://faculty.cse.tamu.edu/davis/suitesparse.html}).
75 @seealso{symamd, colamd}
76 @end deftypefn */)
77 {
78 #if defined (HAVE_AMD)
79 
80  int nargin = args.length ();
81 
83  print_usage ();
84 
85  octave_idx_type n_row, n_col;
86  const octave::suitesparse_integer *ridx, *cidx;
87  SparseMatrix sm;
89 
90  if (args(0).issparse ())
91  {
92  if (args(0).iscomplex ())
93  {
94  scm = args(0).sparse_complex_matrix_value ();
95  n_row = scm.rows ();
96  n_col = scm.cols ();
97  ridx = octave::to_suitesparse_intptr (scm.xridx ());
98  cidx = octave::to_suitesparse_intptr (scm.xcidx ());
99  }
100  else
101  {
102  sm = args(0).sparse_matrix_value ();
103  n_row = sm.rows ();
104  n_col = sm.cols ();
105  ridx = octave::to_suitesparse_intptr (sm.xridx ());
106  cidx = octave::to_suitesparse_intptr (sm.xcidx ());
107  }
108  }
109  else
110  {
111  if (args(0).iscomplex ())
112  sm = SparseMatrix (real (args(0).complex_matrix_value ()));
113  else
114  sm = SparseMatrix (args(0).matrix_value ());
115 
116  n_row = sm.rows ();
117  n_col = sm.cols ();
118  ridx = octave::to_suitesparse_intptr (sm.xridx ());
119  cidx = octave::to_suitesparse_intptr (sm.xcidx ());
120  }
121 
122  if (n_row != n_col)
123  err_square_matrix_required ("amd", "S");
124 
125  OCTAVE_LOCAL_BUFFER (double, Control, AMD_CONTROL);
126  AMD_NAME (_defaults) (Control);
127  if (nargin > 1)
128  {
129  octave_scalar_map arg1 = args(1).xscalar_map_value ("amd: OPTS argument must be a scalar structure");
130 
132 
133  tmp = arg1.getfield ("dense");
134  if (tmp.is_defined ())
135  Control[AMD_DENSE] = tmp.double_value ();
136 
137  tmp = arg1.getfield ("aggressive");
138  if (tmp.is_defined ())
139  Control[AMD_AGGRESSIVE] = tmp.double_value ();
140  }
141 
143  Matrix xinfo (AMD_INFO, 1);
144  double *Info = xinfo.fortran_vec ();
145 
146  // FIXME: how can we manage the memory allocation of amd
147  // in a cleaner manner?
148  SUITESPARSE_ASSIGN_FPTR (malloc_func, amd_malloc, malloc);
149  SUITESPARSE_ASSIGN_FPTR (free_func, amd_free, free);
150  SUITESPARSE_ASSIGN_FPTR (calloc_func, amd_calloc, calloc);
151  SUITESPARSE_ASSIGN_FPTR (realloc_func, amd_realloc, realloc);
152  SUITESPARSE_ASSIGN_FPTR (printf_func, amd_printf, printf);
153 
154  octave_idx_type result = AMD_NAME (_order) (n_col, cidx, ridx, P, Control,
155  Info);
156 
157  if (result == AMD_OUT_OF_MEMORY)
158  error ("amd: out of memory");
159  else if (result == AMD_INVALID)
160  error ("amd: matrix S is corrupted");
161 
162  Matrix Pout (1, n_col);
163  for (octave_idx_type i = 0; i < n_col; i++)
164  Pout.xelem (i) = P[i] + 1;
165 
166  if (nargout > 1)
167  return ovl (Pout, xinfo);
168  else
169  return ovl (Pout);
170 
171 #else
172 
173  octave_unused_parameter (args);
174  octave_unused_parameter (nargout);
175 
176  err_disabled_feature ("amd", "AMD");
177 
178 #endif
179 }
180 
181 /*
182 %!shared A, A2, opts
183 %! A = ones (20, 30);
184 %! A2 = ones (30, 30);
185 %!
186 %!testif HAVE_AMD
187 %! assert(amd (A2), [1:30]);
188 %! opts.dense = 25;
189 %! assert(amd (A2, opts), [1:30]);
190 %! opts.aggressive = 1;
191 %! assert(amd (A2, opts), [1:30]);
192 
193 %!error <S must be a square matrix|was unavailable or disabled> amd (A)
194 %!error amd (A2, 2)
195 %!error <matrix S is corrupted|was unavailable or disabled> amd ([])
196 */
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
const T * fortran_vec(void) const
Definition: Array.h:584
printf("%s\, nthargout(2, "system", "cmd"))
void error(const char *fmt,...)
Definition: error.cc:578
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:118
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:997
int suitesparse_integer
Definition: oct-sparse.h:168
double tmp
Definition: data.cc:6252
octave_idx_type * xridx(void)
Definition: Sparse.h:501
Definition: dMatrix.h:36
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:184
With real return the complex result
Definition: data.cc:3260
T & xelem(octave_idx_type n)
Definition: Array.h:458
octave_idx_type cols(void) const
Definition: Sparse.h:259
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).isinteger())
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:41
args.length() nargin
Definition: file-io.cc:589
for i
Definition: data.cc:5264
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Macro to define an at run time dynamically loadable builtin function.
Definition: defun-dld.h:58
octave_idx_type * xcidx(void)
Definition: Sparse.h:514
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:135
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
octave_idx_type rows(void) const
Definition: Sparse.h:258
suitesparse_integer * to_suitesparse_intptr(octave_idx_type *i)
Definition: oct-sparse.cc:48