00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 #include <config.h>
00028 #endif
00029
00030 #include <cstdlib>
00031
00032 #include <string>
00033 #include <vector>
00034
00035 #include "ov.h"
00036 #include "defun-dld.h"
00037 #include "pager.h"
00038 #include "ov-re-mat.h"
00039
00040 #include "ov-re-sparse.h"
00041 #include "ov-cx-sparse.h"
00042
00043 #include "oct-sparse.h"
00044 #include "oct-locbuf.h"
00045
00046 #ifdef IDX_TYPE_LONG
00047 #define CCOLAMD_NAME(name) ccolamd_l ## name
00048 #define CSYMAMD_NAME(name) csymamd_l ## name
00049 #else
00050 #define CCOLAMD_NAME(name) ccolamd ## name
00051 #define CSYMAMD_NAME(name) csymamd ## name
00052 #endif
00053
00054 DEFUN_DLD (ccolamd, args, nargout,
00055 "-*- texinfo -*-\n\
00056 @deftypefn {Loadable Function} {@var{p} =} ccolamd (@var{S})\n\
00057 @deftypefnx {Loadable Function} {@var{p} =} ccolamd (@var{S}, @var{knobs})\n\
00058 @deftypefnx {Loadable Function} {@var{p} =} ccolamd (@var{S}, @var{knobs}, @var{cmember})\n\
00059 @deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} ccolamd (@dots{})\n\
00060 \n\
00061 Constrained column approximate minimum degree permutation.\n\
00062 @code{@var{p} = ccolamd (@var{S})} returns the column approximate minimum\n\
00063 degree permutation vector for the sparse matrix @var{S}. For a non-symmetric\n\
00064 matrix\n\
00065 @var{S},\n\
00066 @code{@var{S}(:, @var{p})} tends to have sparser LU@tie{}factors than\n\
00067 @var{S}. @code{chol (@var{S}(:, @var{p})' * @var{S}(:, @var{p}))} also\n\
00068 tends to be sparser than @code{chol (@var{S}' * @var{S})}. @code{@var{p} =\n\
00069 ccolamd (@var{S}, 1)} optimizes the ordering for @code{lu (@var{S}(:,\n\
00070 @var{p}))}. The ordering is followed by a column elimination tree\n\
00071 post-ordering.\n\
00072 \n\
00073 @var{knobs} is an optional 1-element to 5-element input vector, with a\n\
00074 default value of @code{[0 10 10 1 0]} if not present or empty. Entries not\n\
00075 present are set to their defaults.\n\
00076 \n\
00077 @table @code\n\
00078 @item @var{knobs}(1)\n\
00079 if nonzero, the ordering is optimized for @code{lu (S(:, p))}. It will be a\n\
00080 poor ordering for @code{chol (@var{S}(:, @var{p})' * @var{S}(:,\n\
00081 @var{p}))}. This is the most important knob for ccolamd.\n\
00082 \n\
00083 @item @var{knobs}(2)\n\
00084 if @var{S} is m-by-n, rows with more than @code{max (16, @var{knobs}(2) *\n\
00085 sqrt (n))} entries are ignored.\n\
00086 \n\
00087 @item @var{knobs}(3)\n\
00088 columns with more than @code{max (16, @var{knobs}(3) * sqrt (min (@var{m},\n\
00089 @var{n})))} entries are ignored and ordered last in the output permutation\n\
00090 (subject to the cmember constraints).\n\
00091 \n\
00092 @item @var{knobs}(4)\n\
00093 if nonzero, aggressive absorption is performed.\n\
00094 \n\
00095 @item @var{knobs}(5)\n\
00096 if nonzero, statistics and knobs are printed.\n\
00097 \n\
00098 @end table\n\
00099 \n\
00100 @var{cmember} is an optional vector of length @math{n}. It defines the\n\
00101 constraints on the column ordering. If @code{@var{cmember}(j) = @var{c}},\n\
00102 then column @var{j} is in constraint set @var{c} (@var{c} must be in the\n\
00103 range 1 to\n\
00104 n). In the output permutation @var{p}, all columns in set 1 appear\n\
00105 first, followed by all columns in set 2, and so on. @code{@var{cmember} =\n\
00106 ones(1,n)} if not present or empty.\n\
00107 @code{ccolamd (@var{S}, [], 1 : n)} returns @code{1 : n}\n\
00108 \n\
00109 @code{@var{p} = ccolamd (@var{S})} is about the same as\n\
00110 @code{@var{p} = colamd (@var{S})}. @var{knobs} and its default values\n\
00111 differ. @code{colamd} always does aggressive absorption, and it finds an\n\
00112 ordering suitable for both @code{lu (@var{S}(:, @var{p}))} and @code{chol\n\
00113 (@var{S}(:, @var{p})' * @var{S}(:, @var{p}))}; it cannot optimize its\n\
00114 ordering for @code{lu (@var{S}(:, @var{p}))} to the extent that\n\
00115 @code{ccolamd (@var{S}, 1)} can.\n\
00116 \n\
00117 @var{stats} is an optional 20-element output vector that provides data\n\
00118 about the ordering and the validity of the input matrix @var{S}. Ordering\n\
00119 statistics are in @code{@var{stats}(1 : 3)}. @code{@var{stats}(1)} and\n\
00120 @code{@var{stats}(2)} are the number of dense or empty rows and columns\n\
00121 ignored by @sc{ccolamd} and @code{@var{stats}(3)} is the number of garbage\n\
00122 collections performed on the internal data structure used by @sc{ccolamd}\n\
00123 (roughly of size @code{2.2 * nnz (@var{S}) + 4 * @var{m} + 7 * @var{n}}\n\
00124 integers).\n\
00125 \n\
00126 @code{@var{stats}(4 : 7)} provide information if CCOLAMD was able to\n\
00127 continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if\n\
00128 invalid. @code{@var{stats}(5)} is the rightmost column index that is\n\
00129 unsorted or contains duplicate entries, or zero if no such column exists.\n\
00130 @code{@var{stats}(6)} is the last seen duplicate or out-of-order row\n\
00131 index in the column index given by @code{@var{stats}(5)}, or zero if no\n\
00132 such row index exists. @code{@var{stats}(7)} is the number of duplicate\n\
00133 or out-of-order row indices. @code{@var{stats}(8 : 20)} is always zero in\n\
00134 the current version of @sc{ccolamd} (reserved for future use).\n\
00135 \n\
00136 The authors of the code itself are S. Larimore, T. Davis (Univ. of Florida)\n\
00137 and S. Rajamanickam in collaboration with J. Bilbert and E. Ng. Supported\n\
00138 by the National Science Foundation (DMS-9504974, DMS-9803599, CCR-0203270),\n\
00139 and a grant from Sandia National Lab. See\n\
00140 @url{http://www.cise.ufl.edu/research/sparse} for ccolamd, csymamd, amd,\n\
00141 colamd, symamd, and other related orderings.\n\
00142 @seealso{colamd, csymamd}\n\
00143 @end deftypefn")
00144 {
00145 octave_value_list retval;
00146
00147 #ifdef HAVE_CCOLAMD
00148
00149 int nargin = args.length ();
00150 int spumoni = 0;
00151
00152 if (nargout > 2 || nargin < 1 || nargin > 3)
00153 usage ("ccolamd: incorrect number of input and/or output arguments");
00154 else
00155 {
00156
00157 OCTAVE_LOCAL_BUFFER (double, knobs, CCOLAMD_KNOBS);
00158 CCOLAMD_NAME (_set_defaults) (knobs);
00159
00160
00161 if (nargin > 1)
00162 {
00163 NDArray User_knobs = args(1).array_value ();
00164 int nel_User_knobs = User_knobs.length ();
00165
00166 if (nel_User_knobs > 0)
00167 knobs [CCOLAMD_LU] = (User_knobs (0) != 0);
00168 if (nel_User_knobs > 1)
00169 knobs [CCOLAMD_DENSE_ROW] = User_knobs (1);
00170 if (nel_User_knobs > 2)
00171 knobs [CCOLAMD_DENSE_COL] = User_knobs (2);
00172 if (nel_User_knobs > 3)
00173 knobs [CCOLAMD_AGGRESSIVE] = (User_knobs (3) != 0);
00174 if (nel_User_knobs > 4)
00175 spumoni = (User_knobs (4) != 0);
00176
00177
00178 if (spumoni)
00179 {
00180 octave_stdout << "\nccolamd version " << CCOLAMD_MAIN_VERSION << "."
00181 << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE
00182 << ":\nknobs(1): " << User_knobs (0) << ", order for ";
00183 if ( knobs [CCOLAMD_LU] != 0)
00184 octave_stdout << "lu(A)\n";
00185 else
00186 octave_stdout << "chol(A'*A)\n";
00187
00188 if (knobs [CCOLAMD_DENSE_ROW] >= 0)
00189 octave_stdout << "knobs(2): " << User_knobs (1)
00190 << ", rows with > max(16,"
00191 << knobs [CCOLAMD_DENSE_ROW] << "*sqrt(size(A,2)))"
00192 << " entries removed\n";
00193 else
00194 octave_stdout << "knobs(2): " << User_knobs (1)
00195 << ", no dense rows removed\n";
00196
00197 if (knobs [CCOLAMD_DENSE_COL] >= 0)
00198 octave_stdout << "knobs(3): " << User_knobs (2)
00199 << ", cols with > max(16,"
00200 << knobs [CCOLAMD_DENSE_COL] << "*sqrt(size(A)))"
00201 << " entries removed\n";
00202 else
00203 octave_stdout << "knobs(3): " << User_knobs (2)
00204 << ", no dense columns removed\n";
00205
00206 if (knobs [CCOLAMD_AGGRESSIVE] != 0)
00207 octave_stdout << "knobs(4): " << User_knobs(3)
00208 << ", aggressive absorption: yes";
00209 else
00210 octave_stdout << "knobs(4): " << User_knobs(3)
00211 << ", aggressive absorption: no";
00212
00213 octave_stdout << "knobs(5): " << User_knobs (4)
00214 << ", statistics and knobs printed\n";
00215 }
00216 }
00217
00218 octave_idx_type n_row, n_col, nnz;
00219 octave_idx_type *ridx, *cidx;
00220 SparseComplexMatrix scm;
00221 SparseMatrix sm;
00222
00223 if (args(0).is_sparse_type ())
00224 {
00225 if (args(0).is_complex_type ())
00226 {
00227 scm = args(0). sparse_complex_matrix_value ();
00228 n_row = scm.rows ();
00229 n_col = scm.cols ();
00230 nnz = scm.nnz ();
00231 ridx = scm.xridx ();
00232 cidx = scm.xcidx ();
00233 }
00234 else
00235 {
00236 sm = args(0).sparse_matrix_value ();
00237
00238 n_row = sm.rows ();
00239 n_col = sm.cols ();
00240 nnz = sm.nnz ();
00241 ridx = sm.xridx ();
00242 cidx = sm.xcidx ();
00243 }
00244 }
00245 else
00246 {
00247 if (args(0).is_complex_type ())
00248 sm = SparseMatrix (real (args(0).complex_matrix_value ()));
00249 else
00250 sm = SparseMatrix (args(0).matrix_value ());
00251
00252 n_row = sm.rows ();
00253 n_col = sm.cols ();
00254 nnz = sm.nnz ();
00255 ridx = sm.xridx ();
00256 cidx = sm.xcidx ();
00257 }
00258
00259
00260 OCTAVE_LOCAL_BUFFER (octave_idx_type, p, n_col+1);
00261 for (octave_idx_type i = 0; i < n_col+1; i++)
00262 p[i] = cidx [i];
00263
00264 octave_idx_type Alen = CCOLAMD_NAME (_recommended) (nnz, n_row, n_col);
00265 OCTAVE_LOCAL_BUFFER (octave_idx_type, A, Alen);
00266 for (octave_idx_type i = 0; i < nnz; i++)
00267 A[i] = ridx [i];
00268
00269 OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, CCOLAMD_STATS);
00270
00271 if (nargin > 2)
00272 {
00273 NDArray in_cmember = args(2).array_value();
00274 octave_idx_type cslen = in_cmember.length();
00275 OCTAVE_LOCAL_BUFFER (octave_idx_type, cmember, cslen);
00276 for (octave_idx_type i = 0; i < cslen; i++)
00277
00278 cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1);
00279
00280 if (cslen != n_col)
00281 error ("ccolamd: CMEMBER must be of length equal to #cols of A");
00282 else
00283
00284 if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, cmember))
00285 {
00286 CCOLAMD_NAME (_report) (stats) ;
00287 error ("ccolamd: internal error!");
00288 return retval;
00289 }
00290 }
00291 else
00292 {
00293
00294 if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, 0))
00295 {
00296 CCOLAMD_NAME (_report) (stats) ;
00297 error ("ccolamd: internal error!");
00298 return retval;
00299 }
00300 }
00301
00302
00303 NDArray out_perm (dim_vector (1, n_col));
00304 for (octave_idx_type i = 0; i < n_col; i++)
00305 out_perm(i) = p [i] + 1;
00306
00307 retval (0) = out_perm;
00308
00309
00310 if (spumoni > 0)
00311 CCOLAMD_NAME (_report) (stats) ;
00312
00313
00314 if (nargout == 2)
00315 {
00316 NDArray out_stats (dim_vector (1, CCOLAMD_STATS));
00317 for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++)
00318 out_stats (i) = stats [i] ;
00319 retval(1) = out_stats;
00320
00321
00322
00323
00324 out_stats (CCOLAMD_INFO1) ++ ;
00325 out_stats (CCOLAMD_INFO2) ++ ;
00326 }
00327 }
00328
00329 #else
00330
00331 error ("ccolamd: not available in this version of Octave");
00332
00333 #endif
00334
00335 return retval;
00336 }
00337
00338 DEFUN_DLD (csymamd, args, nargout,
00339 "-*- texinfo -*-\n\
00340 @deftypefn {Loadable Function} {@var{p} =} csymamd (@var{S})\n\
00341 @deftypefnx {Loadable Function} {@var{p} =} csymamd (@var{S}, @var{knobs})\n\
00342 @deftypefnx {Loadable Function} {@var{p} =} csymamd (@var{S}, @var{knobs}, @var{cmember})\n\
00343 @deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} csymamd (@dots{})\n\
00344 \n\
00345 For a symmetric positive definite matrix @var{S}, returns the permutation\n\
00346 vector @var{p} such that @code{@var{S}(@var{p},@var{p})} tends to have a\n\
00347 sparser Cholesky@tie{}factor than @var{S}. Sometimes @code{csymamd} works\n\
00348 well for symmetric indefinite matrices too. The matrix @var{S} is assumed\n\
00349 to be symmetric; only the strictly lower triangular part is referenced.\n\
00350 @var{S} must be square. The ordering is followed by an elimination tree\n\
00351 post-ordering.\n\
00352 \n\
00353 @var{knobs} is an optional 1-element to 3-element input vector, with a\n\
00354 default value of @code{[10 1 0]} if present or empty. Entries not\n\
00355 present are set to their defaults.\n\
00356 \n\
00357 @table @code\n\
00358 @item @var{knobs}(1)\n\
00359 If @var{S} is n-by-n, then rows and columns with more than\n\
00360 @code{max(16,@var{knobs}(1)*sqrt(n))} entries are ignored, and ordered\n\
00361 last in the output permutation (subject to the cmember constraints).\n\
00362 \n\
00363 @item @var{knobs}(2)\n\
00364 If nonzero, aggressive absorption is performed.\n\
00365 \n\
00366 @item @var{knobs}(3)\n\
00367 If nonzero, statistics and knobs are printed.\n\
00368 \n\
00369 @end table\n\
00370 \n\
00371 @var{cmember} is an optional vector of length n. It defines the constraints\n\
00372 on the ordering. If @code{@var{cmember}(j) = @var{S}}, then row/column j is\n\
00373 in constraint set @var{c} (@var{c} must be in the range 1 to n). In the\n\
00374 output permutation @var{p}, rows/columns in set 1 appear first, followed\n\
00375 by all rows/columns in set 2, and so on. @code{@var{cmember} = ones(1,n)}\n\
00376 if not present or empty. @code{csymamd(@var{S},[],1:n)} returns @code{1:n}.\n\
00377 \n\
00378 @code{@var{p} = csymamd(@var{S})} is about the same as @code{@var{p} =\n\
00379 symamd(@var{S})}. @var{knobs} and its default values differ.\n\
00380 \n\
00381 @code{@var{stats}(4:7)} provide information if CCOLAMD was able to\n\
00382 continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if\n\
00383 invalid. @code{@var{stats}(5)} is the rightmost column index that is\n\
00384 unsorted or contains duplicate entries, or zero if no such column exists.\n\
00385 @code{@var{stats}(6)} is the last seen duplicate or out-of-order row\n\
00386 index in the column index given by @code{@var{stats}(5)}, or zero if no\n\
00387 such row index exists. @code{@var{stats}(7)} is the number of duplicate\n\
00388 or out-of-order row indices. @code{@var{stats}(8:20)} is always zero in\n\
00389 the current version of @sc{ccolamd} (reserved for future use).\n\
00390 \n\
00391 The authors of the code itself are S. Larimore, T. Davis (Uni of Florida)\n\
00392 and S. Rajamanickam in collaboration with J. Bilbert and E. Ng. Supported\n\
00393 by the National Science Foundation (DMS-9504974, DMS-9803599, CCR-0203270),\n\
00394 and a grant from Sandia National Lab. See\n\
00395 @url{http://www.cise.ufl.edu/research/sparse} for ccolamd, csymamd, amd,\n\
00396 colamd, symamd, and other related orderings.\n\
00397 @seealso{symamd, ccolamd}\n\
00398 @end deftypefn")
00399 {
00400 octave_value_list retval;
00401
00402 #if HAVE_CCOLAMD
00403
00404 int nargin = args.length ();
00405 int spumoni = 0;
00406
00407 if (nargout > 2 || nargin < 1 || nargin > 3)
00408 usage ("ccolamd: incorrect number of input and/or output arguments");
00409 else
00410 {
00411
00412 OCTAVE_LOCAL_BUFFER (double, knobs, CCOLAMD_KNOBS);
00413 CCOLAMD_NAME (_set_defaults) (knobs);
00414
00415
00416 if (nargin > 1)
00417 {
00418 NDArray User_knobs = args(1).array_value ();
00419 int nel_User_knobs = User_knobs.length ();
00420
00421 if (nel_User_knobs > 0)
00422 knobs [CCOLAMD_DENSE_ROW] = User_knobs (0);
00423 if (nel_User_knobs > 0)
00424 knobs [CCOLAMD_AGGRESSIVE] = User_knobs (1);
00425 if (nel_User_knobs > 1)
00426 spumoni = static_cast<int> (User_knobs (2));
00427
00428
00429 if (spumoni)
00430 {
00431 octave_stdout << "\ncsymamd version " << CCOLAMD_MAIN_VERSION << "."
00432 << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE << "\n";
00433
00434 if (knobs [CCOLAMD_DENSE_ROW] >= 0)
00435 octave_stdout << "knobs(1): " << User_knobs (0)
00436 << ", rows/cols with > max(16,"
00437 << knobs [CCOLAMD_DENSE_ROW] << "*sqrt(size(A,2)))"
00438 << " entries removed\n";
00439 else
00440 octave_stdout << "knobs(1): " << User_knobs (0)
00441 << ", no dense rows/cols removed\n";
00442
00443 if (knobs [CCOLAMD_AGGRESSIVE] != 0)
00444 octave_stdout << "knobs(2): " << User_knobs(1)
00445 << ", aggressive absorption: yes";
00446 else
00447 octave_stdout << "knobs(2): " << User_knobs(1)
00448 << ", aggressive absorption: no";
00449
00450
00451 octave_stdout << "knobs(3): " << User_knobs (2)
00452 << ", statistics and knobs printed\n";
00453 }
00454 }
00455
00456 octave_idx_type n_row, n_col;
00457 octave_idx_type *ridx, *cidx;
00458 SparseMatrix sm;
00459 SparseComplexMatrix scm;
00460
00461 if (args(0).is_sparse_type ())
00462 {
00463 if (args(0).is_complex_type ())
00464 {
00465 scm = args(0).sparse_complex_matrix_value ();
00466 n_row = scm.rows ();
00467 n_col = scm.cols ();
00468 ridx = scm.xridx ();
00469 cidx = scm.xcidx ();
00470 }
00471 else
00472 {
00473 sm = args(0).sparse_matrix_value ();
00474 n_row = sm.rows ();
00475 n_col = sm.cols ();
00476 ridx = sm.xridx ();
00477 cidx = sm.xcidx ();
00478 }
00479 }
00480 else
00481 {
00482 if (args(0).is_complex_type ())
00483 sm = SparseMatrix (real (args(0).complex_matrix_value ()));
00484 else
00485 sm = SparseMatrix (args(0).matrix_value ());
00486
00487 n_row = sm.rows ();
00488 n_col = sm.cols ();
00489 ridx = sm.xridx ();
00490 cidx = sm.xcidx ();
00491 }
00492
00493 if (n_row != n_col)
00494 {
00495 error ("csymamd: matrix S must be square");
00496 return retval;
00497 }
00498
00499
00500 OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, n_col+1);
00501 OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, CCOLAMD_STATS);
00502
00503 if (nargin > 2)
00504 {
00505 NDArray in_cmember = args(2).array_value();
00506 octave_idx_type cslen = in_cmember.length();
00507 OCTAVE_LOCAL_BUFFER (octave_idx_type, cmember, cslen);
00508 for (octave_idx_type i = 0; i < cslen; i++)
00509
00510 cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1);
00511
00512 if (cslen != n_col)
00513 error ("csymamd: CMEMBER must be of length equal to #cols of A");
00514 else
00515 if (!CSYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats,
00516 &calloc, &free, cmember, -1))
00517 {
00518 CSYMAMD_NAME (_report) (stats) ;
00519 error ("csymamd: internal error!") ;
00520 return retval;
00521 }
00522 }
00523 else
00524 {
00525 if (!CSYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats,
00526 &calloc, &free, 0, -1))
00527 {
00528 CSYMAMD_NAME (_report) (stats) ;
00529 error ("csymamd: internal error!") ;
00530 return retval;
00531 }
00532 }
00533
00534
00535 NDArray out_perm (dim_vector (1, n_col));
00536 for (octave_idx_type i = 0; i < n_col; i++)
00537 out_perm(i) = perm [i] + 1;
00538
00539 retval (0) = out_perm;
00540
00541
00542 if (nargout == 2)
00543 {
00544 NDArray out_stats (dim_vector (1, CCOLAMD_STATS));
00545 for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++)
00546 out_stats (i) = stats [i] ;
00547 retval(1) = out_stats;
00548
00549
00550
00551
00552 out_stats (CCOLAMD_INFO1) ++ ;
00553 out_stats (CCOLAMD_INFO2) ++ ;
00554 }
00555
00556
00557 if (spumoni > 0)
00558 CSYMAMD_NAME (_report) (stats) ;
00559
00560
00561 if (nargout == 2)
00562 {
00563 NDArray out_stats (dim_vector (1, CCOLAMD_STATS));
00564 for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++)
00565 out_stats (i) = stats [i] ;
00566 retval(1) = out_stats;
00567
00568
00569
00570
00571 out_stats (CCOLAMD_INFO1) ++ ;
00572 out_stats (CCOLAMD_INFO2) ++ ;
00573 }
00574 }
00575
00576 #else
00577
00578 error ("csymamd: not available in this version of Octave");
00579
00580 #endif
00581
00582 return retval;
00583 }