Mercurial > octave-nkf
comparison liboctave/UMFPACK/AMD/OCTAVE/amd.cc @ 5164:57077d0ddc8e
[project @ 2005-02-25 19:55:24 by jwe]
author | jwe |
---|---|
date | Fri, 25 Feb 2005 19:55:28 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
5163:9f3299378193 | 5164:57077d0ddc8e |
---|---|
1 /* | |
2 | |
3 Copyright (C) 2004 David Bateman | |
4 | |
5 This program is free software; you can redistribute it and/or modify it | |
6 under the terms of the GNU General Public License as published by the | |
7 Free Software Foundation; either version 2, or (at your option) any | |
8 later version. | |
9 | |
10 This program is distributed in the hope that it will be useful, but WITHOUT | |
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 for more details. | |
14 | |
15 You should have received a copy of the GNU General Public License | |
16 along with this program; see the file COPYING. If not, write to the Free | |
17 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | |
19 In addition to the terms of the GPL, you are permitted to link | |
20 this program with any Open Source program, as defined by the | |
21 Open Source Initiative (www.opensource.org) | |
22 | |
23 */ | |
24 | |
25 /* | |
26 | |
27 This is the Octave interface to the UMFPACK AMD code, which bore the following | |
28 copyright | |
29 | |
30 AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, | |
31 Patrick R. Amestoy, and Iain S. Duff. See ../README for License. | |
32 email: davis@cise.ufl.edu CISE Department, Univ. of Florida. | |
33 web: http://www.cise.ufl.edu/research/sparse/amd | |
34 -------------------------------------------------------------------------- | |
35 | |
36 Acknowledgements: This work was supported by the National Science | |
37 Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270. | |
38 | |
39 */ | |
40 | |
41 #include <cstdlib> | |
42 #include <string> | |
43 | |
44 #include <octave/config.h> | |
45 #include <octave/ov.h> | |
46 #include <octave/defun-dld.h> | |
47 #include <octave/pager.h> | |
48 #include <octave/ov-re-mat.h> | |
49 | |
50 #include "ov-re-sparse.h" | |
51 #include "ov-cx-sparse.h" | |
52 | |
53 // External AMD functions in C | |
54 extern "C" { | |
55 #include "amd.h" | |
56 } | |
57 | |
58 DEFUN_DLD (amd, args, nargout, | |
59 "-*- texinfo -*-\n\ | |
60 @deftypefn {Loadable Function} {@var{p} =} amd (@var{s})\n\ | |
61 @deftypefnx {Loadable Function} {@var{Control} =} amd ()\n\ | |
62 @deftypefnx {Loadable Function} {[@var{p}, @var{info}] =} amd (@var{s})\n\ | |
63 \n\ | |
64 AMD Approximate minimum degree permutation. Returns the approximate\n\ | |
65 minimum degree permutation vector for the sparse matrix\n\ | |
66 @code{@var{c} = @var{S} + @var{S}'}. The Cholesky factorization of\n\ | |
67 @code{@var{c} (@var{p}, @var{p})}, or @code{@var{s} (@var{p}, @var{p})},\n\ | |
68 tends to be sparser than that of @var{c} or @var{s}.\n\ | |
69 @var{s} must be square. If @var{s} is full, @code{amd (@var{S})} is\n\ | |
70 equivalent to @code{amd (sparse (@var{s}))}.\n\ | |
71 \n\ | |
72 @table @asis\n\ | |
73 @item @var{Control} (1)\n\ | |
74 If S is n-by-n, then rows/columns with more than\n\ | |
75 @code{@dfn{max} (16, (@var{Control} (1)) * @dfn{sqrt} (@var{n}))} entries\n\ | |
76 in @code{@var{s} + @var{S}'} are considered @emph{dense}, and ignored during\n\ | |
77 ordering. They are placed last in the output permutation. The default is\n\ | |
78 10.0 if @var{Control} is not present.\n\ | |
79 @item @var{Control} (2)\n\ | |
80 If nonzero, then aggressive absorption is performed. This is the default if\n\ | |
81 @var{Control} is not present.\n\ | |
82 @item @var{Control} (3)\n\ | |
83 If nonzero, print statistics about the ordering.\n\ | |
84 @end table\n\ | |
85 \n\ | |
86 @table @asis\n\ | |
87 @item @var{Info} (1)\n\ | |
88 status (0: ok, -1: out of memory, -2: matrix invalid)\n\ | |
89 @item @var{Info} (2)\n\ | |
90 @code{@var{n} = size (@var{a}, 1)}\n\ | |
91 @item @var{Info} (3)\n\ | |
92 @code{nnz (A)}\n\ | |
93 @item @var{Info} (4)\n\ | |
94 The symmetry of the matrix @var{s} (0.0 means purely unsymmetric, 1.0 means\n\ | |
95 purely symmetric). Computed as: @code{@var{b} = tril (@var{s}, -1) +\n\ | |
96 triu (@var{s}, 1); @var{symmetry} = nnz (@var{b} & @var{b}')\n\ | |
97 / nnz (@var{b});}\n\ | |
98 @item @var{Info} (5)\n\ | |
99 @code{nnz (diag (@var{s}))}\n\ | |
100 @item @var{Info} (6)\n\ | |
101 @dfn{nnz} in @code{@var{s} + @var{s}'}, excluding the diagonal\n\ | |
102 (= @code{nnz (@var{b} + @var{b}')})\n\ | |
103 @item @var{Info} (7)\n\ | |
104 Number of @emph{dense} rows/columns in @code{@var{s} + @var{s}'}\n\ | |
105 @item @var{Info} (8)\n\ | |
106 The amount of memory used by AMD, in bytes\n\ | |
107 @item @var{Info} (9)\n\ | |
108 The number of memory compactions performed by AMD\n\ | |
109 @end table\n\ | |
110 \n\ | |
111 The following statistics are slight upper bounds because of the\n\ | |
112 approximate degree in AMD. The bounds are looser if @emph{dense}\n\ | |
113 rows/columns are ignored during ordering @code{(@var{Info} (7) > 0)}.\n\ | |
114 The statistics are for a subsequent factorization of the matrix\n\ | |
115 @code{@var{c} (@var{p},@var{p})}. The LU factorization statistics assume\n \ | |
116 no pivoting.\n\ | |
117 \n\ | |
118 @table @asis\n\ | |
119 @item @var{Info} (10)\n\ | |
120 The number of nonzeros in L, excluding the diagonal\n\ | |
121 @item @var{Info} (11)\n\ | |
122 The number of divide operations for LL', LDL', or LU\n\ | |
123 @item @var{Info (12)}\n\ | |
124 The number of multiply-subtract pairs for LL' or LDL'\n\ | |
125 @item @var{Info} (13)\n\ | |
126 The number of multiply-subtract pairs for LU\n\ | |
127 @item @var{Info} (14)\n\ | |
128 The max number of nonzeros in any column of L (incl. diagonal)\n\ | |
129 @item @var{Info} (15:20)\n\ | |
130 unused, reserved for future use\n\ | |
131 @end table\n\ | |
132 \n\ | |
133 An assembly tree post-ordering is performed, which is typically the same\n\ | |
134 as an elimination tree post-ordering. It is not always identical because\n\ | |
135 of the approximate degree update used, and because @emph{dense} rows/columns\n\ | |
136 do not take part in the post-order. It well-suited for a subsequent\n\ | |
137 @dfn{chol}, however. If you require a precise elimination tree\n\ | |
138 post-ordering, then do:\n\ | |
139 \n\ | |
140 @group\n\ | |
141 @var{p} = @dfn{amd} (@var{s});\n\ | |
142 % skip this if S already symmetric\n\ | |
143 @var{c} = spones (@var{s}) + spones (@var{s}');\n\ | |
144 [@var{ignore}, @var{q}] = sparsfun ('symetree', @var{c} (@var{p}, @var{p}));\n\ | |
145 @var{p} = @var{p} (@var{q});\n\ | |
146 @end group\n\ | |
147 \n\ | |
148 AMD Version 1.1 (Jan. 21, 2004), Copyright @copyright{} 2004 by\n\ | |
149 Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff.\n\ | |
150 \n\ | |
151 email: davis@@cise.ufl.edu (CISE Department, Univ. of Florida).\n\ | |
152 \n\ | |
153 web: http://www.cise.ufl.edu/research/sparse/amd\n\ | |
154 \n\ | |
155 Acknowledgements: This work was supported by the National Science\n\ | |
156 Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270.\n\ | |
157 @end deftypefn") | |
158 { | |
159 int nargin = args.length (); | |
160 octave_value_list retval; | |
161 int spumoni = 0; | |
162 | |
163 if (nargin > 2 || nargout > 2) | |
164 usage ("p = amd (A) or [p, Info] = amd (A, Control)"); | |
165 else if (nargin == 0) | |
166 { | |
167 // Get the default control parameter, and return | |
168 NDArray control (dim_vector (AMD_CONTROL, 1)); | |
169 double *control_ptr = control.fortran_vec (); | |
170 amd_defaults (control_ptr); | |
171 if (nargout == 0) | |
172 amd_control (control_ptr); | |
173 else | |
174 retval(0) = control; | |
175 } | |
176 else | |
177 { | |
178 NDArray control (dim_vector (AMD_CONTROL, 1)); | |
179 double *control_ptr = control.fortran_vec (); | |
180 amd_defaults (control_ptr); | |
181 | |
182 if (nargin > 1) | |
183 { | |
184 NDArray control_in = args(1).array_value(); | |
185 | |
186 if (error_state) | |
187 { | |
188 error ("amd: could not read control vector"); | |
189 return retval; | |
190 } | |
191 | |
192 dim_vector dv = control_in.dims (); | |
193 if (dv.length() > 2 || (dv(0) != 1 && dv(1) != 1)) | |
194 { | |
195 error ("amd: control vector isn't a vector"); | |
196 return retval; | |
197 } | |
198 | |
199 int nc = dv.numel (); | |
200 control (AMD_DENSE) = (nc > 0 ? control_in (AMD_DENSE) : | |
201 AMD_DEFAULT_DENSE); | |
202 control (AMD_AGGRESSIVE) = (nc > 1 ? control_in (AMD_AGGRESSIVE) : | |
203 AMD_DEFAULT_AGGRESSIVE); | |
204 spumoni = (nc > 2 ? (control_in (2) != 0) : 0); | |
205 } | |
206 | |
207 if (spumoni > 0) | |
208 amd_control (control_ptr); | |
209 | |
210 int *Ap, *Ai; | |
211 int n, m, nz; | |
212 | |
213 // These are here only so that the C++ destructors don't prematurally | |
214 // remove the underlying data we are interested in | |
215 SparseMatrix sm; | |
216 SparseComplexMatrix scm; | |
217 Matrix mm; | |
218 ComplexMatrix cm; | |
219 | |
220 if (args(0).class_name () != "sparse" && spumoni > 0) | |
221 octave_stdout << " input matrix A is full (sparse copy" | |
222 << " of A will be created)" << std::endl; | |
223 | |
224 if (args(0).is_complex_type ()) | |
225 { | |
226 scm = args(0).sparse_complex_matrix_value (); | |
227 Ai = scm.ridx (); | |
228 Ap = scm.cidx (); | |
229 m = scm.rows (); | |
230 n = scm.cols (); | |
231 nz = scm.nnz (); | |
232 } | |
233 else | |
234 { | |
235 sm = args(0).sparse_matrix_value (); | |
236 Ai = sm.ridx (); | |
237 Ap = sm.cidx (); | |
238 m = sm.rows (); | |
239 n = sm.cols (); | |
240 nz = sm.nnz (); | |
241 } | |
242 | |
243 if (spumoni > 0) | |
244 octave_stdout << " input matrix A is " << m << "-by-" << n | |
245 << std::endl; | |
246 | |
247 if (m != n) | |
248 { | |
249 error ("amd: A must be square"); | |
250 return retval; | |
251 } | |
252 | |
253 if (spumoni > 0) | |
254 octave_stdout << " input matrix A has " << nz << | |
255 " nonzero entries" << std::endl; | |
256 | |
257 // allocate workspace for output permutation | |
258 Array<int> P(n+1); | |
259 int *P_ptr = P.fortran_vec (); | |
260 NDArray info (dim_vector (AMD_INFO, 1)); | |
261 double *info_ptr = info.fortran_vec (); | |
262 int result; | |
263 | |
264 // order the matrix | |
265 result = amd_order (n, Ap, Ai, P_ptr, control_ptr, info_ptr); | |
266 | |
267 // print results (including return value) | |
268 if (spumoni > 0) | |
269 amd_info (info_ptr); | |
270 | |
271 // check error conditions | |
272 if (result == AMD_OUT_OF_MEMORY) | |
273 error ("amd: out of memory"); | |
274 else if (result == AMD_INVALID) | |
275 error ("amd: input matrix A is corrupted"); | |
276 else | |
277 { | |
278 // copy the outputs to Octave | |
279 | |
280 // output permutation, P | |
281 NDArray perm (dim_vector (1, n)); | |
282 for (int i = 0; i < n; i++) | |
283 perm (i) = double (P(i) + 1); // 1-based indexing for Octave | |
284 | |
285 retval (0) = perm; | |
286 | |
287 // Info | |
288 if (nargout > 1) | |
289 retval (1) = info; | |
290 } | |
291 } | |
292 return retval; | |
293 } | |
294 | |
295 /* | |
296 ;;; Local Variables: *** | |
297 ;;; mode: C++ *** | |
298 ;;; End: *** | |
299 */ |