GNU Octave  9.1.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-2024 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 
50 
51 DEFUN (amd, args, nargout,
52  doc: /* -*- texinfo -*-
53 @deftypefn {} {@var{p} =} amd (@var{S})
54 @deftypefnx {} {@var{p} =} amd (@var{S}, @var{opts})
55 
56 Return the approximate minimum degree permutation of a matrix.
57 
58 This is a permutation such that the Cholesky@tie{}factorization of
59 @code{@var{S} (@var{p}, @var{p})} tends to be sparser than the
60 Cholesky@tie{}factorization of @var{S} itself. @code{amd} is typically
61 faster than @code{symamd} but serves a similar purpose.
62 
63 The optional parameter @var{opts} is a structure that controls the behavior
64 of @code{amd}. The fields of the structure are
65 
66 @table @asis
67 @item @var{opts}.dense
68 Determines what @code{amd} considers to be a dense row or column of the
69 input matrix. Rows or columns with more than @code{max (16, (dense *
70 sqrt (@var{n})))} entries, where @var{n} is the order of the matrix @var{S},
71 are ignored by @code{amd} during the calculation of the permutation.
72 The value of dense must be a positive scalar and the default value is 10.0
73 
74 @item @var{opts}.aggressive
75 If this value is a nonzero scalar, then @code{amd} performs aggressive
76 absorption. The default is not to perform aggressive absorption.
77 @end table
78 
79 The author of the code itself is Timothy A. Davis
80 (see @url{http://faculty.cse.tamu.edu/davis/suitesparse.html}).
81 @seealso{symamd, colamd}
82 @end deftypefn */)
83 {
84 #if defined (HAVE_AMD)
85 
86  int nargin = args.length ();
87 
88  if (nargin < 1 || nargin > 2)
89  print_usage ();
90 
91  octave_idx_type n_row, n_col;
92  const suitesparse_integer *ridx, *cidx;
93  SparseMatrix sm;
95 
96  if (args(0).issparse ())
97  {
98  if (args(0).iscomplex ())
99  {
100  scm = args(0).sparse_complex_matrix_value ();
101  n_row = scm.rows ();
102  n_col = scm.cols ();
103  ridx = to_suitesparse_intptr (scm.xridx ());
104  cidx = to_suitesparse_intptr (scm.xcidx ());
105  }
106  else
107  {
108  sm = args(0).sparse_matrix_value ();
109  n_row = sm.rows ();
110  n_col = sm.cols ();
111  ridx = to_suitesparse_intptr (sm.xridx ());
112  cidx = to_suitesparse_intptr (sm.xcidx ());
113  }
114  }
115  else
116  {
117  if (args(0).iscomplex ())
118  sm = SparseMatrix (real (args(0).complex_matrix_value ()));
119  else
120  sm = SparseMatrix (args(0).matrix_value ());
121 
122  n_row = sm.rows ();
123  n_col = sm.cols ();
124  ridx = to_suitesparse_intptr (sm.xridx ());
125  cidx = to_suitesparse_intptr (sm.xcidx ());
126  }
127 
128  if (n_row != n_col)
129  err_square_matrix_required ("amd", "S");
130 
131  OCTAVE_LOCAL_BUFFER (double, Control, AMD_CONTROL);
132  AMD_NAME (_defaults) (Control);
133  if (nargin > 1)
134  {
135  octave_scalar_map arg1 = args(1).xscalar_map_value ("amd: OPTS argument must be a scalar structure");
136 
137  octave_value tmp;
138 
139  tmp = arg1.getfield ("dense");
140  if (tmp.is_defined ())
141  Control[AMD_DENSE] = tmp.double_value ();
142 
143  tmp = arg1.getfield ("aggressive");
144  if (tmp.is_defined ())
145  Control[AMD_AGGRESSIVE] = tmp.double_value ();
146  }
147 
149  Matrix xinfo (AMD_INFO, 1);
150  double *Info = xinfo.fortran_vec ();
151 
152  // FIXME: how can we manage the memory allocation of amd
153  // in a cleaner manner?
154  SUITESPARSE_ASSIGN_FPTR (malloc_func, amd_malloc, malloc);
155  SUITESPARSE_ASSIGN_FPTR (free_func, amd_free, free);
156  SUITESPARSE_ASSIGN_FPTR (calloc_func, amd_calloc, calloc);
157  SUITESPARSE_ASSIGN_FPTR (realloc_func, amd_realloc, realloc);
158  SUITESPARSE_ASSIGN_FPTR (printf_func, amd_printf, printf);
159 
160  octave_idx_type result = AMD_NAME (_order) (n_col, cidx, ridx, P, Control,
161  Info);
162 
163  if (result == AMD_OUT_OF_MEMORY)
164  error ("amd: out of memory");
165  else if (result == AMD_INVALID)
166  error ("amd: matrix S is corrupted");
167 
168  Matrix Pout (1, n_col);
169  for (octave_idx_type i = 0; i < n_col; i++)
170  Pout.xelem (i) = P[i] + 1;
171 
172  if (nargout > 1)
173  return ovl (Pout, xinfo);
174  else
175  return ovl (Pout);
176 
177 #else
178 
179  octave_unused_parameter (args);
180  octave_unused_parameter (nargout);
181 
182  err_disabled_feature ("amd", "AMD");
183 
184 #endif
185 }
186 
187 /*
188 %!shared A, A2, opts
189 %! A = ones (20, 30);
190 %! A2 = ones (30, 30);
191 
192 %!testif HAVE_AMD
193 %! assert(amd (A2), [1:30]);
194 %! opts.dense = 25;
195 %! assert(amd (A2, opts), [1:30]);
196 %! opts.aggressive = 1;
197 %! assert(amd (A2, opts), [1:30]);
198 
199 %!testif HAVE_AMD
200 %! assert (amd ([]), zeros (1,0))
201 
202 %!error <S must be a square matrix|was unavailable or disabled> amd (A)
203 %!error amd (A2, 2)
204 */
205 
206 OCTAVE_END_NAMESPACE(octave)
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
Definition: dMatrix.h:42
octave_idx_type cols() const
Definition: Sparse.h:352
octave_idx_type * xcidx()
Definition: Sparse.h:602
octave_idx_type rows() const
Definition: Sparse.h:351
octave_idx_type * xridx()
Definition: Sparse.h:589
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:183
bool is_defined() const
Definition: ov.h:592
double double_value(bool frc_str_conv=false) const
Definition: ov.h:841
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#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:988
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
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
suitesparse_integer * to_suitesparse_intptr(octave_idx_type *i)
Definition: oct-sparse.cc:51
int suitesparse_integer
Definition: oct-sparse.h:184
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:219