GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
amd.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2008-2025 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
51DEFUN (amd, args, nargout,
52 doc: /* -*- texinfo -*-
53@deftypefn {} {@var{p} =} amd (@var{S})
54@deftypefnx {} {@var{p} =} amd (@var{S}, @var{opts})
55
56Return the approximate minimum degree permutation of a matrix.
57
58This is a permutation such that the Cholesky@tie{}factorization of
59@code{@var{S} (@var{p}, @var{p})} tends to be sparser than the
60Cholesky@tie{}factorization of @var{S} itself. @code{amd} is typically
61faster than @code{symamd} but serves a similar purpose.
62
63The optional parameter @var{opts} is a structure that controls the behavior
64of @code{amd}. The fields of the structure are
65
66@table @asis
67@item @var{opts}.dense
68Determines what @code{amd} considers to be a dense row or column of the
69input matrix. Rows or columns with more than @code{max (16, (dense *
70sqrt (@var{n})))} entries, where @var{n} is the order of the matrix @var{S},
71are ignored by @code{amd} during the calculation of the permutation.
72The value of dense must be a positive scalar and the default value is 10.0
73
74@item @var{opts}.aggressive
75If this value is a nonzero scalar, then @code{amd} performs aggressive
76absorption. The default is not to perform aggressive absorption.
77@end table
78
79The 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.rwdata ();
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
206OCTAVE_END_NAMESPACE(octave)
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition Array.h:525
T * rwdata()
Size of the specified dimension.
octave_idx_type cols() const
Definition Sparse.h:349
octave_idx_type rows() const
Definition Sparse.h:348
octave_idx_type * xcidx()
Definition Sparse.h:599
octave_idx_type * xridx()
Definition Sparse.h:586
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:847
ColumnVector real(const ComplexColumnVector &a)
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
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:1003
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:217