GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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