GNU Octave  6.2.0
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-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 // This is the octave interface to amd, which bore the copyright given
27 // in the help of the functions.
28 
29 #if defined (HAVE_CONFIG_H)
30 # include "config.h"
31 #endif
32 
33 #include <cstdlib>
34 
35 #include "CSparse.h"
36 #include "Sparse.h"
37 #include "dMatrix.h"
38 #include "oct-locbuf.h"
39 #include "oct-sparse.h"
40 
41 #include "defun.h"
42 #include "error.h"
43 #include "errwarn.h"
44 #include "oct-map.h"
45 #include "ov.h"
46 #include "ovl.h"
47 #include "parse.h"
48 
49 DEFUN (amd, args, nargout,
50  doc: /* -*- texinfo -*-
51 @deftypefn {} {@var{p} =} amd (@var{S})
52 @deftypefnx {} {@var{p} =} amd (@var{S}, @var{opts})
53 
54 Return the approximate minimum degree permutation of a matrix.
55 
56 This is a permutation such that the Cholesky@tie{}factorization of
57 @code{@var{S} (@var{p}, @var{p})} tends to be sparser than the
58 Cholesky@tie{}factorization of @var{S} itself. @code{amd} is typically
59 faster than @code{symamd} but serves a similar purpose.
60 
61 The optional parameter @var{opts} is a structure that controls the behavior
62 of @code{amd}. The fields of the structure are
63 
64 @table @asis
65 @item @var{opts}.dense
66 Determines what @code{amd} considers to be a dense row or column of the
67 input matrix. Rows or columns with more than @code{max (16, (dense *
68 sqrt (@var{n})))} entries, where @var{n} is the order of the matrix @var{S},
69 are ignored by @code{amd} during the calculation of the permutation.
70 The value of dense must be a positive scalar and the default value is 10.0
71 
72 @item @var{opts}.aggressive
73 If this value is a nonzero scalar, then @code{amd} performs aggressive
74 absorption. The default is not to perform aggressive absorption.
75 @end table
76 
77 The author of the code itself is Timothy A. Davis
78 (see @url{http://faculty.cse.tamu.edu/davis/suitesparse.html}).
79 @seealso{symamd, colamd}
80 @end deftypefn */)
81 {
82 #if defined (HAVE_AMD)
83 
84  int nargin = args.length ();
85 
86  if (nargin < 1 || nargin > 2)
87  print_usage ();
88 
89  octave_idx_type n_row, n_col;
90  const octave::suitesparse_integer *ridx, *cidx;
91  SparseMatrix sm;
93 
94  if (args(0).issparse ())
95  {
96  if (args(0).iscomplex ())
97  {
98  scm = args(0).sparse_complex_matrix_value ();
99  n_row = scm.rows ();
100  n_col = scm.cols ();
101  ridx = octave::to_suitesparse_intptr (scm.xridx ());
102  cidx = octave::to_suitesparse_intptr (scm.xcidx ());
103  }
104  else
105  {
106  sm = args(0).sparse_matrix_value ();
107  n_row = sm.rows ();
108  n_col = sm.cols ();
109  ridx = octave::to_suitesparse_intptr (sm.xridx ());
110  cidx = octave::to_suitesparse_intptr (sm.xcidx ());
111  }
112  }
113  else
114  {
115  if (args(0).iscomplex ())
116  sm = SparseMatrix (real (args(0).complex_matrix_value ()));
117  else
118  sm = SparseMatrix (args(0).matrix_value ());
119 
120  n_row = sm.rows ();
121  n_col = sm.cols ();
122  ridx = octave::to_suitesparse_intptr (sm.xridx ());
123  cidx = octave::to_suitesparse_intptr (sm.xcidx ());
124  }
125 
126  if (n_row != n_col)
127  err_square_matrix_required ("amd", "S");
128 
129  OCTAVE_LOCAL_BUFFER (double, Control, AMD_CONTROL);
130  AMD_NAME (_defaults) (Control);
131  if (nargin > 1)
132  {
133  octave_scalar_map arg1 = args(1).xscalar_map_value ("amd: OPTS argument must be a scalar structure");
134 
135  octave_value tmp;
136 
137  tmp = arg1.getfield ("dense");
138  if (tmp.is_defined ())
139  Control[AMD_DENSE] = tmp.double_value ();
140 
141  tmp = arg1.getfield ("aggressive");
142  if (tmp.is_defined ())
143  Control[AMD_AGGRESSIVE] = tmp.double_value ();
144  }
145 
147  Matrix xinfo (AMD_INFO, 1);
148  double *Info = xinfo.fortran_vec ();
149 
150  // FIXME: how can we manage the memory allocation of amd
151  // in a cleaner manner?
152  SUITESPARSE_ASSIGN_FPTR (malloc_func, amd_malloc, malloc);
153  SUITESPARSE_ASSIGN_FPTR (free_func, amd_free, free);
154  SUITESPARSE_ASSIGN_FPTR (calloc_func, amd_calloc, calloc);
155  SUITESPARSE_ASSIGN_FPTR (realloc_func, amd_realloc, realloc);
156  SUITESPARSE_ASSIGN_FPTR (printf_func, amd_printf, printf);
157 
158  octave_idx_type result = AMD_NAME (_order) (n_col, cidx, ridx, P, Control,
159  Info);
160 
161  if (result == AMD_OUT_OF_MEMORY)
162  error ("amd: out of memory");
163  else if (result == AMD_INVALID)
164  error ("amd: matrix S is corrupted");
165 
166  Matrix Pout (1, n_col);
167  for (octave_idx_type i = 0; i < n_col; i++)
168  Pout.xelem (i) = P[i] + 1;
169 
170  if (nargout > 1)
171  return ovl (Pout, xinfo);
172  else
173  return ovl (Pout);
174 
175 #else
176 
177  octave_unused_parameter (args);
178  octave_unused_parameter (nargout);
179 
180  err_disabled_feature ("amd", "AMD");
181 
182 #endif
183 }
184 
185 /*
186 %!shared A, A2, opts
187 %! A = ones (20, 30);
188 %! A2 = ones (30, 30);
189 
190 %!testif HAVE_AMD
191 %! assert(amd (A2), [1:30]);
192 %! opts.dense = 25;
193 %! assert(amd (A2, opts), [1:30]);
194 %! opts.aggressive = 1;
195 %! assert(amd (A2, opts), [1:30]);
196 
197 %!testif HAVE_AMD
198 %! assert (amd ([]), zeros (1,0))
199 
200 %!error <S must be a square matrix|was unavailable or disabled> amd (A)
201 %!error amd (A2, 2)
202 */
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:469
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
Definition: dMatrix.h:42
octave_idx_type cols(void) const
Definition: Sparse.h:251
octave_idx_type * xridx(void)
Definition: Sparse.h:485
octave_idx_type rows(void) const
Definition: Sparse.h:250
octave_idx_type * xcidx(void)
Definition: Sparse.h:498
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:183
bool is_defined(void) const
Definition: ov.h:551
double double_value(bool frc_str_conv=false) const
Definition: ov.h:794
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void error(const char *fmt,...)
Definition: error.cc:968
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:122
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:53
int suitesparse_integer
Definition: oct-sparse.h:171
suitesparse_integer * to_suitesparse_intptr(octave_idx_type *i)
Definition: oct-sparse.cc:51
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
void * malloc(unsigned)
void free(void *)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211