Mercurial > octave-nkf
comparison src/DLD-FUNCTIONS/colamd.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 | 234abf4c74dd |
comparison
equal
deleted
inserted
replaced
5163:9f3299378193 | 5164:57077d0ddc8e |
---|---|
1 /* | |
2 | |
3 Copyright (C) 2004 David Bateman | |
4 Copyright (C) 1998-2004 Andy Adler | |
5 | |
6 Octave is free software; you can redistribute it and/or modify it | |
7 under the terms of the GNU General Public License as published by the | |
8 Free Software Foundation; either version 2, or (at your option) any | |
9 later version. | |
10 | |
11 Octave is distributed in the hope that it will be useful, but WITHOUT | |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program; see the file COPYING. If not, write to the Free | |
18 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | |
20 */ | |
21 | |
22 // This is the octave interface to colamd, which bore the copyright given | |
23 // in the help of the functions. | |
24 | |
25 #ifdef HAVE_CONFIG_H | |
26 #include <config.h> | |
27 #endif | |
28 | |
29 #include <cstdlib> | |
30 | |
31 #include <string> | |
32 #include <vector> | |
33 | |
34 #include "ov.h" | |
35 #include "defun-dld.h" | |
36 #include "pager.h" | |
37 #include "ov-re-mat.h" | |
38 | |
39 #include "ov-re-sparse.h" | |
40 #include "ov-cx-sparse.h" | |
41 | |
42 // External COLAMD functions in C | |
43 extern "C" { | |
44 #include "COLAMD/colamd.h" | |
45 } | |
46 | |
47 // The symmetric column elimination tree code take from the Davis LDL code. | |
48 // Copyright given elsewhere in this file. | |
49 static | |
50 void symetree (const int *ridx, const int *cidx, int *Parent, int *P, int n) | |
51 { | |
52 OCTAVE_LOCAL_BUFFER (int, Flag, n); | |
53 OCTAVE_LOCAL_BUFFER (int, Pinv, (P ? n : 0)); | |
54 if (P) | |
55 // If P is present then compute Pinv, the inverse of P | |
56 for (int k = 0 ; k < n ; k++) | |
57 Pinv [P [k]] = k ; | |
58 | |
59 for (int k = 0 ; k < n ; k++) | |
60 { | |
61 // L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) | |
62 Parent [k] = n ; // parent of k is not yet known | |
63 Flag [k] = k ; // mark node k as visited | |
64 int kk = (P) ? (P [k]) : (k) ; // kth original, or permuted, column | |
65 int p2 = cidx [kk+1] ; | |
66 for (int p = cidx [kk] ; p < p2 ; p++) | |
67 { | |
68 // A (i,k) is nonzero (original or permuted A) | |
69 int i = (Pinv) ? (Pinv [ridx [p]]) : (ridx [p]) ; | |
70 if (i < k) | |
71 { | |
72 // follow path from i to root of etree, stop at flagged node | |
73 for ( ; Flag [i] != k ; i = Parent [i]) | |
74 { | |
75 // find parent of i if not yet determined | |
76 if (Parent [i] == n) | |
77 Parent [i] = k ; | |
78 Flag [i] = k ; // mark i as visited | |
79 } | |
80 } | |
81 } | |
82 } | |
83 } | |
84 | |
85 // The elimination tree post-ordering code below is taken from SuperLU | |
86 static inline | |
87 int make_set (int i, int *pp) | |
88 { | |
89 pp[i] = i; | |
90 return i; | |
91 } | |
92 | |
93 static inline | |
94 int link (int s, int t, int *pp) | |
95 { | |
96 pp[s] = t; | |
97 return t; | |
98 } | |
99 | |
100 static inline | |
101 int find (int i, int *pp) | |
102 { | |
103 register int p, gp; | |
104 | |
105 p = pp[i]; | |
106 gp = pp[p]; | |
107 while (gp != p) { | |
108 pp[i] = gp; | |
109 i = gp; | |
110 p = pp[i]; | |
111 gp = pp[p]; | |
112 } | |
113 return (p); | |
114 } | |
115 | |
116 static | |
117 int etdfs (int v, int *first_kid, int *next_kid, int *post, int postnum) | |
118 { | |
119 for (int w = first_kid[v]; w != -1; w = next_kid[w]) { | |
120 postnum = etdfs (w, first_kid, next_kid, post, postnum); | |
121 } | |
122 post[postnum++] = v; | |
123 | |
124 return postnum; | |
125 } | |
126 | |
127 static | |
128 void TreePostorder(int n, int *parent, int *post) | |
129 { | |
130 // Allocate storage for working arrays and results | |
131 OCTAVE_LOCAL_BUFFER (int, first_kid, n+1); | |
132 OCTAVE_LOCAL_BUFFER (int, next_kid, n+1); | |
133 | |
134 // Set up structure describing children | |
135 for (int v = 0; v <= n; first_kid[v++] = -1); | |
136 for (int v = n-1; v >= 0; v--) | |
137 { | |
138 int dad = parent[v]; | |
139 next_kid[v] = first_kid[dad]; | |
140 first_kid[dad] = v; | |
141 } | |
142 | |
143 // Depth-first search from dummy root vertex #n | |
144 etdfs (n, first_kid, next_kid, post, 0); | |
145 } | |
146 | |
147 static | |
148 void coletree (const int *ridx, const int *colbeg, int *colend, | |
149 int *parent, int nr, int nc) | |
150 { | |
151 OCTAVE_LOCAL_BUFFER (int, root, nc); | |
152 OCTAVE_LOCAL_BUFFER (int, pp, nc); | |
153 OCTAVE_LOCAL_BUFFER (int, firstcol, nr); | |
154 | |
155 // Compute firstcol[row] = first nonzero column in row | |
156 for (int row = 0; row < nr; firstcol[row++] = nc); | |
157 for (int col = 0; col < nc; col++) | |
158 for (int p = colbeg[col]; p < colend[col]; p++) | |
159 { | |
160 int row = ridx[p]; | |
161 if (firstcol[row] > col) | |
162 firstcol[row] = col; | |
163 } | |
164 | |
165 // Compute etree by Liu's algorithm for symmetric matrices, | |
166 // except use (firstcol[r],c) in place of an edge (r,c) of A. | |
167 // Thus each row clique in A'*A is replaced by a star | |
168 // centered at its first vertex, which has the same fill. | |
169 for (int col = 0; col < nc; col++) | |
170 { | |
171 int cset = make_set (col, pp); | |
172 root[cset] = col; | |
173 parent[col] = nc; | |
174 for (int p = colbeg[col]; p < colend[col]; p++) | |
175 { | |
176 int row = firstcol[ridx[p]]; | |
177 if (row >= col) | |
178 continue; | |
179 int rset = find (row, pp); | |
180 int rroot = root[rset]; | |
181 if (rroot != col) | |
182 { | |
183 parent[rroot] = col; | |
184 cset = link (cset, rset, pp); | |
185 root[cset] = col; | |
186 } | |
187 } | |
188 } | |
189 } | |
190 | |
191 DEFUN_DLD (colamd, args, nargout, | |
192 "-*- texinfo -*-\n\ | |
193 @deftypefn {Loadable Function} {@var{p} =} colamd (@var{s})\n\ | |
194 @deftypefnx {Loadable Function} {@var{p} =} colamd (@var{s}, @var{knobs})\n\ | |
195 @deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} colamd (@var{s})\n\ | |
196 @deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} colamd (@var{s}, @var{knobs})\n\ | |
197 \n\ | |
198 Column approximate minimum degree permutation. @code{@var{p} = colamd\n\ | |
199 (@var{s})} returns the column approximate minimum degree permutation\n\ | |
200 vector for the sparse matrix @var{s}. For a non-symmetric matrix @var{s},\n\ | |
201 @code{@var{s} (:,@var{p})} tends to have sparser LU factors than @var{s}.\n\ | |
202 The Cholesky factorization of @code{@var{s} (:,@var{p})' * @var{s}\n\ | |
203 (:,@var{p})} also tends to be sparser than that of @code{@var{s}' *\n\ | |
204 @var{s}}.\n\ | |
205 \n\ | |
206 @var{knobs} is an optional two-element input vector. If @var{s} is\n\ | |
207 m-by-n, then rows with more than @code{(@var{knobs} (1)) * @var{n}}\n\ | |
208 entries are ignored. Columns with more than @code{(@var{knobs} (2)) *\n\ | |
209 @var{m}} entries are removed prior to ordering, and ordered last in the\n\ | |
210 output permutation @var{p}. If the knobs parameter is not present, then\n\ | |
211 0.5 is used instead, for both @code{@var{knobs} (1)} and\n\ | |
212 @code{@var{knobs} (2)}. @code{@var{knobs} (3)} controls the printing of\n\ | |
213 statistics and error messages.\n\ | |
214 \n\ | |
215 @var{stats} is an optional 20-element output vector that provides data\n\ | |
216 about the ordering and the validity of the input matrix @var{s}. Ordering\n\ | |
217 statistics are in @code{@var{stats} (1:3)}. @code{@var{stats} (1)} and\n\ | |
218 @code{@var{stats} (2)} are the number of dense or empty rows and columns\n\ | |
219 ignored by COLAMD and @code{@var{stats} (3)} is the number of garbage\n\ | |
220 collections performed on the internal data structure used by COLAMD\n\ | |
221 (roughly of size @code{2.2 * nnz(@var{s}) + 4 * @var{m} + 7 * @var{n}}\n\ | |
222 integers).\n\ | |
223 \n\ | |
224 Octave built-in functions are intended to generate valid sparse matrices,\n\ | |
225 with no duplicate entries, with ascending row indices of the nonzeros\n\ | |
226 in each column, with a non-negative number of entries in each column (!)\n\ | |
227 and so on. If a matrix is invalid, then COLAMD may or may not be able\n\ | |
228 to continue. If there are duplicate entries (a row index appears two or\n\ | |
229 more times in the same column) or if the row indices in a column are out\n\ | |
230 of order, then COLAMD can correct these errors by ignoring the duplicate\n\ | |
231 entries and sorting each column of its internal copy of the matrix\n\ | |
232 @var{s} (the input matrix @var{s} is not repaired, however). If a matrix\n\ | |
233 is invalid in other ways then COLAMD cannot continue, an error message is\n\ | |
234 printed, and no output arguments (@var{p} or @var{stats}) are returned.\n\ | |
235 COLAMD is thus a simple way to check a sparse matrix to see if it's\n\ | |
236 valid.\n\ | |
237 \n\ | |
238 @code{@var{stats} (4:7)} provide information if COLAMD was able to\n\ | |
239 continue. The matrix is OK if @code{@var{stats} (4)} is zero, or 1 if\n\ | |
240 invalid. @code{@var{stats} (5)} is the rightmost column index that is\n\ | |
241 unsorted or contains duplicate entries, or zero if no such column exists.\n\ | |
242 @code{@var{stats} (6)} is the last seen duplicate or out-of-order row\n\ | |
243 index in the column index given by @code{@var{stats} (5)}, or zero if no\n\ | |
244 such row index exists. @code{@var{stats} (7)} is the number of duplicate\n\ | |
245 or out-of-order row indices. @code{@var{stats} (8:20)} is always zero in\n\ | |
246 the current version of COLAMD (reserved for future use).\n\ | |
247 \n\ | |
248 The ordering is followed by a column elimination tree post-ordering.\n\ | |
249 \n\ | |
250 The authors of the code itself are Stefan I. Larimore and Timothy A.\n\ | |
251 Davis (davis@@cise.ufl.edu), University of Florida. The algorithm was\n\ | |
252 developed in collaboration with John Gilbert, Xerox PARC, and Esmond\n\ | |
253 Ng, Oak Ridge National Laboratory. (see\n\ | |
254 @url{http://www.cise.ufl.edu/research/sparse/colamd})\n\ | |
255 @end deftypefn\n\ | |
256 @seealso{colperm, symamd}") | |
257 { | |
258 octave_value_list retval; | |
259 int nargin = args.length (); | |
260 int spumoni = 0; | |
261 | |
262 if (nargout < 0 || nargout > 2 || nargin < 0 || nargin > 2) | |
263 usage ("colamd: incorrect number of input and/or output arguments"); | |
264 else | |
265 { | |
266 // Get knobs | |
267 OCTAVE_LOCAL_BUFFER (double, knobs, COLAMD_KNOBS); | |
268 colamd_set_defaults (knobs); | |
269 | |
270 // Check for user-passed knobs | |
271 if (nargin == 2) | |
272 { | |
273 NDArray User_knobs = args(1).array_value (); | |
274 int nel_User_knobs = User_knobs.length (); | |
275 | |
276 if (nel_User_knobs > 0) | |
277 knobs [COLAMD_DENSE_ROW] = User_knobs (COLAMD_DENSE_ROW); | |
278 if (nel_User_knobs > 1) | |
279 knobs [COLAMD_DENSE_COL] = User_knobs (COLAMD_DENSE_COL) ; | |
280 if (nel_User_knobs > 2) | |
281 spumoni = (int) User_knobs (2); | |
282 } | |
283 | |
284 // print knob settings if spumoni is set | |
285 if (spumoni > 0) | |
286 { | |
287 octave_stdout << "colamd: dense row fraction: " | |
288 << knobs [COLAMD_DENSE_ROW] << std::endl; | |
289 octave_stdout << "colamd: dense col fraction: " | |
290 << knobs [COLAMD_DENSE_COL] << std::endl; | |
291 } | |
292 | |
293 int n_row, n_col, nnz; | |
294 int *ridx, *cidx; | |
295 SparseComplexMatrix scm; | |
296 SparseMatrix sm; | |
297 | |
298 if (args(0).class_name () == "sparse") | |
299 { | |
300 if (args(0).is_complex_type ()) | |
301 { | |
302 scm = args(0). sparse_complex_matrix_value (); | |
303 n_row = scm.rows (); | |
304 n_col = scm.cols (); | |
305 nnz = scm.nnz (); | |
306 ridx = scm.xridx (); | |
307 cidx = scm.xcidx (); | |
308 } | |
309 else | |
310 { | |
311 sm = args(0).sparse_matrix_value (); | |
312 | |
313 n_row = sm.rows (); | |
314 n_col = sm.cols (); | |
315 nnz = sm.nnz (); | |
316 ridx = sm.xridx (); | |
317 cidx = sm.xcidx (); | |
318 } | |
319 } | |
320 else | |
321 { | |
322 if (args(0).is_complex_type ()) | |
323 sm = SparseMatrix (real (args(0).complex_matrix_value ())); | |
324 else | |
325 sm = SparseMatrix (args(0).matrix_value ()); | |
326 | |
327 n_row = sm.rows (); | |
328 n_col = sm.cols (); | |
329 nnz = sm.nnz (); | |
330 ridx = sm.xridx (); | |
331 cidx = sm.xcidx (); | |
332 } | |
333 | |
334 // Allocate workspace for colamd | |
335 OCTAVE_LOCAL_BUFFER (int, p, n_col+1); | |
336 for (int i = 0; i < n_col+1; i++) | |
337 p[i] = cidx [i]; | |
338 | |
339 int Alen = colamd_recommended (nnz, n_row, n_col); | |
340 OCTAVE_LOCAL_BUFFER (int, A, Alen); | |
341 for (int i = 0; i < nnz; i++) | |
342 A[i] = ridx [i]; | |
343 | |
344 // Order the columns (destroys A) | |
345 OCTAVE_LOCAL_BUFFER (int, stats, COLAMD_STATS); | |
346 if (!colamd (n_row, n_col, Alen, A, p, knobs, stats)) | |
347 { | |
348 colamd_report (stats) ; | |
349 error ("colamd: internal error!"); | |
350 return retval; | |
351 } | |
352 | |
353 // column elimination tree post-ordering (reuse variables) | |
354 OCTAVE_LOCAL_BUFFER (int, colbeg, n_col + 1); | |
355 OCTAVE_LOCAL_BUFFER (int, colend, n_col + 1); | |
356 OCTAVE_LOCAL_BUFFER (int, etree, n_col + 1); | |
357 | |
358 for (int i = 0; i < n_col; i++) | |
359 { | |
360 colbeg[i] = cidx[p[i]]; | |
361 colend[i] = cidx[p[i]+1]; | |
362 } | |
363 | |
364 coletree (ridx, colbeg, colend, etree, n_row, n_col); | |
365 | |
366 // Calculate the tree post-ordering | |
367 TreePostorder (n_col, etree, colbeg); | |
368 | |
369 // return the permutation vector | |
370 NDArray out_perm (dim_vector (1, n_col)); | |
371 for (int i = 0; i < n_col; i++) | |
372 out_perm(i) = p [colbeg [i]] + 1; | |
373 | |
374 retval (0) = out_perm; | |
375 | |
376 // print stats if spumoni > 0 | |
377 if (spumoni > 0) | |
378 colamd_report (stats) ; | |
379 | |
380 // Return the stats vector | |
381 if (nargout == 2) | |
382 { | |
383 NDArray out_stats (dim_vector (1, COLAMD_STATS)); | |
384 for (int i = 0 ; i < COLAMD_STATS ; i++) | |
385 out_stats (i) = stats [i] ; | |
386 retval(1) = out_stats; | |
387 | |
388 // fix stats (5) and (6), for 1-based information on | |
389 // jumbled matrix. note that this correction doesn't | |
390 // occur if symamd returns FALSE | |
391 out_stats (COLAMD_INFO1) ++ ; | |
392 out_stats (COLAMD_INFO2) ++ ; | |
393 } | |
394 } | |
395 | |
396 return retval; | |
397 } | |
398 | |
399 DEFUN_DLD (symamd, args, nargout, | |
400 "-*- texinfo -*-\n\ | |
401 @deftypefn {Loadable Function} {@var{p} =} symamd (@var{s})\n\ | |
402 @deftypefnx {Loadable Function} {@var{p} =} symamd (@var{s}, @var{knobs})\n\ | |
403 @deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} symamd (@var{s})\n\ | |
404 @deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} symamd (@var{s}, @var{knobs})\n\ | |
405 \n\ | |
406 For a symmetric positive definite matrix @var{s}, returns the permutation\n\ | |
407 vector p such that @code{@var{s} (@var{p}, @var{p})} tends to have a\n\ | |
408 sparser Cholesky factor than @var{s}. Sometimes SYMAMD works well for\n\ | |
409 symmetric indefinite matrices too. The matrix @var{s} is assumed to be\n\ | |
410 symmetric; only the strictly lower triangular part is referenced. @var{s}\n\ | |
411 must be square.\n\ | |
412 \n\ | |
413 @var{knobs} is an optional input argument. If @var{s} is n-by-n, then\n\ | |
414 rows and columns with more than @code{@var{knobs} (1) * @var{n}} entries\n\ | |
415 are removed prior to ordering, and ordered last in the output permutation\n\ | |
416 @var{p}. If the @var{knobs} parameter is not present, then the default of\n\ | |
417 0.5 is used instead. @code{@var{knobs} (2)} controls the printing of\n\ | |
418 statistics and error messages.\n\ | |
419 \n\ | |
420 @var{stats} is an optional 20-element output vector that provides data\n\ | |
421 about the ordering and the validity of the input matrix @var{s}. Ordering\n\ | |
422 statistics are in @code{@var{stats} (1:3)}. @code{@var{stats} (1) =\n\ | |
423 @var{stats} (2)} is the number of dense or empty rows and columns\n\ | |
424 ignored by SYMAMD and @code{@var{stats} (3)} is the number of garbage\n\ | |
425 collections performed on the internal data structure used by SYMAMD\n\ | |
426 (roughly of size @code{8.4 * nnz (tril (@var{s}, -1)) + 9 * @var{n}}\n\ | |
427 integers).\n\ | |
428 \n\ | |
429 Octave built-in functions are intended to generate valid sparse matrices,\n\ | |
430 with no duplicate entries, with ascending row indices of the nonzeros\n\ | |
431 in each column, with a non-negative number of entries in each column (!)\n\ | |
432 and so on. If a matrix is invalid, then SYMAMD may or may not be able\n\ | |
433 to continue. If there are duplicate entries (a row index appears two or\n\ | |
434 more times in the same column) or if the row indices in a column are out\n\ | |
435 of order, then SYMAMD can correct these errors by ignoring the duplicate\n\ | |
436 entries and sorting each column of its internal copy of the matrix S (the\n\ | |
437 input matrix S is not repaired, however). If a matrix is invalid in\n\ | |
438 other ways then SYMAMD cannot continue, an error message is printed, and\n\ | |
439 no output arguments (@var{p} or @var{stats}) are returned. SYMAMD is\n\ | |
440 thus a simple way to check a sparse matrix to see if it's valid.\n\ | |
441 \n\ | |
442 @code{@var{stats} (4:7)} provide information if SYMAMD was able to\n\ | |
443 continue. The matrix is OK if @code{@var{stats} (4)} is zero, or 1\n\ | |
444 if invalid. @code{@var{stats} (5)} is the rightmost column index that\n\ | |
445 is unsorted or contains duplicate entries, or zero if no such column\n\ | |
446 exists. @code{@var{stats} (6)} is the last seen duplicate or out-of-order\n\ | |
447 row index in the column index given by @code{@var{stats} (5)}, or zero\n\ | |
448 if no such row index exists. @code{@var{stats} (7)} is the number of\n\ | |
449 duplicate or out-of-order row indices. @code{@var{stats} (8:20)} is\n\ | |
450 always zero in the current version of SYMAMD (reserved for future use).\n\ | |
451 \n\ | |
452 The ordering is followed by a column elimination tree post-ordering.\n\ | |
453 \n\ | |
454 \n\ | |
455 The authors of the code itself are Stefan I. Larimore and Timothy A.\n\ | |
456 Davis (davis@@cise.ufl.edu), University of Florida. The algorithm was\n\ | |
457 developed in collaboration with John Gilbert, Xerox PARC, and Esmond\n\ | |
458 Ng, Oak Ridge National Laboratory. (see\n\ | |
459 @url{http://www.cise.ufl.edu/research/sparse/colamd})\n\ | |
460 @end deftypefn\n\ | |
461 @seealso{colperm, colamd}") | |
462 { | |
463 octave_value_list retval; | |
464 int nargin = args.length (); | |
465 int spumoni = 0; | |
466 | |
467 if (nargout < 0 || nargout > 2 || nargin < 0 || nargin > 2) | |
468 usage ("symamd: incorrect number of input and/or output arguments"); | |
469 else | |
470 { | |
471 // Get knobs | |
472 OCTAVE_LOCAL_BUFFER (double, knobs, COLAMD_KNOBS); | |
473 colamd_set_defaults (knobs); | |
474 | |
475 // Check for user-passed knobs | |
476 if (nargin == 2) | |
477 { | |
478 NDArray User_knobs = args(1).array_value (); | |
479 int nel_User_knobs = User_knobs.length (); | |
480 | |
481 if (nel_User_knobs > 0) | |
482 knobs [COLAMD_DENSE_ROW] = User_knobs (COLAMD_DENSE_ROW); | |
483 if (nel_User_knobs > 1) | |
484 spumoni = (int) User_knobs (1); | |
485 } | |
486 | |
487 // print knob settings if spumoni is set | |
488 if (spumoni > 0) | |
489 octave_stdout << "symamd: dense row/col fraction: " | |
490 << knobs [COLAMD_DENSE_ROW] << std::endl; | |
491 | |
492 int n_row, n_col, nnz; | |
493 int *ridx, *cidx; | |
494 SparseMatrix sm; | |
495 SparseComplexMatrix scm; | |
496 | |
497 if (args(0).class_name () == "sparse") | |
498 { | |
499 if (args(0).is_complex_type ()) | |
500 { | |
501 scm = args(0).sparse_complex_matrix_value (); | |
502 n_row = scm.rows (); | |
503 n_col = scm.cols (); | |
504 nnz = scm.nnz (); | |
505 ridx = scm.xridx (); | |
506 cidx = scm.xcidx (); | |
507 } | |
508 else | |
509 { | |
510 sm = args(0).sparse_matrix_value (); | |
511 n_row = sm.rows (); | |
512 n_col = sm.cols (); | |
513 nnz = sm.nnz (); | |
514 ridx = sm.xridx (); | |
515 cidx = sm.xcidx (); | |
516 } | |
517 } | |
518 else | |
519 { | |
520 if (args(0).is_complex_type ()) | |
521 sm = SparseMatrix (real (args(0).complex_matrix_value ())); | |
522 else | |
523 sm = SparseMatrix (args(0).matrix_value ()); | |
524 | |
525 n_row = sm.rows (); | |
526 n_col = sm.cols (); | |
527 nnz = sm.nnz (); | |
528 ridx = sm.xridx (); | |
529 cidx = sm.xcidx (); | |
530 } | |
531 | |
532 if (n_row != n_col) | |
533 { | |
534 error ("symamd: matrix must be square"); | |
535 return retval; | |
536 } | |
537 | |
538 // Allocate workspace for symamd | |
539 OCTAVE_LOCAL_BUFFER (int, perm, n_col+1); | |
540 OCTAVE_LOCAL_BUFFER (int, stats, COLAMD_STATS); | |
541 if (!symamd (n_col, ridx, cidx, perm, knobs, stats, &calloc, &free)) | |
542 { | |
543 symamd_report (stats) ; | |
544 error ("symamd: internal error!") ; | |
545 return retval; | |
546 } | |
547 | |
548 // column elimination tree post-ordering | |
549 OCTAVE_LOCAL_BUFFER (int, etree, n_col + 1); | |
550 symetree (ridx, cidx, etree, perm, n_col); | |
551 | |
552 // Calculate the tree post-ordering | |
553 OCTAVE_LOCAL_BUFFER (int, post, n_col + 1); | |
554 TreePostorder (n_col, etree, post); | |
555 | |
556 // return the permutation vector | |
557 NDArray out_perm (dim_vector (1, n_col)); | |
558 for (int i = 0; i < n_col; i++) | |
559 out_perm(i) = perm [post [i]] + 1; | |
560 | |
561 retval (0) = out_perm; | |
562 | |
563 // print stats if spumoni > 0 | |
564 if (spumoni > 0) | |
565 symamd_report (stats) ; | |
566 | |
567 // Return the stats vector | |
568 if (nargout == 2) | |
569 { | |
570 NDArray out_stats (dim_vector (1, COLAMD_STATS)); | |
571 for (int i = 0 ; i < COLAMD_STATS ; i++) | |
572 out_stats (i) = stats [i] ; | |
573 retval(1) = out_stats; | |
574 | |
575 // fix stats (5) and (6), for 1-based information on | |
576 // jumbled matrix. note that this correction doesn't | |
577 // occur if symamd returns FALSE | |
578 out_stats (COLAMD_INFO1) ++ ; | |
579 out_stats (COLAMD_INFO2) ++ ; | |
580 } | |
581 } | |
582 | |
583 return retval; | |
584 } | |
585 | |
586 DEFUN_DLD (etree, args, nargout, | |
587 "-*- texinfo -*-\n\ | |
588 @deftypefn {Loadable Function} {@var{p} =} etree (@var{s})\n\ | |
589 @deftypefnx {Loadable Function} {@var{p} =} etree (@var{s}, @var{typ})\n\ | |
590 @deftypefnx {Loadable Function} {[@var{p}, @var{q}] =} etree (@var{s}, @var{typ})\n\ | |
591 \n\ | |
592 Returns the elimination tree for the matrix @var{s}. By default @var{s}\n\ | |
593 is assumed to be symmetric and the symmetric elimination tree is\n\ | |
594 returned. The argument @var{typ} controls whether a symmetric or\n\ | |
595 column elimination tree is returned. Valid values of @var{typ} are\n\ | |
596 'sym' or 'col', for symmetric or column elimination tree respectively\n\ | |
597 \n\ | |
598 Called with a second argument, @dfn{etree} also returns the postorder\n\ | |
599 permutations on the tree.\n\ | |
600 @end deftypefn") | |
601 { | |
602 octave_value_list retval; | |
603 int nargin = args.length (); | |
604 | |
605 if (nargout < 0 || nargout > 2 || nargin < 0 || nargin > 2) | |
606 usage ("etree: incorrect number of input and/or output arguments"); | |
607 else | |
608 { | |
609 int n_row, n_col, nnz; | |
610 int *ridx, *cidx; | |
611 bool is_sym = true; | |
612 SparseMatrix sm; | |
613 SparseComplexMatrix scm; | |
614 | |
615 if (args(0).class_name () == "sparse") | |
616 { | |
617 if (args(0).is_complex_type ()) | |
618 { | |
619 scm = args(0).sparse_complex_matrix_value (); | |
620 n_row = scm.rows (); | |
621 n_col = scm.cols (); | |
622 nnz = scm.nnz (); | |
623 ridx = scm.xridx (); | |
624 cidx = scm.xcidx (); | |
625 } | |
626 else | |
627 { | |
628 sm = args(0).sparse_matrix_value (); | |
629 n_row = sm.rows (); | |
630 n_col = sm.cols (); | |
631 nnz = sm.nnz (); | |
632 ridx = sm.xridx (); | |
633 cidx = sm.xcidx (); | |
634 } | |
635 | |
636 } | |
637 else | |
638 { | |
639 error ("etree: must be called with a sparse matrix"); | |
640 return retval; | |
641 } | |
642 | |
643 if (nargin == 2) | |
644 if (args(1).is_string ()) | |
645 { | |
646 std::string str = args(1).string_value (); | |
647 if (str.find("C") == 0 || str.find("c") == 0) | |
648 is_sym = false; | |
649 } | |
650 else | |
651 { | |
652 error ("etree: second argument must be a string"); | |
653 return retval; | |
654 } | |
655 | |
656 // column elimination tree post-ordering (reuse variables) | |
657 OCTAVE_LOCAL_BUFFER (int, etree, n_col + 1); | |
658 | |
659 | |
660 if (is_sym) | |
661 { | |
662 if (n_row != n_col) | |
663 { | |
664 error ("etree: matrix is marked as symmetric, but not square"); | |
665 return retval; | |
666 } | |
667 symetree (ridx, cidx, etree, NULL, n_col); | |
668 } | |
669 else | |
670 { | |
671 OCTAVE_LOCAL_BUFFER (int, colbeg, n_col); | |
672 OCTAVE_LOCAL_BUFFER (int, colend, n_col); | |
673 | |
674 for (int i = 0; i < n_col; i++) | |
675 { | |
676 colbeg[i] = cidx[i]; | |
677 colend[i] = cidx[i+1]; | |
678 } | |
679 | |
680 coletree (ridx, colbeg, colend, etree, n_row, n_col); | |
681 } | |
682 | |
683 NDArray tree (dim_vector (1, n_col)); | |
684 for (int i = 0; i < n_col; i++) | |
685 // We flag a root with n_col while Matlab does it with zero | |
686 // Convert for matlab compatiable output | |
687 if (etree[i] == n_col) | |
688 tree (i) = 0; | |
689 else | |
690 tree (i) = etree[i] + 1; | |
691 | |
692 retval (0) = tree; | |
693 | |
694 if (nargout == 2) | |
695 { | |
696 // Calculate the tree post-ordering | |
697 OCTAVE_LOCAL_BUFFER (int, post, n_col + 1); | |
698 TreePostorder (n_col, etree, post); | |
699 | |
700 NDArray postorder (dim_vector (1, n_col)); | |
701 for (int i = 0; i < n_col; i++) | |
702 postorder (i) = post[i] + 1; | |
703 | |
704 retval (1) = postorder; | |
705 } | |
706 } | |
707 | |
708 return retval; | |
709 } | |
710 | |
711 DEFUN_DLD (symbfact, args, nargout, | |
712 "-*- texinfo -*-\n\ | |
713 @deftypefn {Loadable Function} {[@var{count}, @var{h}, @var{parent}, @var{post}, @var{r}]} = symbfact (@var{s}, @var{typ})\n\ | |
714 \n\ | |
715 Performs a symbolic factorization analysis on the sparse matrix @var{s}.\n\ | |
716 @end deftypefn") | |
717 { | |
718 error ("symbfact: not implemented yet"); | |
719 return octave_value (); | |
720 } | |
721 | |
722 /* | |
723 ;;; Local Variables: *** | |
724 ;;; mode: C++ *** | |
725 ;;; End: *** | |
726 */ |