changelog shortlog tags changeset files revisions annotate raw

src/DLD-FUNCTIONS/ccolamd.cc

changeset 10289: 4b124317dc38
parent:d0ce5e973937
author: John W. Eaton <jwe@octave.org>
date: Tue Feb 09 20:58:55 2010 -0500 (65 minutes ago)
permissions: -rw-r--r--
description: base_properties::set_children: account for hidden children
1/*
2
3Copyright (C) 2005, 2006, 2007, 2008 David Bateman
4
5This file is part of Octave.
6
7Octave is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12Octave is distributed in the hope that it will be useful, but WITHOUT
13ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with Octave; see the file COPYING. If not, see
19<http://www.gnu.org/licenses/>.
20
21*/
22
23// This is the octave interface to ccolamd, which bore the copyright given
24// in the help of the functions.
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29
30#include <cstdlib>
31
32#include <string>
33#include <vector>
34
35#include "ov.h"
36#include "defun-dld.h"
37#include "pager.h"
38#include "ov-re-mat.h"
39
40#include "ov-re-sparse.h"
41#include "ov-cx-sparse.h"
42
43#include "oct-sparse.h"
44#include "oct-locbuf.h"
45
46#ifdef IDX_TYPE_LONG
47#define CCOLAMD_NAME(name) ccolamd_l ## name
48#define CSYMAMD_NAME(name) csymamd_l ## name
49#else
50#define CCOLAMD_NAME(name) ccolamd ## name
51#define CSYMAMD_NAME(name) csymamd ## name
52#endif
53
54DEFUN_DLD (ccolamd, args, nargout,
55 "-*- texinfo -*-\n\
56@deftypefn {Loadable Function} {@var{p} =} ccolamd (@var{s})\n\
57@deftypefnx {Loadable Function} {@var{p} =} ccolamd (@var{s}, @var{knobs})\n\
58@deftypefnx {Loadable Function} {@var{p} =} ccolamd (@var{s}, @var{knobs}, @var{cmember})\n\
59@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} ccolamd (@dots{})\n\
60\n\
61Constrained column approximate minimum degree permutation. @code{@var{p} =\n\
62ccolamd (@var{s})} returns the column approximate minimum degree permutation\n\
63vector for the sparse matrix @var{s}. For a non-symmetric matrix @var{s},\n\
64@code{@var{s} (:, @var{p})} tends to have sparser LU factors than @var{s}.\n\
65@code{chol (@var{s} (:, @var{p})' * @var{s} (:, @var{p}))} also tends to be\n\
66sparser than @code{chol (@var{s}' * @var{s})}. @code{@var{p} = ccolamd\n\
67(@var{s}, 1)} optimizes the ordering for @code{lu (@var{s} (:, @var{p}))}.\n\
68The ordering is followed by a column elimination tree post-ordering.\n\
69\n\
70@var{knobs} is an optional one- to five-element input vector, with a default\n\
71value of @code{[0 10 10 1 0]} if not present or empty. Entries not present\n\
72are set to their defaults.\n\
73\n\
74@table @code\n\
75@item @var{knobs}(1)\n\
76if nonzero, the ordering is optimized for @code{lu (S (:, p))}. It will be a\n\
77poor ordering for @code{chol (@var{s} (:, @var{p})' * @var{s} (:,\n\
78@var{p}))}. This is the most important knob for ccolamd.\n\
79\n\
80@item @var{knob}(2)\n\
81if @var{s} is m-by-n, rows with more than @code{max (16, @var{knobs} (2) *\n\
82sqrt (n))} entries are ignored.\n\
83\n\
84@item @var{knob}(3)\n\
85columns with more than @code{max (16, @var{knobs} (3) * sqrt (min (@var{m},\n\
86@var{n})))} entries are ignored and ordered last in the output permutation\n\
87(subject to the cmember constraints).\n\
88\n\
89@item @var{knob}(4)\n\
90if nonzero, aggressive absorption is performed.\n\
91\n\
92@item @var{knob}(5)\n\
93if nonzero, statistics and knobs are printed.\n\
94\n\
95@end table\n\
96\n\
97@var{cmember} is an optional vector of length n. It defines the constraints\n\
98on the column ordering. If @code{@var{cmember} (j) = @var{c}}, then column\n\
99@var{j} is in constraint set @var{c} (@var{c} must be in the range 1 to\n\
100@var{n}). In the output permutation @var{p}, all columns in set 1 appear\n\
101first, followed by all columns in set 2, and so on. @code{@var{cmember} =\n\
102ones(1,n)} if not present or empty. @code{ccolamd (@var{s}, [], 1 :\n\
103@var{n})} returns @code{1 : @var{n}}\n\
104\n\
105@code{@var{p} = ccolamd (@var{s})} is about the same as @code{@var{p} =\n\
106colamd (@var{s})}. @var{knobs} and its default values differ. @code{colamd}\n\
107always does aggressive absorption, and it finds an ordering suitable for\n\
108both @code{lu (@var{s} (:, @var{p}))} and @code{chol (@var{S} (:, @var{p})'\n\
109* @var{s} (:, @var{p}))}; it cannot optimize its ordering for\n\
110@code{lu (@var{s} (:, @var{p}))} to the extent that\n\
111@code{ccolamd (@var{s}, 1)} can.\n\
112\n\
113@var{stats} is an optional 20-element output vector that provides data\n\
114about the ordering and the validity of the input matrix @var{s}. Ordering\n\
115statistics are in @code{@var{stats} (1 : 3)}. @code{@var{stats} (1)} and\n\
116@code{@var{stats} (2)} are the number of dense or empty rows and columns\n\
117ignored by CCOLAMD and @code{@var{stats} (3)} is the number of garbage\n\
118collections performed on the internal data structure used by CCOLAMD\n\
119(roughly of size @code{2.2 * nnz (@var{s}) + 4 * @var{m} + 7 * @var{n}}\n\
120integers).\n\
121\n\
122@code{@var{stats} (4 : 7)} provide information if CCOLAMD was able to\n\
123continue. The matrix is OK if @code{@var{stats} (4)} is zero, or 1 if\n\
124invalid. @code{@var{stats} (5)} is the rightmost column index that is\n\
125unsorted or contains duplicate entries, or zero if no such column exists.\n\
126@code{@var{stats} (6)} is the last seen duplicate or out-of-order row\n\
127index in the column index given by @code{@var{stats} (5)}, or zero if no\n\
128such row index exists. @code{@var{stats} (7)} is the number of duplicate\n\
129or out-of-order row indices. @code{@var{stats} (8 : 20)} is always zero in\n\
130the current version of CCOLAMD (reserved for future use).\n\
131\n\
132The authors of the code itself are S. Larimore, T. Davis (Uni of Florida)\n\
133and S. Rajamanickam in collaboration with J. Bilbert and E. Ng. Supported\n\
134by the National Science Foundation (DMS-9504974, DMS-9803599, CCR-0203270),\n\
135and a grant from Sandia National Lab. See\n\
136@url{http://www.cise.ufl.edu/research/sparse} for ccolamd, csymamd, amd,\n\
137colamd, symamd, and other related orderings.\n\
138@seealso{colamd, csymamd}\n\
139@end deftypefn")
140{
141 octave_value_list retval;
142
143#ifdef HAVE_CCOLAMD
144
145 int nargin = args.length ();
146 int spumoni = 0;
147
148 if (nargout > 2 || nargin < 1 || nargin > 3)
149 usage ("ccolamd: incorrect number of input and/or output arguments");
150 else
151 {
152 // Get knobs
153 OCTAVE_LOCAL_BUFFER (double, knobs, CCOLAMD_KNOBS);
154 CCOLAMD_NAME (_set_defaults) (knobs);
155
156 // Check for user-passed knobs
157 if (nargin > 1)
158 {
159 NDArray User_knobs = args(1).array_value ();
160 int nel_User_knobs = User_knobs.length ();
161
162 if (nel_User_knobs > 0)
163 knobs [CCOLAMD_LU] = (User_knobs (0) != 0);
164 if (nel_User_knobs > 1)
165 knobs [CCOLAMD_DENSE_ROW] = User_knobs (1);
166 if (nel_User_knobs > 2)
167 knobs [CCOLAMD_DENSE_COL] = User_knobs (2);
168 if (nel_User_knobs > 3)
169 knobs [CCOLAMD_AGGRESSIVE] = (User_knobs (3) != 0);
170 if (nel_User_knobs > 4)
171 spumoni = (User_knobs (4) != 0);
172
173 // print knob settings if spumoni is set
174 if (spumoni)
175 {
176 octave_stdout << "\nccolamd version " << CCOLAMD_MAIN_VERSION << "."
177 << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE
178 << ":\nknobs(1): " << User_knobs (0) << ", order for ";
179 if ( knobs [CCOLAMD_LU] != 0)
180 octave_stdout << "lu(A)\n";
181 else
182 octave_stdout << "chol(A'*A)\n";
183
184 if (knobs [CCOLAMD_DENSE_ROW] >= 0)
185 octave_stdout << "knobs(2): " << User_knobs (1)
186 << ", rows with > max(16,"
187 << knobs [CCOLAMD_DENSE_ROW] << "*sqrt(size(A,2)))"
188 << " entries removed\n";
189 else
190 octave_stdout << "knobs(2): " << User_knobs (1)
191 << ", no dense rows removed\n";
192
193 if (knobs [CCOLAMD_DENSE_COL] >= 0)
194 octave_stdout << "knobs(3): " << User_knobs (2)
195 << ", cols with > max(16,"
196 << knobs [CCOLAMD_DENSE_COL] << "*sqrt(size(A)))"
197 << " entries removed\n";
198 else
199 octave_stdout << "knobs(3): " << User_knobs (2)
200 << ", no dense columns removed\n";
201
202 if (knobs [CCOLAMD_AGGRESSIVE] != 0)
203 octave_stdout << "knobs(4): " << User_knobs(3)
204 << ", aggressive absorption: yes";
205 else
206 octave_stdout << "knobs(4): " << User_knobs(3)
207 << ", aggressive absorption: no";
208
209 octave_stdout << "knobs(5): " << User_knobs (4)
210 << ", statistics and knobs printed\n";
211 }
212 }
213
214 octave_idx_type n_row, n_col, nnz;
215 octave_idx_type *ridx, *cidx;
216 SparseComplexMatrix scm;
217 SparseMatrix sm;
218
219 if (args(0).is_sparse_type ())
220 {
221 if (args(0).is_complex_type ())
222 {
223 scm = args(0). sparse_complex_matrix_value ();
224 n_row = scm.rows ();
225 n_col = scm.cols ();
226 nnz = scm.nzmax ();
227 ridx = scm.xridx ();
228 cidx = scm.xcidx ();
229 }
230 else
231 {
232 sm = args(0).sparse_matrix_value ();
233
234 n_row = sm.rows ();
235 n_col = sm.cols ();
236 nnz = sm.nzmax ();
237 ridx = sm.xridx ();
238 cidx = sm.xcidx ();
239 }
240 }
241 else
242 {
243 if (args(0).is_complex_type ())
244 sm = SparseMatrix (real (args(0).complex_matrix_value ()));
245 else
246 sm = SparseMatrix (args(0).matrix_value ());
247
248 n_row = sm.rows ();
249 n_col = sm.cols ();
250 nnz = sm.nzmax ();
251 ridx = sm.xridx ();
252 cidx = sm.xcidx ();
253 }
254
255 // Allocate workspace for ccolamd
256 OCTAVE_LOCAL_BUFFER (octave_idx_type, p, n_col+1);
257 for (octave_idx_type i = 0; i < n_col+1; i++)
258 p[i] = cidx [i];
259
260 octave_idx_type Alen = CCOLAMD_NAME (_recommended) (nnz, n_row, n_col);
261 OCTAVE_LOCAL_BUFFER (octave_idx_type, A, Alen);
262 for (octave_idx_type i = 0; i < nnz; i++)
263 A[i] = ridx [i];
264
265 OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, CCOLAMD_STATS);
266
267 if (nargin > 2)
268 {
269 NDArray in_cmember = args(2).array_value();
270 octave_idx_type cslen = in_cmember.length();
271 OCTAVE_LOCAL_BUFFER (octave_idx_type, cmember, cslen);
272 for (octave_idx_type i = 0; i < cslen; i++)
273 // convert cmember from 1-based to 0-based
274 cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1);
275
276 if (cslen != n_col)
277 error ("ccolamd: cmember must be of length equal to #cols of A");
278 else
279 // Order the columns (destroys A)
280 if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, cmember))
281 {
282 CCOLAMD_NAME (_report) (stats) ;
283 error ("ccolamd: internal error!");
284 return retval;
285 }
286 }
287 else
288 {
289 // Order the columns (destroys A)
290 if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, 0))
291 {
292 CCOLAMD_NAME (_report) (stats) ;
293 error ("ccolamd: internal error!");
294 return retval;
295 }
296 }
297
298 // return the permutation vector
299 NDArray out_perm (dim_vector (1, n_col));
300 for (octave_idx_type i = 0; i < n_col; i++)
301 out_perm(i) = p [i] + 1;
302
303 retval (0) = out_perm;
304
305 // print stats if spumoni > 0
306 if (spumoni > 0)
307 CCOLAMD_NAME (_report) (stats) ;
308
309 // Return the stats vector
310 if (nargout == 2)
311 {
312 NDArray out_stats (dim_vector (1, CCOLAMD_STATS));
313 for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++)
314 out_stats (i) = stats [i] ;
315 retval(1) = out_stats;
316
317 // fix stats (5) and (6), for 1-based information on
318 // jumbled matrix. note that this correction doesn't
319 // occur if symamd returns FALSE
320 out_stats (CCOLAMD_INFO1) ++ ;
321 out_stats (CCOLAMD_INFO2) ++ ;
322 }
323 }
324
325#else
326
327 error ("ccolamd: not available in this version of Octave");
328
329#endif
330
331 return retval;
332}
333
334DEFUN_DLD (csymamd, args, nargout,
335 "-*- texinfo -*-\n\
336@deftypefn {Loadable Function} {@var{p} =} csymamd (@var{s})\n\
337@deftypefnx {Loadable Function} {@var{p} =} csymamd (@var{s}, @var{knobs})\n\
338@deftypefnx {Loadable Function} {@var{p} =} csymamd (@var{s}, @var{knobs}, @var{cmember})\n\
339@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} csymamd (@dots{})\n\
340\n\
341For a symmetric positive definite matrix @var{s}, returns the permutation\n\
342vector @var{p} such that @code{@var{s}(@var{p},@var{p})} tends to have a\n\
343sparser Cholesky factor than @var{s}. Sometimes @code{csymamd} works well\n\
344for symmetric indefinite matrices too. The matrix @var{s} is assumed to\n\
345be symmetric; only the strictly lower triangular part is referenced.\n\
346@var{s} must be square. The ordering is followed by an elimination tree\n\
347post-ordering.\n\
348\n\
349@var{knobs} is an optional one- to three-element input vector, with a\n\
350default value of @code{[10 1 0]} if present or empty. Entries not\n\
351present are set to their defaults.\n\
352\n\
353@table @code\n\
354@item @var{knobs}(1)\n\
355If @var{s} is n-by-n, then rows and columns with more than\n\
356@code{max(16,@var{knobs}(1)*sqrt(n))} entries are ignored, and ordered\n\
357last in the output permutation (subject to the cmember constraints).\n\
358\n\
359@item @var{knobs}(2)\n\
360If nonzero, aggressive absorption is performed.\n\
361\n\
362@item @var{knobs}(3)\n\
363If nonzero, statistics and knobs are printed.\n\
364\n\
365@end table\n\
366\n\
367@var{cmember} is an optional vector of length n. It defines the constraints\n\
368on the ordering. If @code{@var{cmember}(j) = @var{s}}, then row/column j is\n\
369in constraint set @var{c} (@var{c} must be in the range 1 to n). In the\n\
370output permutation @var{p}, rows/columns in set 1 appear first, followed\n\
371by all rows/columns in set 2, and so on. @code{@var{cmember} = ones(1,n)}\n\
372if not present or empty. @code{csymamd(@var{s},[],1:n)} returns @code{1:n}.\n\
373\n\
374@code{@var{p} = csymamd(@var{s})} is about the same as @code{@var{p} =\n\
375symamd(@var{s})}. @var{knobs} and its default values differ.\n\
376\n\
377@code{@var{stats} (4:7)} provide information if CCOLAMD was able to\n\
378continue. The matrix is OK if @code{@var{stats} (4)} is zero, or 1 if\n\
379invalid. @code{@var{stats} (5)} is the rightmost column index that is\n\
380unsorted or contains duplicate entries, or zero if no such column exists.\n\
381@code{@var{stats} (6)} is the last seen duplicate or out-of-order row\n\
382index in the column index given by @code{@var{stats} (5)}, or zero if no\n\
383such row index exists. @code{@var{stats} (7)} is the number of duplicate\n\
384or out-of-order row indices. @code{@var{stats} (8:20)} is always zero in\n\
385the current version of CCOLAMD (reserved for future use).\n\
386\n\
387The authors of the code itself are S. Larimore, T. Davis (Uni of Florida)\n\
388and S. Rajamanickam in collaboration with J. Bilbert and E. Ng. Supported\n\
389by the National Science Foundation (DMS-9504974, DMS-9803599, CCR-0203270),\n\
390and a grant from Sandia National Lab. See\n\
391@url{http://www.cise.ufl.edu/research/sparse} for ccolamd, csymamd, amd,\n\
392colamd, symamd, and other related orderings.\n\
393@seealso{symamd, ccolamd}\n\
394@end deftypefn")
395{
396 octave_value_list retval;
397
398#if HAVE_CCOLAMD
399
400 int nargin = args.length ();
401 int spumoni = 0;
402
403 if (nargout > 2 || nargin < 1 || nargin > 3)
404 usage ("ccolamd: incorrect number of input and/or output arguments");
405 else
406 {
407 // Get knobs
408 OCTAVE_LOCAL_BUFFER (double, knobs, CCOLAMD_KNOBS);
409 CCOLAMD_NAME (_set_defaults) (knobs);
410
411 // Check for user-passed knobs
412 if (nargin > 1)
413 {
414 NDArray User_knobs = args(1).array_value ();
415 int nel_User_knobs = User_knobs.length ();
416
417 if (nel_User_knobs > 0)
418 knobs [CCOLAMD_DENSE_ROW] = User_knobs (0);
419 if (nel_User_knobs > 0)
420 knobs [CCOLAMD_AGGRESSIVE] = User_knobs (1);
421 if (nel_User_knobs > 1)
422 spumoni = static_cast<int> (User_knobs (2));
423
424 // print knob settings if spumoni is set
425 if (spumoni)
426 {
427 octave_stdout << "\ncsymamd version " << CCOLAMD_MAIN_VERSION << "."
428 << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE << "\n";
429
430 if (knobs [CCOLAMD_DENSE_ROW] >= 0)
431 octave_stdout << "knobs(1): " << User_knobs (0)
432 << ", rows/cols with > max(16,"
433 << knobs [CCOLAMD_DENSE_ROW] << "*sqrt(size(A,2)))"
434 << " entries removed\n";
435 else
436 octave_stdout << "knobs(1): " << User_knobs (0)
437 << ", no dense rows/cols removed\n";
438
439 if (knobs [CCOLAMD_AGGRESSIVE] != 0)
440 octave_stdout << "knobs(2): " << User_knobs(1)
441 << ", aggressive absorption: yes";
442 else
443 octave_stdout << "knobs(2): " << User_knobs(1)
444 << ", aggressive absorption: no";
445
446
447 octave_stdout << "knobs(3): " << User_knobs (2)
448 << ", statistics and knobs printed\n";
449 }
450 }
451
452 octave_idx_type n_row, n_col, nnz;
453 octave_idx_type *ridx, *cidx;
454 SparseMatrix sm;
455 SparseComplexMatrix scm;
456
457 if (args(0).is_sparse_type ())
458 {
459 if (args(0).is_complex_type ())
460 {
461 scm = args(0).sparse_complex_matrix_value ();
462 n_row = scm.rows ();
463 n_col = scm.cols ();
464 nnz = scm.nzmax ();
465 ridx = scm.xridx ();
466 cidx = scm.xcidx ();
467 }
468 else
469 {
470 sm = args(0).sparse_matrix_value ();
471 n_row = sm.rows ();
472 n_col = sm.cols ();
473 nnz = sm.nzmax ();
474 ridx = sm.xridx ();
475 cidx = sm.xcidx ();
476 }
477 }
478 else
479 {
480 if (args(0).is_complex_type ())
481 sm = SparseMatrix (real (args(0).complex_matrix_value ()));
482 else
483 sm = SparseMatrix (args(0).matrix_value ());
484
485 n_row = sm.rows ();
486 n_col = sm.cols ();
487 nnz = sm.nzmax ();
488 ridx = sm.xridx ();
489 cidx = sm.xcidx ();
490 }
491
492 if (n_row != n_col)
493 {
494 error ("symamd: matrix must be square");
495 return retval;
496 }
497
498 // Allocate workspace for symamd
499 OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, n_col+1);
500 OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, CCOLAMD_STATS);
501
502 if (nargin > 2)
503 {
504 NDArray in_cmember = args(2).array_value();
505 octave_idx_type cslen = in_cmember.length();
506 OCTAVE_LOCAL_BUFFER (octave_idx_type, cmember, cslen);
507 for (octave_idx_type i = 0; i < cslen; i++)
508 // convert cmember from 1-based to 0-based
509 cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1);
510
511 if (cslen != n_col)
512 error ("ccolamd: cmember must be of length equal to #cols of A");
513 else
514 if (!CSYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats,
515 &calloc, &free, cmember, -1))
516 {
517 CSYMAMD_NAME (_report) (stats) ;
518 error ("symamd: internal error!") ;
519 return retval;
520 }
521 }
522 else
523 {
524 if (!CSYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats,
525 &calloc, &free, 0, -1))
526 {
527 CSYMAMD_NAME (_report) (stats) ;
528 error ("symamd: internal error!") ;
529 return retval;
530 }
531 }
532
533 // return the permutation vector
534 NDArray out_perm (dim_vector (1, n_col));
535 for (octave_idx_type i = 0; i < n_col; i++)
536 out_perm(i) = perm [i] + 1;
537
538 retval (0) = out_perm;
539
540 // Return the stats vector
541 if (nargout == 2)
542 {
543 NDArray out_stats (dim_vector (1, CCOLAMD_STATS));
544 for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++)
545 out_stats (i) = stats [i] ;
546 retval(1) = out_stats;
547
548 // fix stats (5) and (6), for 1-based information on
549 // jumbled matrix. note that this correction doesn't
550 // occur if symamd returns FALSE
551 out_stats (CCOLAMD_INFO1) ++ ;
552 out_stats (CCOLAMD_INFO2) ++ ;
553 }
554
555 // print stats if spumoni > 0
556 if (spumoni > 0)
557 CSYMAMD_NAME (_report) (stats) ;
558
559 // Return the stats vector
560 if (nargout == 2)
561 {
562 NDArray out_stats (dim_vector (1, CCOLAMD_STATS));
563 for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++)
564 out_stats (i) = stats [i] ;
565 retval(1) = out_stats;
566
567 // fix stats (5) and (6), for 1-based information on
568 // jumbled matrix. note that this correction doesn't
569 // occur if symamd returns FALSE
570 out_stats (CCOLAMD_INFO1) ++ ;
571 out_stats (CCOLAMD_INFO2) ++ ;
572 }
573 }
574
575#else
576
577 error ("csymamd: not available in this version of Octave");
578
579#endif
580
581 return retval;
582}