# HG changeset patch # User dbateman # Date 1139476323 0 # Node ID 9761b7d24e9eab98ffe9b0cb3256015a3f133838 # Parent bf96b0f9dbd772ef19672e4040f4305a44462d63 [project @ 2006-02-09 09:12:02 by dbateman] diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2006-02-09 David Bateman + + * configure.in: Fix for probe of colamd, cccolamd and metis. New test + for the presence of cxsparse. + Makeconf.in: Include CXSPARSE_LIBS. + 2006-01-19 John W. Eaton * configure.in: Use $WITH_PCRE instead of $HAVE_PCRE in shell test. diff --git a/Makeconf.in b/Makeconf.in --- a/Makeconf.in +++ b/Makeconf.in @@ -200,6 +200,7 @@ COLAMD_LIBS = @COLAMD_LIBS@ CCOLAMD_LIBS = @CCOLAMD_LIBS@ CHOLMOD_LIBS = @CHOLMOD_LIBS@ +CXSPARSE_LIBS = @CXSPARSE_LIBS@ LIBS = @LIBS@ USE_64_BIT_IDX_T = @USE_64_BIT_IDX_T@ diff --git a/PROJECTS b/PROJECTS --- a/PROJECTS +++ b/PROJECTS @@ -107,14 +107,11 @@ Sparse Matrices: --------------- - * QR factorization functions, also for use in lssolve functions. Write - svds function based on this. Write sprank function based on svds. + * Improve QR factorization functions, using idea based on CSPARSE + cs_dmsol.m - * Once dmperm is implemented, perhaps use the technique to detect permuted - triangular matrices with permutations in both rows and cols. - - * Implement fourth argument to the sprand and sprandn that the leading - brand implements. + * Implement fourth argument to the sprand and sprandn, and addition + arguments to sprandsym that the leading brand implements. * Sparse logical indexing in idx_vector class so that something like "a=sprandn(1e6,1e6,1e-6); a(a<1) = 0" won't cause a memory overflow. @@ -122,13 +119,13 @@ * Write the rest of the sparse docs * The algo in TOMS 582 is perfect for symrcm function. However, this is - under the ACM license and can't be used in a GPL program. + under the ACM license and can't be used in a GPL program. An alternative is that PETSC is GPL compatiable and has a symrcm implemented from the original SPARSPAK. Its not clear that this is legal to me as I have found no clarification of the original license of SPARSPAK. As PETSC has had this code for over 10 years without - problem, we can perhaps assume that there is no issues. Maybe need + problem, we can perhaps assume that there are no issues. Maybe need to contact PETSC people or the SPARSPAK people at uni of waterloo to check issues. @@ -155,18 +152,10 @@ way to treat this but a complete rewrite of the sparse assignment functions... - * Port the sparse testing code into the DejaGNU testing code. Add tests - for spkron, matrix_type, luinc.. - * Other missing Functions - eigs - - dmperm Use Tim Davis' BTF code when available - symmmd Superseded by symamd - colmmd Superseded by colamd - - sprandsym - - etreeplot - - treeplot - - gplot - treelayout - cholinc - condest diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -29,7 +29,7 @@ EXTERN_CXXFLAGS="$CXXFLAGS" AC_INIT -AC_REVISION($Revision: 1.498 $) +AC_REVISION($Revision: 1.499 $) AC_PREREQ(2.57) AC_CONFIG_SRCDIR([src/octave.cc]) AC_CONFIG_HEADER(config.h) @@ -808,7 +808,7 @@ if test "$with_colamd" = yes; then warn_colamd="COLAMD not found. This will result in some lack of functionality for sparse matrices." with_colamd=no - AC_CHECK_HEADERS([ufsparse/colamd.h umfpack/colamd.h colamd.h], [ + AC_CHECK_HEADERS([ufsparse/colamd.h colamd/colamd.h colamd.h], [ AC_CHECK_LIB(colamd, colamd, [COLAMD_LIBS="-lcolamd"; with_colamd=yes]) if test "$with_colamd" = yes; then AC_DEFINE(HAVE_COLAMD, 1, [Define if the COLAMD library is used.]) @@ -831,7 +831,7 @@ if test "$with_ccolamd" = yes; then warn_ccolamd="CCOLAMD not found. This will result in some lack of functionality for sparse matrices." with_ccolamd=no - AC_CHECK_HEADERS([ufsparse/ccolamd.h umfpack/ccolamd.h ccolamd.h], [ + AC_CHECK_HEADERS([ufsparse/ccolamd.h ccolamd/ccolamd.h ccolamd.h], [ AC_CHECK_LIB(ccolamd, ccolamd, [CCOLAMD_LIBS="-lccolamd"; with_ccolamd=yes]) if test "$with_ccolamd" = yes; then AC_DEFINE(HAVE_CCOLAMD, 1, [Define if the CCOLAMD library is used.]) @@ -855,8 +855,8 @@ test "$with_ccolamd" = yes && test "$with_amd" = yes; then warn_cholmod="CHOLMOD not found. This will result in some lack of functionality for sparse matrices." with_cholmod=no - AC_CHECK_HEADERS([ufsparse/cholmod.h umfpack/cholmod.h cholmod.h], [ - AC_CHECK_HEADERS([metis/metis.h ufsparse/metis.h umfpack/metis.h metis.h], [ + AC_CHECK_HEADERS([ufsparse/cholmod.h cholmod/cholmod.h cholmod.h], [ + AC_CHECK_HEADERS([ufsparse/metis.h metis/metis.h metis.h], [ AC_CHECK_LIB(metis, METIS_NodeND, with_metis=yes, with_metis=no) break], with_metis=no) @@ -865,14 +865,14 @@ AC_DEFINE(HAVE_METIS, 1, [Define if the METIS library is used.]) AC_CHECK_LIB(cholmod, cholmod_start, [CHOLMOD_LIBS="-lcholmod -lmetis"; with_cholmod=yes], [ - AC_CHECK_LIB(cholmod_start, cholmod, + AC_CHECK_LIB(cholmod, cholmod_start, [CHOLMOD_LIBS="-lcholmod -cblas -lmetis"; with_cholmod=yes], [], $AMD_LIBS $COLAMD_LIBS $CCOLAMD_LIBS $BLAS_LIBS $FLIBS -lmetis)], $AMD_LIBS $COLAMD_LIBS $CCOLAMD_LIBS $BLAS_LIBS $FLIBS -lmetis) else AC_CHECK_LIB(cholmod, cholmod_start, [CHOLMOD_LIBS="-lcholmod"; with_cholmod=yes], [ - AC_CHECK_LIB(cholmod_start, cholmod, [CHOLMOD_LIBS="-lcholmod -cblas"; + AC_CHECK_LIB(cholmod, cholmod_start, [CHOLMOD_LIBS="-lcholmod -cblas"; with_cholmod=yes], [], $AMD_LIBS $COLAMD_LIBS $CCOLAMD_LIBS $BLAS_LIBS $FLIBS)], $AMD_LIBS $COLAMD_LIBS $CCOLAMD_LIBS $BLAS_LIBS $FLIBS) @@ -889,6 +889,29 @@ AC_MSG_WARN($warn_cholmod) fi +CXSPARSE_LIBS= +AC_SUBST(CXSPARSE_LIBS) + +AC_ARG_WITH(cxsparse, + [ --without-cxsparse don't use CXSparse, disable some sparse functionality], + with_cxsparse=$withval, with_cxsparse=yes) + +if test "$with_cxsparse" = yes; then + warn_cxsparse="CXSparse not found. This will result in some lack of functionality for sparse matrices." + with_cxsparse=no + AC_CHECK_HEADERS([ufsparse/cxs.h cxsparse/cxs.h cxs.h], [ + AC_CHECK_LIB(cxspack, cs_sqr_di, [CXSPARSE_LIBS="-lcxspack"; with_cxsparse=yes]) + if test "$with_cxsparse" = yes; then + AC_DEFINE(HAVE_CXSPARSE, 1, [Define if the CXSparse library is used.]) + warn_cxsparse= + fi + break]) +fi + +if test -n "$warn_cxsparse"; then + AC_MSG_WARN($warn_cxsparse) +fi + ### Handle shared library options. ### Enable creation of static libraries. @@ -1810,6 +1833,7 @@ COLAMD libraries: $COLAMD_LIBS CCOLAMD libraries: $CCOLAMD_LIBS CHOLMOD libraries: $CHOLMOD_LIBS + CXSPARSE libraries: $CXSPARSE_LIBS HDF5 libraries: $HDF5_LIBS MPI libraries: $MPI_LIBS LIBS: $LIBS diff --git a/liboctave/CSparse.cc b/liboctave/CSparse.cc --- a/liboctave/CSparse.cc +++ b/liboctave/CSparse.cc @@ -43,6 +43,7 @@ #include "oct-sparse.h" #include "sparse-util.h" #include "SparseCmplxCHOL.h" +#include "SparseCmplxQR.h" #include "oct-sort.h" @@ -610,7 +611,7 @@ SparseComplexMatrix SparseComplexMatrix::dinverse (SparseType &mattyp, octave_idx_type& info, - double& rcond, const bool force, + double& rcond, const bool, const bool calccond) const { SparseComplexMatrix retval; @@ -664,7 +665,7 @@ SparseComplexMatrix SparseComplexMatrix::tinverse (SparseType &mattyp, octave_idx_type& info, - double& rcond, const bool force, + double& rcond, const bool, const bool calccond) const { SparseComplexMatrix retval; @@ -902,7 +903,7 @@ SparseComplexMatrix SparseComplexMatrix::inverse (SparseType& mattype, octave_idx_type& info, - double& rcond, int force, int calc_cond) const + double& rcond, int, int calc_cond) const { int typ = mattype.type (false); SparseComplexMatrix ret; @@ -979,7 +980,7 @@ } ComplexDET -SparseComplexMatrix::determinant (octave_idx_type& err, double& rcond, int calc_cond) const +SparseComplexMatrix::determinant (octave_idx_type& err, double& rcond, int) const { ComplexDET retval; #ifdef HAVE_UMFPACK @@ -4936,7 +4937,6 @@ Symbolic, &Numeric, control, info) ; UMFPACK_ZNAME (free_symbolic) (&Symbolic) ; -#ifdef HAVE_LSSOLVE rcond = Info (UMFPACK_RCOND); volatile double rcond_plus_one = rcond + 1.0; @@ -4955,9 +4955,7 @@ rcond); } - else -#endif - if (status < 0) + else if (status < 0) { (*current_liboctave_error_handler) ("SparseComplexMatrix::solve numeric factorization failed"); @@ -5117,9 +5115,7 @@ ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", rcond); -#ifdef HAVE_LSSOLVE return retval; -#endif } cholmod_dense *X; @@ -5216,25 +5212,6 @@ } } -#ifndef HAVE_LSSOLVE - rcond = Info (UMFPACK_RCOND); - volatile double rcond_plus_one = rcond + 1.0; - - if (status == UMFPACK_WARNING_singular_matrix || - rcond_plus_one == 1.0 || xisnan (rcond)) - { - err = -2; - - if (sing_handler) - sing_handler (rcond); - else - (*current_liboctave_error_handler) - ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", - rcond); - - } -#endif - UMFPACK_ZNAME (report_info) (control, info); UMFPACK_ZNAME (free_numeric) (&Numeric); @@ -5396,9 +5373,7 @@ ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", rcond); -#ifdef HAVE_LSSOLVE return retval; -#endif } cholmod_sparse *X; @@ -5530,25 +5505,6 @@ retval.maybe_compress (); -#ifndef HAVE_LSSOLVE - rcond = Info (UMFPACK_RCOND); - volatile double rcond_plus_one = rcond + 1.0; - - if (status == UMFPACK_WARNING_singular_matrix || - rcond_plus_one == 1.0 || xisnan (rcond)) - { - err = -2; - - if (sing_handler) - sing_handler (rcond); - else - (*current_liboctave_error_handler) - ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", - rcond); - - } -#endif - UMFPACK_ZNAME (report_info) (control, info); UMFPACK_ZNAME (free_numeric) (&Numeric); @@ -5700,9 +5656,7 @@ ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", rcond); -#ifdef HAVE_LSSOLVE return retval; -#endif } cholmod_dense *X; @@ -5777,25 +5731,6 @@ } } -#ifndef HAVE_LSSOLVE - rcond = Info (UMFPACK_RCOND); - volatile double rcond_plus_one = rcond + 1.0; - - if (status == UMFPACK_WARNING_singular_matrix || - rcond_plus_one == 1.0 || xisnan (rcond)) - { - err = -2; - - if (sing_handler) - sing_handler (rcond); - else - (*current_liboctave_error_handler) - ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", - rcond); - - } -#endif - UMFPACK_ZNAME (report_info) (control, info); UMFPACK_ZNAME (free_numeric) (&Numeric); @@ -5957,9 +5892,7 @@ ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", rcond); -#ifdef HAVE_LSSOLVE return retval; -#endif } cholmod_sparse *X; @@ -6070,7 +6003,6 @@ retval.maybe_compress (); -#ifndef HAVE_LSSOLVE rcond = Info (UMFPACK_RCOND); volatile double rcond_plus_one = rcond + 1.0; @@ -6087,7 +6019,6 @@ rcond); } -#endif UMFPACK_ZNAME (report_info) (control, info); @@ -6580,12 +6511,9 @@ } ComplexMatrix -SparseComplexMatrix::lssolve (const Matrix& b, octave_idx_type& info, octave_idx_type& rank) const -{ - info = -1; - (*current_liboctave_error_handler) - ("SparseComplexMatrix::lssolve not implemented yet"); - return ComplexMatrix (); +SparseComplexMatrix::lssolve (const Matrix& b, octave_idx_type& info, octave_idx_type&) const +{ + return qrsolve (*this, b, info); } SparseComplexMatrix @@ -6605,12 +6533,9 @@ SparseComplexMatrix SparseComplexMatrix::lssolve (const SparseMatrix& b, octave_idx_type& info, - octave_idx_type& rank) const -{ - info = -1; - (*current_liboctave_error_handler) - ("SparseComplexMatrix::lssolve not implemented yet"); - return SparseComplexMatrix (); + octave_idx_type&) const +{ + return qrsolve (*this, b, info); } ComplexMatrix @@ -6630,12 +6555,9 @@ ComplexMatrix SparseComplexMatrix::lssolve (const ComplexMatrix& b, octave_idx_type& info, - octave_idx_type& rank) const -{ - info = -1; - (*current_liboctave_error_handler) - ("SparseComplexMatrix::lssolve not implemented yet"); - return ComplexMatrix (); + octave_idx_type&) const +{ + return qrsolve (*this, b, info); } SparseComplexMatrix @@ -6655,12 +6577,9 @@ SparseComplexMatrix SparseComplexMatrix::lssolve (const SparseComplexMatrix& b, octave_idx_type& info, - octave_idx_type& rank) const -{ - info = -1; - (*current_liboctave_error_handler) - ("SparseComplexMatrix::lssolve not implemented yet"); - return SparseComplexMatrix (); + octave_idx_type&) const +{ + return qrsolve (*this, b, info); } ComplexColumnVector @@ -6681,10 +6600,8 @@ ComplexColumnVector SparseComplexMatrix::lssolve (const ColumnVector& b, octave_idx_type& info, octave_idx_type& rank) const { - info = -1; - (*current_liboctave_error_handler) - ("SparseComplexMatrix::lssolve not implemented yet"); - return ComplexColumnVector (); + Matrix tmp (b); + return lssolve (tmp, info, rank).column (static_cast (0)); } ComplexColumnVector @@ -6706,10 +6623,8 @@ SparseComplexMatrix::lssolve (const ComplexColumnVector& b, octave_idx_type& info, octave_idx_type& rank) const { - info = -1; - (*current_liboctave_error_handler) - ("SparseComplexMatrix::lssolve not implemented yet"); - return ComplexColumnVector (); + ComplexMatrix tmp (b); + return lssolve (tmp, info, rank).column (static_cast (0)); } // unary operations diff --git a/liboctave/ChangeLog b/liboctave/ChangeLog --- a/liboctave/ChangeLog +++ b/liboctave/ChangeLog @@ -1,3 +1,20 @@ +2006-02-09 David Bateman + + * SparseQR.cc: new file for real sparse QR class. + * SparseQR.h: declaration. + * SparseCmplxQR.cc: new file for complex sparse QR class. + * SparseCmplxQR.h: declaration. + * dSparse.cc (dinverse,tinverse,inverse): Remove unused input args. + (factorize, fsolve): Enable code code lssolve. + (lssolve): disable unused args, write based in above sparse QR class. + * CSparse.cc (dinverse,tinverse,inverse): Remove unused input args. + (factorize, fsolve): Enable code code lssolve. + (lssolve): disable unused args, write based in above sparse QR class. + * oct-sparse.h: fix location of colamd, ccolamd and metis headers. + Include CXSparse headers. + * Makefile.in (MATRIX_INC): Include SparseQR.h and SparseCmplxQR.h. + (MATRIX_SRC): Include SparseQR.cc and SparseCmplxQR.cc. + 2006-02-08 John W. Eaton * Array-util.h (calc_permutated_idx): Delete. diff --git a/liboctave/Makefile.in b/liboctave/Makefile.in --- a/liboctave/Makefile.in +++ b/liboctave/Makefile.in @@ -37,7 +37,7 @@ boolSparse.h CSparse.h dSparse.h MSparse-defs.h MSparse.h \ Sparse.h sparse-base-lu.h SparseCmplxLU.h SparsedbleLU.h \ sparse-base-chol.h SparseCmplxCHOL.h SparsedbleCHOL.h \ - Sparse-op-defs.h SparseType.h \ + SparseCmplxQR.h SparseQR.h Sparse-op-defs.h SparseType.h \ int8NDArray.h uint8NDArray.h int16NDArray.h uint16NDArray.h \ int32NDArray.h uint32NDArray.h int64NDArray.h uint64NDArray.h \ intNDArray.h @@ -96,7 +96,8 @@ dbleDET.cc dbleHESS.cc dbleLU.cc dbleQR.cc dbleQRP.cc \ dbleSCHUR.cc dbleSVD.cc boolSparse.cc CSparse.cc dSparse.cc \ MSparse.cc Sparse.cc SparseCmplxLU.cc SparsedbleLU.cc \ - SparseCmplxCHOL.cc SparsedbleCHOL.cc SparseType.cc \ + SparseCmplxCHOL.cc SparsedbleCHOL.cc \ + SparseCmplxQR.cc SparseQR.cc SparseType.cc \ int8NDArray.cc uint8NDArray.cc int16NDArray.cc uint16NDArray.cc \ int32NDArray.cc uint32NDArray.cc int64NDArray.cc uint64NDArray.cc diff --git a/liboctave/SparseCmplxQR.cc b/liboctave/SparseCmplxQR.cc new file mode 100644 --- /dev/null +++ b/liboctave/SparseCmplxQR.cc @@ -0,0 +1,676 @@ +/* + +Copyright (C) 2005 David Bateman + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include + +#include "lo-error.h" +#include "SparseCmplxQR.h" + +SparseComplexQR::SparseComplexQR_rep::SparseComplexQR_rep +(const SparseComplexMatrix& a, int order) +{ +#ifdef HAVE_CXSPARSE + // cast away const on A, with full knowledge that CSparse won't touch it + CXSPARSE_ZNAME (cs) A; + A.nzmax = a.nnz (); + A.m = a.rows (); + A.n = a.cols (); + nrows = A.m; + // Cast away const on A, with full knowledge that CSparse won't touch it + // Prevents the methods below making a copy of the data. + A.p = const_cast(a.cidx ()); + A.i = const_cast(a.ridx ()); + A.x = const_cast(reinterpret_cast + (a.data ())); + A.nz = -1; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + S = CXSPARSE_ZNAME (cs_sqr) (&A, order, 1); + N = CXSPARSE_ZNAME (cs_qr) (&A, S); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + if (!N) + (*current_liboctave_error_handler) + ("SparseComplexQR: sparse matrix QR factorization filled"); + count = 1; +#else + (*current_liboctave_error_handler) + ("SparseComplexQR: sparse matrix QR factorization not implemented"); +#endif +} + +SparseComplexQR::SparseComplexQR_rep::~SparseComplexQR_rep (void) +{ +#ifdef HAVE_CXSPARSE + CXSPARSE_ZNAME (cs_sfree) (S); + CXSPARSE_ZNAME (cs_nfree) (N); +#endif +} + +SparseComplexMatrix +SparseComplexQR::SparseComplexQR_rep::V (void) const +{ +#ifdef HAVE_CXSPARSE + // Drop zeros from V and sort + // XXX FIXME XXX Is the double transpose to sort necessary? + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_dropzeros) (N->L); + CXSPARSE_ZNAME (cs) *D = CXSPARSE_ZNAME (cs_transpose) (N->L, 1); + CXSPARSE_ZNAME (cs_spfree) (N->L); + N->L = CXSPARSE_ZNAME (cs_transpose) (D, 1); + CXSPARSE_ZNAME (cs_spfree) (D); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + octave_idx_type nc = N->L->n; + octave_idx_type nz = N->L->nzmax; + SparseComplexMatrix ret (N->L->m, nc, nz); + for (octave_idx_type j = 0; j < nc+1; j++) + ret.xcidx (j) = N->L->p[j]; + for (octave_idx_type j = 0; j < nz; j++) + { + ret.xridx (j) = N->L->i[j]; + ret.xdata (j) = reinterpret_cast(N->L->x)[j]; + } + return ret; +#else + return SparseComplexMatrix (); +#endif +} + +ColumnVector +SparseComplexQR::SparseComplexQR_rep::Pinv (void) const +{ +#ifdef HAVE_CXSPARSE + ColumnVector ret(N->L->m); + for (octave_idx_type i = 0; i < N->L->m; i++) + ret.xelem(i) = S->Pinv[i]; + return ret; +#else + return ColumnVector (); +#endif +} + +ColumnVector +SparseComplexQR::SparseComplexQR_rep::P (void) const +{ +#ifdef HAVE_CXSPARSE + ColumnVector ret(N->L->m); + for (octave_idx_type i = 0; i < N->L->m; i++) + ret.xelem(S->Pinv[i]) = i; + return ret; +#else + return ColumnVector (); +#endif +} + +SparseComplexMatrix +SparseComplexQR::SparseComplexQR_rep::R (const bool econ) const +{ +#ifdef HAVE_CXSPARSE + // Drop zeros from R and sort + // XXX FIXME XXX Is the double transpose to sort necessary? + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_dropzeros) (N->U); + CXSPARSE_ZNAME (cs) *D = CXSPARSE_ZNAME (cs_transpose) (N->U, 1); + CXSPARSE_ZNAME (cs_spfree) (N->U); + N->U = CXSPARSE_ZNAME (cs_transpose) (D, 1); + CXSPARSE_ZNAME (cs_spfree) (D); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + octave_idx_type nc = N->U->n; + octave_idx_type nz = N->U->nzmax; + SparseComplexMatrix ret ((econ ? (nc > nrows ? nrows : nc) : nrows), nc, nz); + for (octave_idx_type j = 0; j < nc+1; j++) + ret.xcidx (j) = N->U->p[j]; + for (octave_idx_type j = 0; j < nz; j++) + { + ret.xridx (j) = N->U->i[j]; + ret.xdata (j) = reinterpret_cast(N->U->x)[j]; + } + return ret; +#else + return SparseComplexMatrix (); +#endif +} + +ComplexMatrix +SparseComplexQR::SparseComplexQR_rep::C (const ComplexMatrix &b) const +{ +#ifdef HAVE_CXSPARSE + octave_idx_type b_nr = b.rows(); + octave_idx_type b_nc = b.cols(); + octave_idx_type nc = N->L->n; + octave_idx_type nr = nrows; + const double _Complex *bvec = + reinterpret_cast(b.fortran_vec()); + ComplexMatrix ret(b_nr,b_nc); + Complex *vec = ret.fortran_vec(); + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) ("matrix dimension mismatch"); + else + { + OCTAVE_LOCAL_BUFFER (Complex, buf, S->m2); + for (volatile octave_idx_type j = 0, idx = 0; j < b_nc; j++, idx+=b_nr) + { + OCTAVE_QUIT; + volatile octave_idx_type nm = (nr < nc ? nr : nc); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_ipvec) (b_nr, S->Pinv, bvec + idx, + reinterpret_cast(buf)); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type i = 0; i < nm; i++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_happly) + (N->L, i, N->B[i], reinterpret_cast(buf)); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + for (octave_idx_type i = 0; i < b_nr; i++) + vec[i+idx] = buf[i]; + } + } + return ret; +#else + return ComplexMatrix (); +#endif +} + +ComplexMatrix +qrsolve(const SparseComplexMatrix&a, const Matrix &b, octave_idx_type &info) +{ +#ifdef HAVE_CXSPARSE + octave_idx_type nr = a.rows(); + octave_idx_type nc = a.cols(); + octave_idx_type b_nc = b.cols(); + octave_idx_type b_nr = b.rows(); + ComplexMatrix x; + info = 0; + + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) + ("matrix dimension mismatch in solution of minimum norm problem"); + else if (nr >= nc) + { + SparseComplexQR q (a, 2); + if (! q.ok ()) + { + info = -1; + return ComplexMatrix(); + } + x.resize(nc, b_nc); + double _Complex *vec = reinterpret_cast + (x.fortran_vec()); + OCTAVE_LOCAL_BUFFER (double _Complex, buf, q.S()->m2); + OCTAVE_LOCAL_BUFFER (Complex, Xx, b_nr); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + Xx[j] = b.xelem(j,i); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_ipvec) + (nr, q.S()->Pinv, reinterpret_cast(Xx), buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_ZNAME (cs_ipvec) (nc, q.S()->Q, buf, vec + idx); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + } + else + { + SparseComplexMatrix at = a.hermitian(); + SparseComplexQR q (at, 2); + if (! q.ok ()) + { + info = -1; + return ComplexMatrix(); + } + x.resize(nc, b_nc); + double _Complex *vec = reinterpret_cast + (x.fortran_vec()); + OCTAVE_LOCAL_BUFFER (double _Complex, buf, + nc > q.S()->m2 ? nc : q.S()->m2); + OCTAVE_LOCAL_BUFFER (Complex, Xx, b_nr); + OCTAVE_LOCAL_BUFFER (Complex, B, nr); + for (octave_idx_type i = 0; i < nr; i++) + B[i] = conj (reinterpret_cast(q.N()->B) [i]); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + Xx[j] = b.xelem(j,i); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_pvec) + (nr, q.S()->Q, reinterpret_cast(Xx), buf); + CXSPARSE_ZNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + CXSPARSE_ZNAME (cs_happly) + (q.N()->L, j, reinterpret_cast(B)[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_pvec) (nc, q.S()->Pinv, buf, vec + idx); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + } + + return x; +#else + return ComplexMatrix (); +#endif +} + +SparseComplexMatrix +qrsolve(const SparseComplexMatrix&a, const SparseMatrix &b, octave_idx_type &info) +{ +#ifdef HAVE_CXSPARSE + octave_idx_type nr = a.rows(); + octave_idx_type nc = a.cols(); + octave_idx_type b_nc = b.cols(); + octave_idx_type b_nr = b.rows(); + SparseComplexMatrix x; + volatile octave_idx_type ii, x_nz; + info = 0; + + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) + ("matrix dimension mismatch in solution of minimum norm problem"); + else if (nr >= nc) + { + SparseComplexQR q (a, 2); + if (! q.ok ()) + { + info = -1; + return SparseComplexMatrix(); + } + x = SparseComplexMatrix (nc, b_nc, b.nzmax()); + x.xcidx(0) = 0; + x_nz = b.nzmax(); + ii = 0; + OCTAVE_LOCAL_BUFFER (Complex, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double _Complex, buf, q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + Xx[j] = b.xelem(j,i); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_ipvec) + (nr, q.S()->Pinv, reinterpret_cast(Xx), buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_ZNAME (cs_ipvec) (nc, q.S()->Q, buf, + reinterpret_cast(Xx)); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (octave_idx_type j = 0; j < nc; j++) + { + Complex tmp = Xx[j]; + if (tmp != 0.0) + { + if (ii == x_nz) + { + // Resize the sparse matrix + octave_idx_type sz = x_nz * (b_nc - i) / b_nc; + sz = (sz > 10 ? sz : 10) + x_nz; + x.change_capacity (sz); + x_nz = sz; + } + x.xdata(ii) = tmp; + x.xridx(ii++) = j; + } + } + x.xcidx(i+1) = ii; + } + } + else + { + SparseComplexMatrix at = a.hermitian(); + SparseComplexQR q (at, 2); + if (! q.ok ()) + { + info = -1; + return SparseComplexMatrix(); + } + x = SparseComplexMatrix (nc, b_nc, b.nzmax()); + x.xcidx(0) = 0; + x_nz = b.nzmax(); + ii = 0; + OCTAVE_LOCAL_BUFFER (Complex, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double _Complex, buf, + nc > q.S()->m2 ? nc : q.S()->m2); + OCTAVE_LOCAL_BUFFER (Complex, B, nr); + for (octave_idx_type i = 0; i < nr; i++) + B[i] = conj (reinterpret_cast(q.N()->B) [i]); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + Xx[j] = b.xelem(j,i); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_pvec) + (nr, q.S()->Q, reinterpret_cast(Xx), buf); + CXSPARSE_ZNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_happly) + (q.N()->L, j, reinterpret_cast(B)[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_pvec) (nc, q.S()->Pinv, buf, + reinterpret_cast(Xx)); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (octave_idx_type j = 0; j < nc; j++) + { + Complex tmp = Xx[j]; + if (tmp != 0.0) + { + if (ii == x_nz) + { + // Resize the sparse matrix + octave_idx_type sz = x_nz * (b_nc - i) / b_nc; + sz = (sz > 10 ? sz : 10) + x_nz; + x.change_capacity (sz); + x_nz = sz; + } + x.xdata(ii) = tmp; + x.xridx(ii++) = j; + } + } + x.xcidx(i+1) = ii; + } + } + + x.maybe_compress (); + return x; +#else + return SparseComplexMatrix (); +#endif +} + +ComplexMatrix +qrsolve(const SparseComplexMatrix&a, const ComplexMatrix &b, octave_idx_type &info) +{ +#ifdef HAVE_CXSPARSE + octave_idx_type nr = a.rows(); + octave_idx_type nc = a.cols(); + octave_idx_type b_nc = b.cols(); + octave_idx_type b_nr = b.rows(); + const double _Complex *bvec = + reinterpret_cast(b.fortran_vec()); + ComplexMatrix x; + info = 0; + + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) + ("matrix dimension mismatch in solution of minimum norm problem"); + else if (nr >= nc) + { + SparseComplexQR q (a, 2); + if (! q.ok ()) + { + info = -1; + return ComplexMatrix(); + } + x.resize(nc, b_nc); + double _Complex *vec = reinterpret_cast + (x.fortran_vec()); + OCTAVE_LOCAL_BUFFER (double _Complex, buf, q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0, bidx = 0; i < b_nc; + i++, idx+=nc, bidx+=b_nr) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_ipvec) (nr, q.S()->Pinv, bvec + bidx, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_ZNAME (cs_ipvec) (nc, q.S()->Q, buf, vec + idx); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + } + else + { + SparseComplexMatrix at = a.hermitian(); + SparseComplexQR q (at, 2); + if (! q.ok ()) + { + info = -1; + return ComplexMatrix(); + } + x.resize(nc, b_nc); + double _Complex *vec = reinterpret_cast + (x.fortran_vec()); + OCTAVE_LOCAL_BUFFER (double _Complex, buf, + nc > q.S()->m2 ? nc : q.S()->m2); + OCTAVE_LOCAL_BUFFER (Complex, B, nr); + for (octave_idx_type i = 0; i < nr; i++) + B[i] = conj (reinterpret_cast(q.N()->B) [i]); + for (volatile octave_idx_type i = 0, idx = 0, bidx = 0; i < b_nc; + i++, idx+=nc, bidx+=b_nr) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_pvec) (nr, q.S()->Q, bvec + bidx, buf); + CXSPARSE_ZNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_happly) + (q.N()->L, j, reinterpret_cast(B)[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_pvec) (nc, q.S()->Pinv, buf, vec + idx); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + } + + return x; +#else + return ComplexMatrix (); +#endif +} + +SparseComplexMatrix +qrsolve(const SparseComplexMatrix&a, const SparseComplexMatrix &b, octave_idx_type &info) +{ +#ifdef HAVE_CXSPARSE + octave_idx_type nr = a.rows(); + octave_idx_type nc = a.cols(); + octave_idx_type b_nc = b.cols(); + octave_idx_type b_nr = b.rows(); + SparseComplexMatrix x; + volatile octave_idx_type ii, x_nz; + info = 0; + + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) + ("matrix dimension mismatch in solution of minimum norm problem"); + else if (nr >= nc) + { + SparseComplexQR q (a, 2); + if (! q.ok ()) + { + info = -1; + return SparseComplexMatrix(); + } + x = SparseComplexMatrix (nc, b_nc, b.nzmax()); + x.xcidx(0) = 0; + x_nz = b.nzmax(); + ii = 0; + OCTAVE_LOCAL_BUFFER (Complex, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double _Complex, buf, q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + Xx[j] = b.xelem(j,i); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_ipvec) + (nr, q.S()->Pinv, reinterpret_cast(Xx), buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_ZNAME (cs_ipvec) (nc, q.S()->Q, buf, + reinterpret_cast(Xx)); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (octave_idx_type j = 0; j < nc; j++) + { + Complex tmp = Xx[j]; + if (tmp != 0.0) + { + if (ii == x_nz) + { + // Resize the sparse matrix + octave_idx_type sz = x_nz * (b_nc - i) / b_nc; + sz = (sz > 10 ? sz : 10) + x_nz; + x.change_capacity (sz); + x_nz = sz; + } + x.xdata(ii) = tmp; + x.xridx(ii++) = j; + } + } + x.xcidx(i+1) = ii; + } + } + else + { + SparseComplexMatrix at = a.hermitian(); + SparseComplexQR q (at, 2); + if (! q.ok ()) + { + info = -1; + return SparseComplexMatrix(); + } + x = SparseComplexMatrix (nc, b_nc, b.nzmax()); + x.xcidx(0) = 0; + x_nz = b.nzmax(); + ii = 0; + OCTAVE_LOCAL_BUFFER (Complex, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double _Complex, buf, + nc > q.S()->m2 ? nc : q.S()->m2); + OCTAVE_LOCAL_BUFFER (Complex, B, nr); + for (octave_idx_type i = 0; i < nr; i++) + B[i] = conj (reinterpret_cast(q.N()->B) [i]); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + Xx[j] = b.xelem(j,i); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_pvec) + (nr, q.S()->Q, reinterpret_cast(Xx), buf); + CXSPARSE_ZNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_happly) + (q.N()->L, j, reinterpret_cast(B)[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_ZNAME (cs_pvec) (nc, q.S()->Pinv, buf, + reinterpret_cast(Xx)); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (octave_idx_type j = 0; j < nc; j++) + { + Complex tmp = Xx[j]; + if (tmp != 0.0) + { + if (ii == x_nz) + { + // Resize the sparse matrix + octave_idx_type sz = x_nz * (b_nc - i) / b_nc; + sz = (sz > 10 ? sz : 10) + x_nz; + x.change_capacity (sz); + x_nz = sz; + } + x.xdata(ii) = tmp; + x.xridx(ii++) = j; + } + } + x.xcidx(i+1) = ii; + } + } + + x.maybe_compress (); + return x; +#else + return SparseComplexMatrix (); +#endif +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ + diff --git a/liboctave/SparseCmplxQR.h b/liboctave/SparseCmplxQR.h new file mode 100644 --- /dev/null +++ b/liboctave/SparseCmplxQR.h @@ -0,0 +1,146 @@ +/* + +Copyright (C) 2005 David Bateman + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. + +*/ + +#if !defined (sparse_cmplx_QR_h) +#define sparse_cmplx_QR_h 1 + +#include + +#include "dMatrix.h" +#include "CMatrix.h" +#include "dSparse.h" +#include "CSparse.h" +#include "oct-sparse.h" + +#ifdef IDX_TYPE_LONG +#define CXSPARSE_ZNAME(name) name ## _cl +#else +#define CXSPARSE_ZNAME(name) name ## _ci +#endif + +class +SparseComplexQR +{ +protected: + class SparseComplexQR_rep + { + public: + SparseComplexQR_rep (const SparseComplexMatrix& a, int order); + + ~SparseComplexQR_rep (void); +#ifdef HAVE_CXSPARSE + bool ok (void) const { return (N && S); } +#else + bool ok (void) const { return false; } +#endif + SparseComplexMatrix V (void) const; + + ColumnVector Pinv (void) const; + + ColumnVector P (void) const; + + SparseComplexMatrix R (const bool econ) const; + + ComplexMatrix C (const ComplexMatrix &b) const; + + int count; + + octave_idx_type nrows; +#ifdef HAVE_CXSPARSE + CXSPARSE_ZNAME (css) *S; + + CXSPARSE_ZNAME (csn) *N; +#endif + }; +private: + SparseComplexQR_rep *rep; + +public: + SparseComplexQR (void) : + rep (new SparseComplexQR_rep (SparseComplexMatrix(), -1)) { } + + SparseComplexQR (const SparseComplexMatrix& a, int order = -1) : + rep (new SparseComplexQR_rep (a, order)) { } + + SparseComplexQR (const SparseComplexQR& a) : rep (a.rep) { rep->count++; } + + ~SparseComplexQR (void) + { + if (--rep->count <= 0) + delete rep; + } + + SparseComplexQR& operator = (const SparseComplexQR& a) + { + if (this != &a) + { + if (--rep->count <= 0) + delete rep; + + rep = a.rep; + rep->count++; + } + return *this; + } + + bool ok (void) const { return rep->ok(); } + + SparseComplexMatrix V (void) const { return rep->V(); } + + ColumnVector Pinv (void) const { return rep->P(); } + + ColumnVector P (void) const { return rep->P(); } + + SparseComplexMatrix R (const bool econ = false) const + { return rep->R(econ); } + + ComplexMatrix C (const ComplexMatrix &b) const { return rep->C(b); } + + friend ComplexMatrix qrsolve (const SparseComplexMatrix &a, const Matrix &b, + octave_idx_type &info); + + friend SparseComplexMatrix qrsolve (const SparseComplexMatrix &a, + const SparseMatrix &b, + octave_idx_type &info); + + friend ComplexMatrix qrsolve (const SparseComplexMatrix &a, + const ComplexMatrix &b, + octave_idx_type &info); + + friend SparseComplexMatrix qrsolve (const SparseComplexMatrix &a, + const SparseComplexMatrix &b, + octave_idx_type &info); + +protected: +#ifdef HAVE_CXSPARSE + CXSPARSE_ZNAME (css) * S (void) { return rep->S; } + + CXSPARSE_ZNAME (csn) * N (void) { return rep->N; } +#endif +}; + +#endif + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff --git a/liboctave/SparseQR.cc b/liboctave/SparseQR.cc new file mode 100644 --- /dev/null +++ b/liboctave/SparseQR.cc @@ -0,0 +1,715 @@ +/* + +Copyright (C) 2005 David Bateman + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include + +#include "lo-error.h" +#include "SparseQR.h" + +SparseQR::SparseQR_rep::SparseQR_rep (const SparseMatrix& a, int order) +{ +#ifdef HAVE_CXSPARSE + CXSPARSE_DNAME (cs) A; + A.nzmax = a.nzmax (); + A.m = a.rows (); + A.n = a.cols (); + nrows = A.m; + // Cast away const on A, with full knowledge that CSparse won't touch it + // Prevents the methods below making a copy of the data. + A.p = const_cast(a.cidx ()); + A.i = const_cast(a.ridx ()); + A.x = const_cast(a.data ()); + A.nz = -1; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + S = CXSPARSE_DNAME (cs_sqr) (&A, order, 1); + N = CXSPARSE_DNAME (cs_qr) (&A, S); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + if (!N) + (*current_liboctave_error_handler) + ("SparseQR: sparse matrix QR factorization filled"); + count = 1; +#else + (*current_liboctave_error_handler) + ("SparseQR: sparse matrix QR factorization not implemented"); +#endif +} + +SparseQR::SparseQR_rep::~SparseQR_rep (void) +{ +#ifdef HAVE_CXSPARSE + CXSPARSE_DNAME (cs_sfree) (S); + CXSPARSE_DNAME (cs_nfree) (N); +#endif +} + +SparseMatrix +SparseQR::SparseQR_rep::V (void) const +{ +#ifdef HAVE_CXSPARSE + // Drop zeros from V and sort + // XXX FIXME XXX Is the double transpose to sort necessary? + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_dropzeros) (N->L); + CXSPARSE_DNAME (cs) *D = CXSPARSE_DNAME (cs_transpose) (N->L, 1); + CXSPARSE_DNAME (cs_spfree) (N->L); + N->L = CXSPARSE_DNAME (cs_transpose) (D, 1); + CXSPARSE_DNAME (cs_spfree) (D); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + octave_idx_type nc = N->L->n; + octave_idx_type nz = N->L->nzmax; + SparseMatrix ret (N->L->m, nc, nz); + for (octave_idx_type j = 0; j < nc+1; j++) + ret.xcidx (j) = N->L->p[j]; + for (octave_idx_type j = 0; j < nz; j++) + { + ret.xridx (j) = N->L->i[j]; + ret.xdata (j) = N->L->x[j]; + } + return ret; +#else + return SparseMatrix (); +#endif +} + +ColumnVector +SparseQR::SparseQR_rep::Pinv (void) const +{ +#ifdef HAVE_CXSPARSE + ColumnVector ret(N->L->m); + for (octave_idx_type i = 0; i < N->L->m; i++) + ret.xelem(i) = S->Pinv[i]; + return ret; +#else + return ColumnVector (); +#endif +} + +ColumnVector +SparseQR::SparseQR_rep::P (void) const +{ +#ifdef HAVE_CXSPARSE + ColumnVector ret(N->L->m); + for (octave_idx_type i = 0; i < N->L->m; i++) + ret.xelem(S->Pinv[i]) = i; + return ret; +#else + return ColumnVector (); +#endif +} + +SparseMatrix +SparseQR::SparseQR_rep::R (const bool econ) const +{ +#ifdef HAVE_CXSPARSE + // Drop zeros from R and sort + // XXX FIXME XXX Is the double transpose to sort necessary? + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_dropzeros) (N->U); + CXSPARSE_DNAME (cs) *D = CXSPARSE_DNAME (cs_transpose) (N->U, 1); + CXSPARSE_DNAME (cs_spfree) (N->U); + N->U = CXSPARSE_DNAME (cs_transpose) (D, 1); + CXSPARSE_DNAME (cs_spfree) (D); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + octave_idx_type nc = N->U->n; + octave_idx_type nz = N->U->nzmax; + + SparseMatrix ret ((econ ? (nc > nrows ? nrows : nc) : nrows), nc, nz); + + for (octave_idx_type j = 0; j < nc+1; j++) + ret.xcidx (j) = N->U->p[j]; + for (octave_idx_type j = 0; j < nz; j++) + { + ret.xridx (j) = N->U->i[j]; + ret.xdata (j) = N->U->x[j]; + } + return ret; +#else + return SparseMatrix (); +#endif +} + +Matrix +SparseQR::SparseQR_rep::C (const Matrix &b) const +{ +#ifdef HAVE_CXSPARSE + octave_idx_type b_nr = b.rows(); + octave_idx_type b_nc = b.cols(); + octave_idx_type nc = N->L->n; + octave_idx_type nr = nrows; + const double *bvec = b.fortran_vec(); + Matrix ret(b_nr,b_nc); + double *vec = ret.fortran_vec(); + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) ("matrix dimension mismatch"); + else + { + OCTAVE_LOCAL_BUFFER (double, buf, S->m2); + for (volatile octave_idx_type j = 0, idx = 0; j < b_nc; j++, idx+=b_nr) + { + OCTAVE_QUIT; + volatile octave_idx_type nm = (nr < nc ? nr : nc); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + // cast away const on bvec, with full knowledge that CSparse + // won't touch it + CXSPARSE_DNAME (cs_ipvec) (b_nr, S->Pinv, bvec + idx, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (volatile octave_idx_type i = 0; i < nm; i++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (N->L, i, N->B[i], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + for (octave_idx_type i = 0; i < b_nr; i++) + vec[i+idx] = buf[i]; + } + } + return ret; +#else + return Matrix (); +#endif +} + +Matrix +qrsolve(const SparseMatrix&a, const Matrix &b, octave_idx_type& info) +{ +#ifdef HAVE_CXSPARSE + octave_idx_type nr = a.rows(); + octave_idx_type nc = a.cols(); + octave_idx_type b_nc = b.cols(); + octave_idx_type b_nr = b.rows(); + const double *bvec = b.fortran_vec(); + Matrix x; + info = 0; + + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) + ("matrix dimension mismatch in solution of minimum norm problem"); + else if (nr >= nc) + { + SparseQR q (a, 2); + if (! q.ok ()) + { + info = -1; + return Matrix(); + } + x.resize(nc, b_nc); + double *vec = x.fortran_vec(); + OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0, bidx = 0; i < b_nc; + i++, idx+=nc, bidx+=b_nr) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + // cast away const on bvec, with full knowledge that CSparse + // won't touch it + CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, bvec + bidx, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, vec + idx); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + } + else + { + SparseMatrix at = a.hermitian(); + SparseQR q (at, 2); + if (! q.ok ()) + { + info = -1; + return Matrix(); + } + x.resize(nc, b_nc); + double *vec = x.fortran_vec(); + OCTAVE_LOCAL_BUFFER (double, buf, nc > q.S()->m2 ? nc : q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0, bidx = 0; i < b_nc; + i++, idx+=nc, bidx+=b_nr) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + // cast away const on bvec, with full knowledge that CSparse + // won't touch it + CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, bvec + bidx, buf); + CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, vec + idx); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + } + + return x; +#else + return Matrix (); +#endif +} + +SparseMatrix +qrsolve(const SparseMatrix&a, const SparseMatrix &b, octave_idx_type &info) +{ +#ifdef HAVE_CXSPARSE + octave_idx_type nr = a.rows(); + octave_idx_type nc = a.cols(); + octave_idx_type b_nr = b.rows(); + octave_idx_type b_nc = b.cols(); + SparseMatrix x; + volatile octave_idx_type ii, x_nz; + info = 0; + + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) + ("matrix dimension mismatch in solution of minimum norm problem"); + else if (nr >= nc) + { + SparseQR q (a, 2); + if (! q.ok ()) + { + info = -1; + return SparseMatrix(); + } + x = SparseMatrix (nc, b_nc, b.nzmax()); + x.xcidx(0) = 0; + x_nz = b.nzmax(); + ii = 0; + OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + Xx[j] = b.xelem(j,i); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xx, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xx); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (octave_idx_type j = 0; j < nc; j++) + { + double tmp = Xx[j]; + if (tmp != 0.0) + { + if (ii == x_nz) + { + // Resize the sparse matrix + octave_idx_type sz = x_nz * (b_nc - i) / b_nc; + sz = (sz > 10 ? sz : 10) + x_nz; + x.change_capacity (sz); + x_nz = sz; + } + x.xdata(ii) = tmp; + x.xridx(ii++) = j; + } + } + x.xcidx(i+1) = ii; + } + } + else + { + SparseMatrix at = a.hermitian(); + SparseQR q (at, 2); + if (! q.ok ()) + { + info = -1; + return SparseMatrix(); + } + x = SparseMatrix (nc, b_nc, b.nzmax()); + x.xcidx(0) = 0; + x_nz = b.nzmax(); + ii = 0; + OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, buf, nc > q.S()->m2 ? nc : q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + Xx[j] = b.xelem(j,i); + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xx, buf); + CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xx); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (octave_idx_type j = 0; j < nc; j++) + { + double tmp = Xx[j]; + if (tmp != 0.0) + { + if (ii == x_nz) + { + // Resize the sparse matrix + octave_idx_type sz = x_nz * (b_nc - i) / b_nc; + sz = (sz > 10 ? sz : 10) + x_nz; + x.change_capacity (sz); + x_nz = sz; + } + x.xdata(ii) = tmp; + x.xridx(ii++) = j; + } + } + x.xcidx(i+1) = ii; + } + } + + x.maybe_compress (); + return x; +#else + return SparseMatrix (); +#endif +} + +ComplexMatrix +qrsolve(const SparseMatrix&a, const ComplexMatrix &b, octave_idx_type &info) +{ +#ifdef HAVE_CXSPARSE + octave_idx_type nr = a.rows(); + octave_idx_type nc = a.cols(); + octave_idx_type b_nc = b.cols(); + octave_idx_type b_nr = b.rows(); + ComplexMatrix x; + info = 0; + + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) + ("matrix dimension mismatch in solution of minimum norm problem"); + else if (nr >= nc) + { + SparseQR q (a, 2); + if (! q.ok ()) + { + info = -1; + return ComplexMatrix(); + } + x.resize(nc, b_nc); + Complex *vec = x.fortran_vec(); + OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + { + Complex c = b.xelem (j,i); + Xx[j] = std::real (c); + Xz[j] = std::imag (c); + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xx, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xx); + + CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xz, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xz); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (octave_idx_type j = 0; j < nc; j++) + vec[j+idx] = Complex (Xx[j], Xz[j]); + } + } + else + { + SparseMatrix at = a.hermitian(); + SparseQR q (at, 2); + if (! q.ok ()) + { + info = -1; + return ComplexMatrix(); + } + x.resize(nc, b_nc); + Complex *vec = x.fortran_vec(); + OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, buf, nc > q.S()->m2 ? nc : q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + { + Complex c = b.xelem (j,i); + Xx[j] = std::real (c); + Xz[j] = std::imag (c); + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xx, buf); + CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xx); + CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xz, buf); + CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xz); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (octave_idx_type j = 0; j < nc; j++) + vec[j+idx] = Complex (Xx[j], Xz[j]); + } + } + + return x; +#else + return ComplexMatrix (); +#endif +} + +SparseComplexMatrix +qrsolve(const SparseMatrix&a, const SparseComplexMatrix &b, octave_idx_type &info) +{ +#ifdef HAVE_CXSPARSE + octave_idx_type nr = a.rows(); + octave_idx_type nc = a.cols(); + octave_idx_type b_nr = b.rows(); + octave_idx_type b_nc = b.cols(); + SparseComplexMatrix x; + volatile octave_idx_type ii, x_nz; + info = 0; + + if (nr < 1 || nc < 1 || nr != b_nr) + (*current_liboctave_error_handler) + ("matrix dimension mismatch in solution of minimum norm problem"); + else if (nr >= nc) + { + SparseQR q (a, 2); + if (! q.ok ()) + { + info = -1; + return SparseComplexMatrix(); + } + x = SparseComplexMatrix (nc, b_nc, b.nzmax()); + x.xcidx(0) = 0; + x_nz = b.nzmax(); + ii = 0; + OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + { + Complex c = b.xelem (j,i); + Xx[j] = std::real (c); + Xz[j] = std::imag (c); + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xx, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xx); + CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xz, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = 0; j < nc; j++) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf); + CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xz); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (octave_idx_type j = 0; j < nc; j++) + { + Complex tmp = Complex (Xx[j], Xz[j]); + if (tmp != 0.0) + { + if (ii == x_nz) + { + // Resize the sparse matrix + octave_idx_type sz = x_nz * (b_nc - i) / b_nc; + sz = (sz > 10 ? sz : 10) + x_nz; + x.change_capacity (sz); + x_nz = sz; + } + x.xdata(ii) = tmp; + x.xridx(ii++) = j; + } + } + x.xcidx(i+1) = ii; + } + } + else + { + SparseMatrix at = a.hermitian(); + SparseQR q (at, 2); + if (! q.ok ()) + { + info = -1; + return SparseComplexMatrix(); + } + x = SparseComplexMatrix (nc, b_nc, b.nzmax()); + x.xcidx(0) = 0; + x_nz = b.nzmax(); + ii = 0; + OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc)); + OCTAVE_LOCAL_BUFFER (double, buf, nc > q.S()->m2 ? nc : q.S()->m2); + for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc) + { + OCTAVE_QUIT; + for (octave_idx_type j = 0; j < b_nr; j++) + { + Complex c = b.xelem (j,i); + Xx[j] = std::real (c); + Xz[j] = std::imag (c); + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xx, buf); + CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xx); + CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xz, buf); + CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + for (volatile octave_idx_type j = nr-1; j >= 0; j--) + { + OCTAVE_QUIT; + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xz); + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + for (octave_idx_type j = 0; j < nc; j++) + { + Complex tmp = Complex (Xx[j], Xz[j]); + if (tmp != 0.0) + { + if (ii == x_nz) + { + // Resize the sparse matrix + octave_idx_type sz = x_nz * (b_nc - i) / b_nc; + sz = (sz > 10 ? sz : 10) + x_nz; + x.change_capacity (sz); + x_nz = sz; + } + x.xdata(ii) = tmp; + x.xridx(ii++) = j; + } + } + x.xcidx(i+1) = ii; + } + } + + x.maybe_compress (); + return x; +#else + return SparseComplexMatrix (); +#endif +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff --git a/liboctave/SparseQR.h b/liboctave/SparseQR.h new file mode 100644 --- /dev/null +++ b/liboctave/SparseQR.h @@ -0,0 +1,142 @@ +/* + +Copyright (C) 2005 David Bateman + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. + +*/ + +#if !defined (sparse_QR_h) +#define sparse_QR_h 1 + +#include + +#include "dMatrix.h" +#include "CMatrix.h" +#include "dSparse.h" +#include "CSparse.h" +#include "oct-sparse.h" + +#ifdef IDX_TYPE_LONG +#define CXSPARSE_DNAME(name) name ## _dl +#else +#define CXSPARSE_DNAME(name) name ## _di +#endif + +class +SparseQR +{ +protected: + class SparseQR_rep + { + public: + SparseQR_rep (const SparseMatrix& a, int order); + + ~SparseQR_rep (void); +#ifdef HAVE_CXSPARSE + bool ok (void) const { return (N && S); } +#else + bool ok (void) const { return false; } +#endif + SparseMatrix V (void) const; + + ColumnVector Pinv (void) const; + + ColumnVector P (void) const; + + SparseMatrix R (const bool econ) const; + + Matrix C (const Matrix &b) const; + + int count; + + octave_idx_type nrows; +#ifdef HAVE_CXSPARSE + CXSPARSE_DNAME (css) *S; + + CXSPARSE_DNAME (csn) *N; +#endif + }; +private: + SparseQR_rep *rep; + +public: + SparseQR (void) : rep (new SparseQR_rep (SparseMatrix(), -1)) { } + + SparseQR (const SparseMatrix& a, int order = -1) : + rep (new SparseQR_rep (a, order)) { } + + SparseQR (const SparseQR& a) : rep (a.rep) { rep->count++; } + + ~SparseQR (void) + { + if (--rep->count <= 0) + delete rep; + } + + SparseQR& operator = (const SparseQR& a) + { + if (this != &a) + { + if (--rep->count <= 0) + delete rep; + + rep = a.rep; + rep->count++; + } + return *this; + } + + bool ok (void) const { return rep->ok(); } + + SparseMatrix V (void) const { return rep->V(); } + + ColumnVector Pinv (void) const { return rep->P(); } + + ColumnVector P (void) const { return rep->P(); } + + SparseMatrix R (const bool econ = false) const { return rep->R(econ); } + + Matrix C (const Matrix &b) const { return rep->C(b); } + + friend Matrix qrsolve (const SparseMatrix &a, const Matrix &b, + octave_idx_type &info); + + friend SparseMatrix qrsolve (const SparseMatrix &a, const SparseMatrix &b, + octave_idx_type &info); + + friend ComplexMatrix qrsolve (const SparseMatrix &a, const ComplexMatrix &b, + octave_idx_type &info); + + friend SparseComplexMatrix qrsolve (const SparseMatrix &a, + const SparseComplexMatrix &b, + octave_idx_type &info); + +protected: +#ifdef HAVE_CXSPARSE + CXSPARSE_DNAME (css) * S (void) { return rep->S; } + + CXSPARSE_DNAME (csn) * N (void) { return rep->N; } +#endif +}; + +#endif + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff --git a/liboctave/SparseType.cc b/liboctave/SparseType.cc --- a/liboctave/SparseType.cc +++ b/liboctave/SparseType.cc @@ -806,7 +806,7 @@ ("Hermitian/Symmetric Tridiagonal Sparse Matrix"); else if (typ == SparseType::Rectangular) (*current_liboctave_warning_handler) - ("Rectangular Sparse Matrix"); + ("Rectangular/Singular Sparse Matrix"); else if (typ == SparseType::Full) (*current_liboctave_warning_handler) ("Full Sparse Matrix"); diff --git a/liboctave/dSparse.cc b/liboctave/dSparse.cc --- a/liboctave/dSparse.cc +++ b/liboctave/dSparse.cc @@ -44,6 +44,7 @@ #include "oct-sparse.h" #include "sparse-util.h" #include "SparsedbleCHOL.h" +#include "SparseQR.h" #include "oct-sort.h" @@ -697,7 +698,7 @@ SparseMatrix SparseMatrix::dinverse (SparseType &mattyp, octave_idx_type& info, - double& rcond, const bool force, + double& rcond, const bool, const bool calccond) const { SparseMatrix retval; @@ -751,7 +752,7 @@ SparseMatrix SparseMatrix::tinverse (SparseType &mattyp, octave_idx_type& info, - double& rcond, const bool force, + double& rcond, const bool, const bool calccond) const { SparseMatrix retval; @@ -989,7 +990,7 @@ SparseMatrix SparseMatrix::inverse (SparseType &mattype, octave_idx_type& info, - double& rcond, int force, int calc_cond) const + double& rcond, int, int calc_cond) const { int typ = mattype.type (false); SparseMatrix ret; @@ -5154,7 +5155,6 @@ &Numeric, control, info) ; UMFPACK_DNAME (free_symbolic) (&Symbolic) ; -#ifdef HAVE_LSSOLVE rcond = Info (UMFPACK_RCOND); volatile double rcond_plus_one = rcond + 1.0; @@ -5173,9 +5173,7 @@ rcond); } - else -#endif - if (status < 0) + else if (status < 0) { (*current_liboctave_error_handler) ("SparseMatrix::solve numeric factorization failed"); @@ -5337,9 +5335,7 @@ ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", rcond); -#ifdef HAVE_LSSOLVE return retval; -#endif } cholmod_dense *X; @@ -5410,25 +5406,6 @@ } } -#ifndef HAVE_LSSOLVE - rcond = Info (UMFPACK_RCOND); - volatile double rcond_plus_one = rcond + 1.0; - - if (status == UMFPACK_WARNING_singular_matrix || - rcond_plus_one == 1.0 || xisnan (rcond)) - { - err = -2; - - if (sing_handler) - sing_handler (rcond); - else - (*current_liboctave_error_handler) - ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", - rcond); - - } -#endif - UMFPACK_DNAME (report_info) (control, info); UMFPACK_DNAME (free_numeric) (&Numeric); @@ -5589,9 +5566,7 @@ ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", rcond); -#ifdef HAVE_LSSOLVE return retval; -#endif } cholmod_sparse *X; @@ -5699,25 +5674,6 @@ retval.maybe_compress (); -#ifndef HAVE_LSSOLVE - rcond = Info (UMFPACK_RCOND); - volatile double rcond_plus_one = rcond + 1.0; - - if (status == UMFPACK_WARNING_singular_matrix || - rcond_plus_one == 1.0 || xisnan (rcond)) - { - err = -2; - - if (sing_handler) - sing_handler (rcond); - else - (*current_liboctave_error_handler) - ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", - rcond); - - } -#endif - UMFPACK_DNAME (report_info) (control, info); UMFPACK_DNAME (free_numeric) (&Numeric); @@ -5868,9 +5824,7 @@ ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", rcond); -#ifdef HAVE_LSSOLVE return retval; -#endif } cholmod_dense *X; @@ -5960,25 +5914,6 @@ retval (i, j) = Complex (Xx[i], Xz[i]); } -#ifndef HAVE_LSSOLVE - rcond = Info (UMFPACK_RCOND); - volatile double rcond_plus_one = rcond + 1.0; - - if (status == UMFPACK_WARNING_singular_matrix || - rcond_plus_one == 1.0 || xisnan (rcond)) - { - err = -2; - - if (sing_handler) - sing_handler (rcond); - else - (*current_liboctave_error_handler) - ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", - rcond); - - } -#endif - UMFPACK_DNAME (report_info) (control, info); UMFPACK_DNAME (free_numeric) (&Numeric); @@ -6140,9 +6075,7 @@ ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", rcond); -#ifdef HAVE_LSSOLVE return retval; -#endif } cholmod_sparse *X; @@ -6261,25 +6194,6 @@ retval.maybe_compress (); -#ifndef HAVE_LSSOLVE - rcond = Info (UMFPACK_RCOND); - volatile double rcond_plus_one = rcond + 1.0; - - if (status == UMFPACK_WARNING_singular_matrix || - rcond_plus_one == 1.0 || xisnan (rcond)) - { - err = -2; - - if (sing_handler) - sing_handler (rcond); - else - (*current_liboctave_error_handler) - ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", - rcond); - - } -#endif - UMFPACK_DNAME (report_info) (control, info); UMFPACK_DNAME (free_numeric) (&Numeric); @@ -6761,12 +6675,9 @@ } Matrix -SparseMatrix::lssolve (const Matrix& b, octave_idx_type& info, octave_idx_type& rank) const -{ - info = -1; - (*current_liboctave_error_handler) - ("SparseMatrix::lssolve not implemented yet"); - return Matrix (); +SparseMatrix::lssolve (const Matrix& b, octave_idx_type& info, octave_idx_type&) const +{ + return qrsolve (*this, b, info); } SparseMatrix @@ -6785,12 +6696,9 @@ } SparseMatrix -SparseMatrix::lssolve (const SparseMatrix& b, octave_idx_type& info, octave_idx_type& rank) const -{ - info = -1; - (*current_liboctave_error_handler) - ("SparseMatrix::lssolve not implemented yet"); - return SparseMatrix (); +SparseMatrix::lssolve (const SparseMatrix& b, octave_idx_type& info, octave_idx_type&) const +{ + return qrsolve (*this, b, info); } ComplexMatrix @@ -6809,12 +6717,9 @@ } ComplexMatrix -SparseMatrix::lssolve (const ComplexMatrix& b, octave_idx_type& info, octave_idx_type& rank) const -{ - info = -1; - (*current_liboctave_error_handler) - ("SparseMatrix::lssolve not implemented yet"); - return ComplexMatrix (); +SparseMatrix::lssolve (const ComplexMatrix& b, octave_idx_type& info, octave_idx_type&) const +{ + return qrsolve (*this, b, info); } SparseComplexMatrix @@ -6834,12 +6739,9 @@ SparseComplexMatrix SparseMatrix::lssolve (const SparseComplexMatrix& b, octave_idx_type& info, - octave_idx_type& rank) const -{ - info = -1; - (*current_liboctave_error_handler) - ("SparseMatrix::lssolve not implemented yet"); - return SparseComplexMatrix (); + octave_idx_type&) const +{ + return qrsolve (*this, b, info); } ColumnVector diff --git a/liboctave/oct-sparse.h b/liboctave/oct-sparse.h --- a/liboctave/oct-sparse.h +++ b/liboctave/oct-sparse.h @@ -42,26 +42,24 @@ #if defined (HAVE_UFSPARSE_COLAMD_H) #include -#elif defined (HAVE_UMFPACK_COLAMD_H) -#include +#elif defined (HAVE_COLAMD_COLAMD_H) +#include #elif defined (HAVE_COLAMD_H) #include #endif #if defined (HAVE_UFSPARSE_CCOLAMD_H) #include -#elif defined (HAVE_UMFPACK_CCOLAMD_H) -#include +#elif defined (HAVE_CCOLAMD_CCOLAMD_H) +#include #elif defined (HAVE_CCOLAMD_H) #include #endif -#if defined (HAVE_METIS_METIS_H) +#if defined (HAVE_UFSPARSE_METIS_H) +#include +#elif defined (HAVE_METIS_METIS_H) #include -#elif defined (HAVE_UFSPARSE_METIS_H) -#include -#elif defined (HAVE_UMFPACK_METIS_H) -#include #elif defined (HAVE_METIS_H) #include #endif @@ -69,11 +67,19 @@ #if defined (HAVE_UFSPARSE_CHOLMOD_H) #include #elif defined (HAVE_UMFPACK_CHOLMOD_H) -#include +#include #elif defined (HAVE_CHOLMOD_H) #include #endif +#if defined (HAVE_UFSPARSE_CXS_H) +#include +#elif defined (HAVE_CXSPARSE_CXS_H) +#include +#elif defined (HAVE_CXS_H) +#include +#endif + #if (defined (HAVE_UFSPARSE_CHOLMOD_H) \ || defined (HAVE_UMFPACK_CHOLMOD_H) \ || defined (HAVE_CHOLMOD_H)) diff --git a/scripts/ChangeLog b/scripts/ChangeLog --- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,15 @@ +2006-02-09 David Bateman + + * general/triu.m: Minimum change to allow sparse matrix. More needed + for arbitrary user type. + * general/tril.m: ditto. + * sparse/sprand.m : Doc fix. + * sparse/sprandn.m: Ditto. + * sparse/sprandsym.m: New function. + * audio/setaudio.m, general/cart2pol.m, general/cart2sph.m, + general/pol2cart.m, general/sph2cart.m, signal/freqz_plot.m: + Update for syntax error for latest texinfo.tex file. + 2006-02-02 John W. Eaton * plot/grid.m: Append ";\n" to "set grid" command. diff --git a/scripts/audio/setaudio.m b/scripts/audio/setaudio.m --- a/scripts/audio/setaudio.m +++ b/scripts/audio/setaudio.m @@ -18,7 +18,7 @@ ## 02110-1301, USA. ## -*- texinfo -*- -## @deftypefn {Function File} setaudio ([@var{w_type} [, @var{value}]]) +## @deftypefn {Function File} {} setaudio ([@var{w_type} [, @var{value}]]) ## Execute the shell command @samp{mixer [@var{w_type} [, @var{value}]]} ## @end deftypefn diff --git a/scripts/general/cart2pol.m b/scripts/general/cart2pol.m --- a/scripts/general/cart2pol.m +++ b/scripts/general/cart2pol.m @@ -18,8 +18,8 @@ ## 02110-1301, USA. ## -*- texinfo -*- -## @deftypefn {Function File} {} [@var{theta}, @var{r}] = cart2pol (@var{x}, @var{y}) -## @deftypefnx {Function File} {} [@var{theta}, @var{r}, @var{z}] = cart2pol (@var{x}, @var{y}, @var{z}) +## @deftypefn {Function File} {[@var{theta}, @var{r}] =} cart2pol (@var{x}, @var{y}) +## @deftypefnx {Function File} {[@var{theta}, @var{r}, @var{z}] =} cart2pol (@var{x}, @var{y}, @var{z}) ## Transform cartesian to polar or cylindrical coordinates. ## @var{x}, @var{y} (and @var{z}) must be of same shape. ## @var{theta} describes the angle relative to the x - axis. diff --git a/scripts/general/cart2sph.m b/scripts/general/cart2sph.m --- a/scripts/general/cart2sph.m +++ b/scripts/general/cart2sph.m @@ -18,7 +18,7 @@ ## 02110-1301, USA. ## -*- texinfo -*- -## @deftypefn {Function File} {} [@var{theta}, @var{phi}, @var{r}] = cart2sph (@var{x}, @var{y}, @var{z}) +## @deftypefn {Function File} {[@var{theta}, @var{phi}, @var{r}] =} cart2sph (@var{x}, @var{y}, @var{z}) ## Transform cartesian to spherical coordinates. ## @var{x}, @var{y} and @var{z} must be of same shape. ## @var{theta} describes the angle relative to the x - axis. diff --git a/scripts/general/pol2cart.m b/scripts/general/pol2cart.m --- a/scripts/general/pol2cart.m +++ b/scripts/general/pol2cart.m @@ -18,8 +18,8 @@ ## 02110-1301, USA. ## -*- texinfo -*- -## @deftypefn {Function File} {} [@var{x}, @var{y}] = pol2cart (@var{theta}, @var{r}) -## @deftypefnx {Function File} {} [@var{x}, @var{y}, @var{z}] = pol2cart (@var{theta}, @var{r}, @var{z}) +## @deftypefn {Function File} {[@var{x}, @var{y}] =} pol2cart (@var{theta}, @var{r}) +## @deftypefnx {Function File} {[@var{x}, @var{y}, @var{z}] =} pol2cart (@var{theta}, @var{r}, @var{z}) ## Transform polar or cylindrical to cartesian coordinates. ## @var{theta}, @var{r} (and @var{z}) must be of same shape. ## @var{theta} describes the angle relative to the x - axis. diff --git a/scripts/general/sph2cart.m b/scripts/general/sph2cart.m --- a/scripts/general/sph2cart.m +++ b/scripts/general/sph2cart.m @@ -18,7 +18,7 @@ ## 02110-1301, USA. ## -*- texinfo -*- -## @deftypefn {Function File} {} [@var{x}, @var{y}, @var{z}] = sph2cart (@var{theta}, @var{phi}, @var{r}) +## @deftypefn {Function File} {[@var{x}, @var{y}, @var{z}] =} sph2cart (@var{theta}, @var{phi}, @var{r}) ## Transform spherical to cartesian coordinates. ## @var{x}, @var{y} and @var{z} must be of same shape. ## @var{theta} describes the angle relative to the x-axis. diff --git a/scripts/general/tril.m b/scripts/general/tril.m --- a/scripts/general/tril.m +++ b/scripts/general/tril.m @@ -69,7 +69,11 @@ if (nargin > 0) [nr, nc] = size (x); - retval = zeros (nr, nc, class (x)); + if (isa (x, "sparse")) + retval = sparse (nr, nc); + else + retval = zeros (nr, nc, class (x)); + endif endif if (nargin == 1) diff --git a/scripts/general/triu.m b/scripts/general/triu.m --- a/scripts/general/triu.m +++ b/scripts/general/triu.m @@ -28,7 +28,11 @@ if (nargin > 0) [nr, nc] = size (x); - retval = zeros (nr, nc, class (x)); + if (isa (x, "sparse")) + retval = sparse (nr, nc); + else + retval = zeros (nr, nc, class (x)); + endif endif if (nargin == 1) diff --git a/scripts/signal/freqz_plot.m b/scripts/signal/freqz_plot.m --- a/scripts/signal/freqz_plot.m +++ b/scripts/signal/freqz_plot.m @@ -18,7 +18,7 @@ ## 02110-1301, USA. ## -*- texinfo -*- -## @deftypefn {Function File} freqz_plot (@var{w}, @var{h}) +## @deftypefn {Function File} {} freqz_plot (@var{w}, @var{h}) ## Plot the pass band, stop band and phase response of @var{h}. ## @end deftypefn diff --git a/scripts/sparse/sprand.m b/scripts/sparse/sprand.m --- a/scripts/sparse/sprand.m +++ b/scripts/sparse/sprand.m @@ -7,8 +7,8 @@ ## @deftypefnx {Function File} {} sprand (@var{s}) ## Generate a random sparse matrix. The size of the matrix will be ## @var{m} by @var{n}, with a density of values given by @var{d}. -## @var{d} should be between 0 and 1. Values will be normally -## distributed with mean of zero and variance 1. +## @var{d} should be between 0 and 1. Values will be uniformly +## distributed between 0 and 1. ## ## Note: sometimes the actual density may be a bit smaller than @var{d}. ## This is unlikely to happen for large really sparse matrices. diff --git a/scripts/sparse/sprandn.m b/scripts/sparse/sprandn.m --- a/scripts/sparse/sprandn.m +++ b/scripts/sparse/sprandn.m @@ -3,8 +3,8 @@ ## This program is free software and is in the public domain ## -*- texinfo -*- -## @deftypefn {Function File} {} sprand (@var{m}, @var{n}, @var{d}) -## @deftypefnx {Function File} {} sprand (@var{s}) +## @deftypefn {Function File} {} sprandn (@var{m}, @var{n}, @var{d}) +## @deftypefnx {Function File} {} sprandn (@var{s}) ## Generate a random sparse matrix. The size of the matrix will be ## @var{m} by @var{n}, with a density of values given by @var{d}. ## @var{d} should be between 0 and 1. Values will be normally diff --git a/scripts/sparse/sprandsym.m b/scripts/sparse/sprandsym.m new file mode 100644 --- /dev/null +++ b/scripts/sparse/sprandsym.m @@ -0,0 +1,75 @@ +## Copyright (C) 2004 David Bateman & Andy Adler +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +## 02110-1301 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} sprandsym (@var{n}, @var{d}) +## @deftypefnx {Function File} {} sprandsym (@var{s}) +## Generate a symmetric random sparse matrix. The size of the matrix will be +## @var{n} by @var{n}, with a density of values given by @var{d}. +## @var{d} should be between 0 and 1. Values will be normally +## distributed with mean of zero and variance 1. +## +## Note: sometimes the actual density may be a bit smaller than @var{d}. +## This is unlikely to happen for large really sparse matrices. +## +## If called with a single matrix argument, a random sparse matrix is +## generated wherever the matrix @var{S} is non-zero in its lower +## triangular part. +## @end deftypefn +## @seealso{sprand, sprandn} + +function S = sprandsym(n,d) + if nargin == 1 + [i,j,v,nr,nc] = spfind(tril(n)); + S = sparse(i,j,randn(size(v)),nr,nc); + S = S + tril(S,-1)'; + elseif nargin == 2 + m1 = floor(n/2); + n1 = m1 + 1; + mn1 = m1*n1; + k1 = round(d*mn1); + idx1=unique(fix(rand(min(k1*1.01,k1+10),1)*mn1))+1; + # idx contains random numbers in [1,mn] + # generate 1% or 10 more random values than necessary + # in order to reduce the probability that there are less than k + # distinct values; + # maybe a better strategy could be used + # but I don't think it's worth the price + k1 = min(length(idx1),k1); # actual number of entries in S + j1 = floor((idx1(1:k1)-1)/m1); + i1 = idx1(1:k1) - j1*m1; + + n2 = ceil(n/2); + nn2 = n2*n2; + k2 = round(d*nn2); + idx2=unique(fix(rand(min(k2*1.01,k1+10),1)*nn2))+1; + k2 = min(length(idx2),k2); + j2 = floor((idx2(1:k2)-1)/n2); + i2 = idx2(1:k2) - j2*n2; + + if isempty(i1) && isempty(i2) + S = sparse(n,n); + else + S1 = sparse(i1,j1+1,randn(k1,1),m1,n1); + S = [tril(S1), sparse(m1,m1); ... + sparse(i2,j2+1,randn(k2,1),n2,n2), triu(S1,1)']; + S = S + tril(S,-1)'; + endif + else + usage("sprandsym(n,density) OR sprandsym(S)"); + endif +endfunction diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,15 @@ +2006-02-09 David Bateman + + * DLD-FUNCTIONS/spqr.cc: New file for sparse QR and dmperm based on + CSparse. + * DLD-FUNCTIONS/matrix_type.cc (Fmatrix_type): dintinguish between + rectangular and singular matrices. Add tests. + * DLD-FUNCTIONS/luinc.cc: Add tests. + * DLD-FUNCTIONS/spkron.cc: Ditto. + * Makefile.in (DLD_XSRC): Add spqr.cc. + (OCT_LINK_DEPS): Add CSSPARSE_LIBS. + * sparse-xdiv.h: Remove conditio of lssolve. + 2006-02-08 John W. Eaton * parse.y (frob_function): Clear ID_NAME from top_level symbol diff --git a/src/DLD-FUNCTIONS/luinc.cc b/src/DLD-FUNCTIONS/luinc.cc --- a/src/DLD-FUNCTIONS/luinc.cc +++ b/src/DLD-FUNCTIONS/luinc.cc @@ -279,6 +279,28 @@ } /* + +%!test +%! a=sparse([1,2,0,0;0,1,2,0;1e-14,0,3,0;0,0,0,1]); +%! [l,u]=luinc(a,1e-10); +%! assert(l*u, sparse([1,2,0,0;0,1,2,0;0,0,3,0;0,0,0,1]),1e-10); +%! opts.droptol=1e-10; +%! [l,u]=luinc(a,opts); +%! assert(l*u, sparse([1,2,0,0;0,1,2,0;0,0,3,0;0,0,0,1]),1e-10); + +%!test +%! a=sparse([1i,2,0,0;0,1,2,0;1e-14,0,3,0;0,0,0,1]); +%! [l,u]=luinc(a,1e-10); +%! assert(l*u, sparse([1i,2,0,0;0,1,2,0;0,0,3,0;0,0,0,1]),1e-10); +%! opts.droptol=1e-10; +%! [l,u]=luinc(a,opts); +%! assert(l*u, sparse([1i,2,0,0;0,1,2,0;0,0,3,0;0,0,0,1]),1e-10); + +%!error splu(sparse([1i,2,0,0;0,1,2,0;1e-14,0,3,0;0,0,0,1])); + +*/ + +/* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** diff --git a/src/DLD-FUNCTIONS/matrix_type.cc b/src/DLD-FUNCTIONS/matrix_type.cc --- a/src/DLD-FUNCTIONS/matrix_type.cc +++ b/src/DLD-FUNCTIONS/matrix_type.cc @@ -157,6 +157,13 @@ retval = octave_value ("Tridiagonal Positive Definite"); else if (typ == SparseType::Hermitian) retval = octave_value ("Positive Definite"); + else if (typ == SparseType::Rectangular) + { + if (args(0).rows() == args(0).columns()) + retval = octave_value ("Singular"); + else + retval = octave_value ("Rectangular"); + } else if (typ == SparseType::Full) retval = octave_value ("Full"); else @@ -284,6 +291,66 @@ } /* + +%!assert(matrix_type(speye(10,10)),"Diagonal"); +%!assert(matrix_type(speye(10,10)([2:10,1],:)),"Permuted Diagonal"); +%!assert(matrix_type([[speye(10,10);sparse(1,10)],[1;sparse(9,1);1]]),"Upper"); +%!assert(matrix_type([[speye(10,10);sparse(1,10)],[1;sparse(9,1);1]](:,[2,1,3:11])),"Permuted Upper"); +%!assert(matrix_type([speye(10,10),sparse(10,1);1,sparse(1,9),1]),"Lower"); +%!assert(matrix_type([speye(10,10),sparse(10,1);1,sparse(1,9),1]([2,1,3:11],:)),"Permuted Lower"); +%!test +%! bnd=spparms("bandden"); +%! spparms("bandden",0.5); +%! a = spdiags(randn(10,3),[-1,0,1],10,10); +%! assert(matrix_type(a),"Tridiagonal"); +%! assert(matrix_type(abs(a')+abs(a)),"Tridiagonal Positive Definite"); +%! spparms("bandden",bnd); +%!test +%! bnd=spparms("bandden"); +%! spparms("bandden",0.5); +%! a = spdiags(randn(10,4),[-2:1],10,10); +%! assert(matrix_type(a),"Banded"); +%! assert(matrix_type(a'*a),"Banded Positive Definite"); +%! spparms("bandden",bnd); +%!test +%! a=[speye(10,10),[sparse(9,1);1];-1,sparse(1,9),1]; +%! assert(matrix_type(a),"Full"); +%! assert(matrix_type(a'*a),"Positive Definite"); +%!assert(matrix_type(speye(10,11)),"Rectangular"); + +%!assert(matrix_type(1i*speye(10,10)),"Diagonal"); +%!assert(matrix_type(1i*speye(10,10)([2:10,1],:)),"Permuted Diagonal"); +%!assert(matrix_type([[speye(10,10);sparse(1,10)],[1i;sparse(9,1);1]]),"Upper"); +%!assert(matrix_type([[speye(10,10);sparse(1,10)],[1i;sparse(9,1);1]](:,[2,1,3:11])),"Permuted Upper"); +%!assert(matrix_type([speye(10,10),sparse(10,1);1i,sparse(1,9),1]),"Lower"); +%!assert(matrix_type([speye(10,10),sparse(10,1);1i,sparse(1,9),1]([2,1,3:11],:)),"Permuted Lower"); +%!test +%! bnd=spparms("bandden"); +%! spparms("bandden",0.5); +%! assert(matrix_type(spdiags(1i*randn(10,3),[-1,0,1],10,10)),"Tridiagonal"); +%! a = 1i*randn(9,1);a=[[a;0],ones(10,1),[0;-a]]; +%! assert(matrix_type(spdiags(a,[-1,0,1],10,10)),"Tridiagonal Positive Definite"); +%! spparms("bandden",bnd); +%!test +%! bnd=spparms("bandden"); +%! spparms("bandden",0.5); +%! assert(matrix_type(spdiags(1i*randn(10,4),[-2:1],10,10)),"Banded"); +%! a = 1i*randn(9,2);a=[[a;[0,0]],ones(10,1),[[0;-a(:,2)],[0;0;-a(1:8,1)]]]; +%! assert(matrix_type(spdiags(a,[-2:2],10,10)),"Banded Positive Definite"); +%! spparms("bandden",bnd); +%!test +%! a=[speye(10,10),[sparse(9,1);1i];-1,sparse(1,9),1]; +%! assert(matrix_type(a),"Full"); +%! assert(matrix_type(a'*a),"Positive Definite"); +%!assert(matrix_type(speye(10,11)),"Rectangular"); + +%!test +%! a = matrix_type(spdiags(randn(10,3),[-1,0,1],10,10),"Singular"); +%! assert(matrix_type(a),"Singular"); + +*/ + +/* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** diff --git a/src/DLD-FUNCTIONS/spkron.cc b/src/DLD-FUNCTIONS/spkron.cc --- a/src/DLD-FUNCTIONS/spkron.cc +++ b/src/DLD-FUNCTIONS/spkron.cc @@ -138,3 +138,16 @@ return retval; } + +/* + +%!assert(spkron(spdiag([1,2,3]),spdiag([1,2,3])),sparse(kron(diag([1,2,3]),diag([1,2,3])))) +%!assert(spkron(spdiag([1i,2,3]),spdiag([1i,2,3])),sparse(kron(diag([1i,2,3]),diag([1i,2,3])))) + +*/ + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff --git a/src/DLD-FUNCTIONS/spqr.cc b/src/DLD-FUNCTIONS/spqr.cc new file mode 100644 --- /dev/null +++ b/src/DLD-FUNCTIONS/spqr.cc @@ -0,0 +1,339 @@ +/* + +Copyright (C) 2005 David Bateman +Copyright (C) 1998-2005 Andy Adler + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if HAVE_CXSPARSE +#include +#endif + +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "oct-obj.h" +#include "utils.h" + +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" +#include "SparseQR.h" +#include "SparseCmplxQR.h" + +#ifdef IDX_TYPE_LONG +#define CSSPARSE_NAME(name) name ## _dl +#else +#define CSSPARSE_NAME(name) name ## _di +#endif + +// PKG_ADD: dispatch ("qr", "spqr", "sparse matrix"); +// PKG_ADD: dispatch ("qr", "spqr", "sparse complex matrix"); +// PKG_ADD: dispatch ("qr", "spqr", "sparse bool matrix"); +DEFUN_DLD (spqr, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{r} =} spqr (@var{a})\n\ +@deftypefnx {Loadable Function} {@var{r} =} spqr (@var{a},0)\n\ +@deftypefnx {Loadable Function} {[@var{c}, @var{r}] =} spqr (@var{a},@var{b})\n\ +@deftypefnx {Loadable Function} {[@var{c}, @var{r}] =} spqr (@var{a},@var{b},0)\n\ +@cindex QR factorization\n\ +Compute the sparse QR factorization of @var{a}, using @sc{CSparse}.\n\ +As the matrix @var{Q} is in general a full matrix, this function returns\n\ +the @var{Q}-less factorization @var{r} of @var{a}, such that\n\ +@code{@var{r} = chol (@var{a}' * @var{a})}.\n\ +\n\ +If the final argument is the scalar @code{0} and the number of rows is\n\ +larger than the number of columns, then an economy factorization is\n\ +returned. That is @var{r} will have only @code{size (@var{a},1)} rows.\n\ +\n\ +If an additional matrix @var{b} is supplied, then @code{spqr} returns\n\ +@var{c}, where @code{@var{c} = @var{q}' * @var{b}}. This allows the\n\ +least squares approximation of @code{@var{a} \\ @var{b}} to be calculated\n\ +as\n\ +\n\ +@example\n\ +[@var{c},@var{r}] = spqr (@var{a},@var{b})\n\ +@var{x} = @var{r} \\ @var{c}\n\ +@end example\n\ +\n\ +@end deftypefn\n\ +@seealso{spchol, qr}") +{ + int nargin = args.length (); + octave_value_list retval; + bool economy = false; + bool is_cmplx = false; + bool have_b = false; + + if (nargin < 1 || nargin > 3) + print_usage ("spqr"); + else + { + if (args(0).is_complex_type ()) + is_cmplx = true; + if (nargin > 1) + { + have_b = true; + if (args(nargin-1).is_scalar_type ()) + { + int val = args(nargin-1).int_value (); + if (val == 0) + { + economy = true; + have_b = (nargin > 2); + } + } + if (have_b && args(1).is_complex_type ()) + is_cmplx = true; + } + + if (!error_state) + { + if (have_b && nargout < 2) + error ("spqr: incorrect number of output arguments"); + else if (is_cmplx) + { + SparseComplexQR q (args(0).sparse_complex_matrix_value ()); + if (!error_state) + { + if (have_b) + { + retval(1) = q.R (economy); + retval(0) = q.C (args(1).complex_matrix_value ()); + } + else + retval(0) = q.R (economy); + } + } + else + { + SparseQR q (args(0).sparse_matrix_value ()); + if (!error_state) + { + if (have_b) + { + retval(1) = q.R (economy); + retval(0) = q.C (args(1).matrix_value ()); + } + else + retval(0) = q.R (economy); + } + } + } + } + return retval; +} + +/* + +The deactivated tests below can't be tested till rectangular back-subs is +implemented for sparse matrices. + +%!test +%! n = 20; d= 0.2; +%! a = sprandn(n,n,d)+speye(n,n); +%! r = spqr(a); +%! assert(r'*r,a'*a,1e-10) + +%!test +%! n = 20; d= 0.2; +%! a = sprandn(n,n,d)+speye(n,n); +%! q = symamd(a); +%! a = a(q,q); +%! r = spqr(a); +%! assert(r'*r,a'*a,1e-10) + +%!test +%! n = 20; d= 0.2; +%! a = sprandn(n,n,d)+speye(n,n); +%! [c,r] = spqr(a,ones(n,1)); +%! assert (r\c,full(a)\ones(n,1),10e-10) + +%!test +%! n = 20; d= 0.2; +%! a = sprandn(n,n,d)+speye(n,n); +%! b = randn(n,2); +%! [c,r] = spqr(a,b); +%! assert (r\c,full(a)\b,10e-10) + +%% Test under-determined systems!! +%!#test +%! n = 20; d= 0.2; +%! a = sprandn(n,n+1,d)+speye(n,n+1); +%! b = randn(n,2); +%! [c,r] = spqr(a,b); +%! assert (r\c,full(a)\b,10e-10) + +%!test +%! n = 20; d= 0.2; +%! a = 1i*sprandn(n,n,d)+speye(n,n); +%! r = spqr(a); +%! assert(r'*r,a'*a,1e-10) + +%!test +%! n = 20; d= 0.2; +%! a = 1i*sprandn(n,n,d)+speye(n,n); +%! q = symamd(a); +%! a = a(q,q); +%! r = spqr(a); +%! assert(r'*r,a'*a,1e-10) + +%!test +%! n = 20; d= 0.2; +%! a = 1i*sprandn(n,n,d)+speye(n,n); +%! [c,r] = spqr(a,ones(n,1)); +%! assert (r\c,full(a)\ones(n,1),10e-10) + +%!test +%! n = 20; d= 0.2; +%! a = 1i*sprandn(n,n,d)+speye(n,n); +%! b = randn(n,2); +%! [c,r] = spqr(a,b); +%! assert (r\c,full(a)\b,10e-10) + +%% Test under-determined systems!! +%!#test +%! n = 20; d= 0.2; +%! a = 1i*sprandn(n,n+1,d)+speye(n,n+1); +%! b = randn(n,2); +%! [c,r] = spqr(a,b); +%! assert (r\c,full(a)\b,10e-10) + +%!error spqr(sprandn(10,10,0.2),ones(10,1)); + +*/ + +static RowVector +put_int (octave_idx_type *p, octave_idx_type n) +{ + RowVector ret (n); + for (octave_idx_type i = 0; i < n; i++) + ret.xelem(i) = p[i] + 1; + return ret; +} + +DEFUN_DLD (dmperm, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} dmperm (@var{s})\n\ +@deftypefnx {Loadable Function} {[@var{p}. @var{q}. @var{r}, @var{s}] =} dmperm (@var{s})\n\ +\n\ +@cindex Dulmage-Mendelsohn decomposition\n\ +Perform a Deulmage-Mendelsohn permutation on the sparse matrix @var{s}.\n\ +With a single output argument @dfn{dmperm} performs the row permutations\n\ +@var{p} such that @code{@var{s} (@var{p},:)} has no zero elements on the\n\ +diagonal.\n\ +\n\ +Called with two or more output arguments, returns the row and column\n\ +permutations, such that @code{@var{s} (@var{p}, @var{q})} is in block\n\ +triangular form. The values of @var{r} and @var{s} define the boundaries\n\ +of the blocks. If @var{s} is square then @code{@var{r} == @var{s}}.\n\ +\n\ +The method used is described in: A. Pothen & C.-J. Fan. Computing the block\n\ +triangular form of a sparse matrix. ACM Trans. Math. Software,\n\ +16(4):303-324, 1990.\n\ +@end deftypefn\n\ +@seealso{colamd,ccolamd}") +{ + int nargin = args.length(); + octave_value_list retval; + +#if HAVE_CXSPARSE + if (nargin != 1) + { + print_usage ("dmperm"); + return retval; + } + + octave_value arg = args(0); + octave_idx_type nr = arg.rows (); + octave_idx_type nc = arg.columns (); + SparseMatrix m; + SparseComplexMatrix cm; + CSSPARSE_NAME (cs) csm; + csm.m = nr; + csm.n = nc; + csm.x = NULL; + csm.nz = -1; + + if (arg.is_real_type ()) + { + m = arg.sparse_matrix_value (); + csm.nzmax = m.nnz(); + csm.p = m.xcidx (); + csm.i = m.xridx (); + } + else + { + cm = arg.sparse_complex_matrix_value (); + csm.nzmax = cm.nnz(); + csm.p = cm.xcidx (); + csm.i = cm.xridx (); + } + + if (!error_state) + { + if (nargout <= 1) + { + octave_idx_type *jmatch = CSSPARSE_NAME (cs_maxtrans) (&csm); + retval(0) = put_int (jmatch + nr, nc); + CSSPARSE_NAME (cs_free) (jmatch); + } + else + { + CSSPARSE_NAME (csd) *dm = CSSPARSE_NAME(cs_dmperm) (&csm); + //retval(5) = put_int (dm->rr, 5); + //retval(4) = put_int (dm->cc, 5); + retval(3) = put_int (dm->S, dm->nb+1); + retval(2) = put_int (dm->R, dm->nb+1); + retval(1) = put_int (dm->Q, nc); + retval(0) = put_int (dm->P, nr); + CSSPARSE_NAME (cs_dfree) (dm); + } + } +#else + error ("dmperm: not available in this version of Octave"); +#endif + + return retval; +} + +/* + +%!test +%! n=20; +%! a=speye(n,n);a=a(randperm(n),:); +%! assert(a(dmperm(a),:),speye(n)) + +%!test +%! n=20; +%! d=0.2; +%! a=tril(sprandn(n,n,d),-1)+speye(n,n); +%! a=a(randperm(n),randperm(n)); +%! [p,q,r,s]=dmperm(a); +%! assert(tril(a(p,q),-1),sparse(n,n)) + +*/ + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff --git a/src/Makefile.in b/src/Makefile.in --- a/src/Makefile.in +++ b/src/Makefile.in @@ -51,7 +51,7 @@ lpsolve.cc lsode.cc lu.cc luinc.cc matrix_type.cc minmax.cc \ pinv.cc qr.cc quad.cc qz.cc rand.cc regexp.cc schur.cc sort.cc \ sparse.cc spchol.cc spdet.cc spkron.cc splu.cc spparms.cc \ - sqrtm.cc svd.cc syl.cc time.cc \ + spqr.cc sqrtm.cc svd.cc syl.cc time.cc \ __gnuplot_raw__.l __glpk__.cc __qp__.cc DLD_SRC := $(addprefix DLD-FUNCTIONS/, $(DLD_XSRC)) @@ -252,7 +252,8 @@ OCT_LINK_DEPS = \ -L../libcruft $(LIBCRUFT) -L../liboctave $(LIBOCTAVE) \ -L. $(LIBOCTINTERP) $(CHOLMOD_LIBS) $(UMFPACK_LIBS) $(AMD_LIBS) \ - $(COLAMD_LIBS) $(CCOLAMD_LIBS) $(BLAS_LIBS) $(FFTW_LIBS) $(LIBS) $(FLIBS) + $(COLAMD_LIBS) $(CCOLAMD_LIBS) $(CXSPARSE_LIBS) $(BLAS_LIBS) \ + $(FFTW_LIBS) $(LIBS) $(FLIBS) DISTFILES = Makefile.in ChangeLog mkdefs mkops mkgendoc \ DOCSTRINGS mkbuiltins mk-errno-list mk-pkg-add \ @@ -313,7 +314,7 @@ $(OCTAVE_LFLAGS) \ $(OCTAVE_LIBS) \ $(LEXLIB) $(UMFPACK_LIBS) $(AMD_LIBS) $(COLAMD_LIBS) \ - $(CHOLMOD_LIBS) $(CCOLAMD_LIBS) $(BLAS_LIBS) \ + $(CHOLMOD_LIBS) $(CCOLAMD_LIBS) $(CXSPARSE_LIBS) $(BLAS_LIBS) \ $(FFTW_LIBS) $(LIBS) $(FLIBS) stmp-pic: pic diff --git a/src/sparse-xdiv.cc b/src/sparse-xdiv.cc --- a/src/sparse-xdiv.cc +++ b/src/sparse-xdiv.cc @@ -39,12 +39,7 @@ static inline bool result_ok (octave_idx_type info) { -#ifdef HAVE_LSSOLVE return (info != -2 && info != -1); -#else - // If the matrix is singular, who cares as we don't have QR based solver yet - return (info != -1); -#endif } static void diff --git a/test/ChangeLog b/test/ChangeLog --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,7 @@ +2006-02-09 David Bateman + + * test/build_sparse_tests.sh: Add tests for sparse QR solvers. + 2006-01-21 David Bateman * build_sparsetest.sh: Add new un-ordered indexing, assignment and diff --git a/test/build_sparse_tests.sh b/test/build_sparse_tests.sh --- a/test/build_sparse_tests.sh +++ b/test/build_sparse_tests.sh @@ -914,6 +914,26 @@ %!assert(sparse(tcs\xs),sparse(tcf\xf),1e-10); EOF + +cat >>$TESTS <