symbfact.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2012 David Bateman
00004 Copyright (C) 1998-2005 Andy Adler
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include "SparseCmplxCHOL.h"
00029 #include "SparsedbleCHOL.h"
00030 #include "oct-spparms.h"
00031 #include "sparse-util.h"
00032 #include "oct-locbuf.h"
00033 
00034 #include "ov-re-sparse.h"
00035 #include "ov-cx-sparse.h"
00036 #include "defun-dld.h"
00037 #include "error.h"
00038 #include "gripes.h"
00039 #include "oct-obj.h"
00040 #include "utils.h"
00041 
00042 DEFUN_DLD (symbfact, args, nargout,
00043     "-*- texinfo -*-\n\
00044 @deftypefn  {Loadable Function} {[@var{count}, @var{h}, @var{parent}, @var{post}, @var{r}] =} symbfact (@var{S})\n\
00045 @deftypefnx {Loadable Function} {[@dots{}] =} symbfact (@var{S}, @var{typ})\n\
00046 @deftypefnx {Loadable Function} {[@dots{}] =} symbfact (@var{S}, @var{typ}, @var{mode})\n\
00047 \n\
00048 Perform a symbolic factorization analysis on the sparse matrix @var{S}.\n\
00049 Where\n\
00050 \n\
00051 @table @var\n\
00052 @item S\n\
00053 @var{S} is a complex or real sparse matrix.\n\
00054 \n\
00055 @item typ\n\
00056 Is the type of the factorization and can be one of\n\
00057 \n\
00058 @table @samp\n\
00059 @item sym\n\
00060 Factorize @var{S}.  This is the default.\n\
00061 \n\
00062 @item col\n\
00063 Factorize @code{@var{S}' * @var{S}}.\n\
00064 \n\
00065 @item row\n\
00066 Factorize @xcode{@var{S} * @var{S}'}.\n\
00067 \n\
00068 @item lo\n\
00069 Factorize @xcode{@var{S}'}\n\
00070 @end table\n\
00071 \n\
00072 @item mode\n\
00073 The default is to return the Cholesky@tie{}factorization for @var{r}, and if\n\
00074 @var{mode} is 'L', the conjugate transpose of the Cholesky@tie{}factorization\n\
00075 is returned.  The conjugate transpose version is faster and uses less\n\
00076 memory, but returns the same values for @var{count}, @var{h}, @var{parent}\n\
00077 and @var{post} outputs.\n\
00078 @end table\n\
00079 \n\
00080 The output variables are\n\
00081 \n\
00082 @table @var\n\
00083 @item count\n\
00084 The row counts of the Cholesky@tie{}factorization as determined by @var{typ}.\n\
00085 \n\
00086 @item h\n\
00087 The height of the elimination tree.\n\
00088 \n\
00089 @item parent\n\
00090 The elimination tree itself.\n\
00091 \n\
00092 @item post\n\
00093 A sparse boolean matrix whose structure is that of the Cholesky\n\
00094 factorization as determined by @var{typ}.\n\
00095 @end table\n\
00096 @end deftypefn")
00097 {
00098   octave_value_list retval;
00099   int nargin = args.length ();
00100 
00101   if (nargin < 1  || nargin > 3 || nargout > 5)
00102     {
00103       print_usage ();
00104       return retval;
00105     }
00106 
00107 #ifdef HAVE_CHOLMOD
00108 
00109   cholmod_common Common;
00110   cholmod_common *cm = &Common;
00111   CHOLMOD_NAME(start) (cm);
00112 
00113   double spu = octave_sparse_params::get_key ("spumoni");
00114   if (spu == 0.)
00115     {
00116       cm->print = -1;
00117       cm->print_function = 0;
00118     }
00119   else
00120     {
00121       cm->print = static_cast<int> (spu) + 2;
00122       cm->print_function =&SparseCholPrint;
00123     }
00124 
00125   cm->error_handler = &SparseCholError;
00126   cm->complex_divide = CHOLMOD_NAME(divcomplex);
00127   cm->hypotenuse = CHOLMOD_NAME(hypot);
00128 
00129   double dummy;
00130   cholmod_sparse Astore;
00131   cholmod_sparse *A = &Astore;
00132   A->packed = true;
00133   A->sorted = true;
00134   A->nz = 0;
00135 #ifdef IDX_TYPE_LONG
00136   A->itype = CHOLMOD_LONG;
00137 #else
00138   A->itype = CHOLMOD_INT;
00139 #endif
00140   A->dtype = CHOLMOD_DOUBLE;
00141   A->stype = 1;
00142   A->x = &dummy;
00143 
00144   if (args(0).is_real_type ())
00145     {
00146       const SparseMatrix a = args(0).sparse_matrix_value();
00147       A->nrow = a.rows();
00148       A->ncol = a.cols();
00149       A->p = a.cidx();
00150       A->i = a.ridx();
00151       A->nzmax = a.nnz();
00152       A->xtype = CHOLMOD_REAL;
00153 
00154       if (a.rows() > 0 && a.cols() > 0)
00155         A->x = a.data();
00156     }
00157   else if (args(0).is_complex_type ())
00158     {
00159       const SparseComplexMatrix a = args(0).sparse_complex_matrix_value();
00160       A->nrow = a.rows();
00161       A->ncol = a.cols();
00162       A->p = a.cidx();
00163       A->i = a.ridx();
00164       A->nzmax = a.nnz();
00165       A->xtype = CHOLMOD_COMPLEX;
00166 
00167       if (a.rows() > 0 && a.cols() > 0)
00168         A->x = a.data();
00169     }
00170   else
00171     gripe_wrong_type_arg ("symbfact", args(0));
00172 
00173   octave_idx_type coletree = false;
00174   octave_idx_type n = A->nrow;
00175 
00176   if (nargin > 1)
00177     {
00178       char ch;
00179       std::string str = args(1).string_value();
00180       ch = tolower (str.c_str()[0]);
00181       if (ch == 'r')
00182         A->stype = 0;
00183       else if (ch == 'c')
00184         {
00185           n = A->ncol;
00186           coletree = true;
00187           A->stype = 0;
00188         }
00189       else if (ch == 's')
00190         A->stype = 1;
00191       else if (ch == 's')
00192         A->stype = -1;
00193       else
00194         error ("symbfact: unrecognized TYP in symbolic factorization");
00195     }
00196 
00197   if (A->stype && A->nrow != A->ncol)
00198     error ("symbfact: S must be a square matrix");
00199 
00200   if (!error_state)
00201     {
00202       OCTAVE_LOCAL_BUFFER (octave_idx_type, Parent, n);
00203       OCTAVE_LOCAL_BUFFER (octave_idx_type, Post, n);
00204       OCTAVE_LOCAL_BUFFER (octave_idx_type, ColCount, n);
00205       OCTAVE_LOCAL_BUFFER (octave_idx_type, First, n);
00206       OCTAVE_LOCAL_BUFFER (octave_idx_type, Level, n);
00207 
00208       cholmod_sparse *F = CHOLMOD_NAME(transpose) (A, 0, cm);
00209       cholmod_sparse *Aup, *Alo;
00210 
00211       if (A->stype == 1 || coletree)
00212         {
00213           Aup = A ;
00214           Alo = F ;
00215         }
00216       else
00217         {
00218           Aup = F ;
00219           Alo = A ;
00220         }
00221 
00222       CHOLMOD_NAME(etree) (Aup, Parent, cm);
00223 
00224       if (cm->status < CHOLMOD_OK)
00225         {
00226           error("matrix corrupted");
00227           goto symbfact_error;
00228         }
00229 
00230       if (CHOLMOD_NAME(postorder) (Parent, n, 0, Post, cm) != n)
00231         {
00232           error("postorder failed");
00233           goto symbfact_error;
00234         }
00235 
00236       CHOLMOD_NAME(rowcolcounts) (Alo, 0, 0, Parent, Post, 0,
00237                                   ColCount, First, Level, cm);
00238 
00239       if (cm->status < CHOLMOD_OK)
00240         {
00241           error("matrix corrupted");
00242           goto symbfact_error;
00243         }
00244 
00245       if (nargout > 4)
00246         {
00247           cholmod_sparse *A1, *A2;
00248 
00249           if (A->stype == 1)
00250             {
00251               A1 = A;
00252               A2 = 0;
00253             }
00254           else if (A->stype == -1)
00255             {
00256               A1 = F;
00257               A2 = 0;
00258             }
00259           else if (coletree)
00260             {
00261               A1 = F;
00262               A2 = A;
00263             }
00264           else
00265             {
00266               A1 = A;
00267               A2 = F;
00268             }
00269 
00270           // count the total number of entries in L
00271           octave_idx_type lnz = 0 ;
00272           for (octave_idx_type j = 0 ; j < n ; j++)
00273             lnz += ColCount [j] ;
00274 
00275 
00276           // allocate the output matrix L (pattern-only)
00277           SparseBoolMatrix L (n, n, lnz);
00278 
00279           // initialize column pointers
00280           lnz = 0;
00281           for (octave_idx_type j = 0 ; j < n ; j++)
00282             {
00283               L.xcidx(j) = lnz;
00284               lnz += ColCount [j];
00285             }
00286           L.xcidx(n) = lnz;
00287 
00288 
00289           /* create a copy of the column pointers */
00290           octave_idx_type *W = First;
00291           for (octave_idx_type j = 0 ; j < n ; j++)
00292             W [j] = L.xcidx(j);
00293 
00294           // get workspace for computing one row of L
00295           cholmod_sparse *R = cholmod_allocate_sparse (n, 1, n, false, true,
00296                                                        0, CHOLMOD_PATTERN, cm);
00297           octave_idx_type *Rp = static_cast<octave_idx_type *>(R->p);
00298           octave_idx_type *Ri = static_cast<octave_idx_type *>(R->i);
00299 
00300           // compute L one row at a time
00301           for (octave_idx_type k = 0 ; k < n ; k++)
00302             {
00303               // get the kth row of L and store in the columns of L
00304               CHOLMOD_NAME (row_subtree) (A1, A2, k, Parent, R, cm) ;
00305               for (octave_idx_type p = 0 ; p < Rp [1] ; p++)
00306                 L.xridx (W [Ri [p]]++) = k ;
00307 
00308               // add the diagonal entry
00309               L.xridx (W [k]++) = k ;
00310             }
00311 
00312           // free workspace
00313           cholmod_free_sparse (&R, cm) ;
00314 
00315 
00316           // transpose L to get R, or leave as is
00317           if (nargin < 3)
00318             L = L.transpose ();
00319 
00320           // fill numerical values of L with one's
00321           for (octave_idx_type p = 0 ; p < lnz ; p++)
00322             L.xdata(p) = true;
00323 
00324           retval(4) = L;
00325         }
00326 
00327       ColumnVector tmp (n);
00328       if (nargout > 3)
00329         {
00330           for (octave_idx_type i = 0; i < n; i++)
00331             tmp(i) = Post[i] + 1;
00332           retval(3) = tmp;
00333         }
00334 
00335       if (nargout > 2)
00336         {
00337           for (octave_idx_type i = 0; i < n; i++)
00338             tmp(i) = Parent[i] + 1;
00339           retval(2) = tmp;
00340         }
00341 
00342       if (nargout > 1)
00343         {
00344           /* compute the elimination tree height */
00345           octave_idx_type height = 0 ;
00346           for (int i = 0 ; i < n ; i++)
00347             height = (height > Level[i] ? height : Level[i]);
00348           height++ ;
00349           retval(1) = static_cast<double> (height);
00350         }
00351 
00352       for (octave_idx_type i = 0; i < n; i++)
00353         tmp(i) = ColCount[i];
00354       retval(0) = tmp;
00355     }
00356 
00357  symbfact_error:
00358 #else
00359   error ("symbfact: not available in this version of Octave");
00360 #endif
00361 
00362   return retval;
00363 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines