amd.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2008-2012 David Bateman
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 // This is the octave interface to amd, which bore the copyright given
00024 // in the help of the functions.
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 #include "oct-map.h"
00043 
00044 #include "oct-sparse.h"
00045 #include "oct-locbuf.h"
00046 
00047 #ifdef IDX_TYPE_LONG
00048 #define AMD_NAME(name) amd_l ## name
00049 #else
00050 #define AMD_NAME(name) amd ## name
00051 #endif
00052 
00053 DEFUN_DLD (amd, args, nargout,
00054     "-*- texinfo -*-\n\
00055 @deftypefn  {Loadable Function} {@var{p} =} amd (@var{S})\n\
00056 @deftypefnx {Loadable Function} {@var{p} =} amd (@var{S}, @var{opts})\n\
00057 \n\
00058 Return the approximate minimum degree permutation of a matrix.  This\n\
00059 permutation such that the Cholesky@tie{}factorization of @code{@var{S}\n\
00060 (@var{p}, @var{p})} tends to be sparser than the Cholesky@tie{}factorization\n\
00061 of @var{S} itself.  @code{amd} is typically faster than @code{symamd} but\n\
00062 serves a similar purpose.\n\
00063 \n\
00064 The optional parameter @var{opts} is a structure that controls the\n\
00065 behavior of @code{amd}.  The fields of the structure are\n\
00066 \n\
00067 @table @asis\n\
00068 @item @var{opts}.dense\n\
00069 Determines what @code{amd} considers to be a dense row or column of the\n\
00070 input matrix.  Rows or columns with more than @code{max(16, (dense *\n\
00071 sqrt (@var{n})} entries, where @var{n} is the order of the matrix @var{S},\n\
00072 are ignored by @code{amd} during the calculation of the permutation\n\
00073 The value of dense must be a positive scalar and its default value is 10.0\n\
00074 \n\
00075 @item @var{opts}.aggressive\n\
00076 If this value is a non zero scalar, then @code{amd} performs aggressive\n\
00077 absorption.  The default is not to perform aggressive absorption.\n\
00078 @end table\n\
00079 \n\
00080 The author of the code itself is Timothy A. Davis\n\
00081 @email{davis@@cise.ufl.edu}, University of Florida (see\n\
00082 @url{http://www.cise.ufl.edu/research/sparse/amd}).\n\
00083 @seealso{symamd, colamd}\n\
00084 @end deftypefn")
00085 {
00086   octave_value_list retval;
00087 
00088 #ifdef HAVE_AMD
00089   int nargin = args.length ();
00090 
00091   if (nargin < 1 || nargin > 2)
00092     print_usage ();
00093   else
00094     {
00095       octave_idx_type n_row, n_col;
00096       const octave_idx_type *ridx, *cidx;
00097       SparseMatrix sm;
00098       SparseComplexMatrix scm;
00099 
00100       if (args(0).is_sparse_type ())
00101         {
00102           if (args(0).is_complex_type ())
00103             {
00104               scm = args(0).sparse_complex_matrix_value ();
00105               n_row = scm.rows ();
00106               n_col = scm.cols ();
00107               ridx = scm.xridx ();
00108               cidx = scm.xcidx ();
00109             }
00110           else
00111             {
00112               sm = args(0).sparse_matrix_value ();
00113               n_row = sm.rows ();
00114               n_col = sm.cols ();
00115               ridx = sm.xridx ();
00116               cidx = sm.xcidx ();
00117             }
00118         }
00119       else
00120         {
00121           if (args(0).is_complex_type ())
00122             sm = SparseMatrix (real (args(0).complex_matrix_value ()));
00123           else
00124             sm = SparseMatrix (args(0).matrix_value ());
00125 
00126           n_row = sm.rows ();
00127           n_col = sm.cols ();
00128           ridx = sm.xridx ();
00129           cidx = sm.xcidx ();
00130         }
00131 
00132       if (!error_state && n_row != n_col)
00133         error ("amd: matrix S must be square");
00134 
00135       if (!error_state)
00136         {
00137           OCTAVE_LOCAL_BUFFER (double, Control, AMD_CONTROL);
00138           AMD_NAME (_defaults) (Control) ;
00139           if (nargin > 1)
00140             {
00141               octave_scalar_map arg1 = args(1).scalar_map_value ();
00142 
00143               if (!error_state)
00144                 {
00145                   octave_value tmp;
00146 
00147                   tmp = arg1.getfield ("dense");
00148                   if (tmp.is_defined ())
00149                     Control[AMD_DENSE] = tmp.double_value ();
00150 
00151                   tmp = arg1.getfield ("aggressive");
00152                   if (tmp.is_defined ())
00153                     Control[AMD_AGGRESSIVE] = tmp.double_value ();
00154                 }
00155               else
00156                 error ("amd: OPTS argument must be a scalar structure");
00157             }
00158 
00159           if (!error_state)
00160             {
00161               OCTAVE_LOCAL_BUFFER (octave_idx_type, P, n_col);
00162               Matrix xinfo (AMD_INFO, 1);
00163               double *Info = xinfo.fortran_vec ();
00164 
00165               // FIXME -- how can we manage the memory allocation of
00166               // amd in a cleaner manner?
00167               amd_malloc = malloc;
00168               amd_free = free;
00169               amd_calloc = calloc;
00170               amd_realloc = realloc;
00171               amd_printf = printf;
00172 
00173               octave_idx_type result = AMD_NAME (_order) (n_col, cidx, ridx, P,
00174                                                           Control, Info);
00175 
00176               switch (result)
00177                 {
00178                 case AMD_OUT_OF_MEMORY:
00179                   error ("amd: out of memory");
00180                   break;
00181                 case AMD_INVALID:
00182                   error ("amd: matrix S is corrupted");
00183                   break;
00184                 default:
00185                   {
00186                     if (nargout > 1)
00187                       retval(1) = xinfo;
00188 
00189                     Matrix Pout (1, n_col);
00190                     for (octave_idx_type i = 0; i < n_col; i++)
00191                       Pout.xelem (i) = P[i] + 1;
00192 
00193                     retval (0) = Pout;
00194                   }
00195                 }
00196             }
00197         }
00198     }
00199 #else
00200 
00201   error ("amd: not available in this version of Octave");
00202 
00203 #endif
00204 
00205   return retval;
00206 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines