Mercurial > hg > octave-nkf
view liboctave/SparseType.cc @ 5356:06585668a971 ss-2-9-3
[project @ 2005-05-18 17:20:31 by jwe]
author | jwe |
---|---|
date | Wed, 18 May 2005 17:20:32 +0000 |
parents | 22994a5730f9 |
children | b4cfbb0ec8c4 |
line wrap: on
line source
/* Copyright (C) 2004 David Bateman Copyright (C) 1998-2004 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 <config.h> #endif #include <vector> #include "SparseType.h" #include "dSparse.h" #include "CSparse.h" #include "oct-spparms.h" // XXX FIXME XXX There is a large code duplication here SparseType::SparseType (void) : typ (SparseType::Unknown), nperm (0) { sp_bandden = Voctave_sparse_controls.get_key ("bandden"); } SparseType::SparseType (const SparseType &a) : typ (a.typ), sp_bandden (a.sp_bandden), bandden (a.bandden), upper_band (a.upper_band), lower_band (a.lower_band), dense (a.dense), nperm (a.nperm) { if (nperm != 0) { perm = new octave_idx_type [nperm]; for (octave_idx_type i = 0; i < nperm; i++) perm[i] = a.perm[i]; } } SparseType::SparseType (const SparseMatrix &a) { octave_idx_type nrows = a.rows (); octave_idx_type ncols = a.cols (); octave_idx_type nnz = a.nnz (); if (Voctave_sparse_controls.get_key ("spumoni") != 0.) (*current_liboctave_warning_handler) ("Calculating Sparse Matrix Type"); nperm = 0; if (nrows != ncols) typ = SparseType::Rectangular; else { sp_bandden = Voctave_sparse_controls.get_key ("bandden"); bool maybe_hermitian = false; typ = SparseType::Full; if (nnz == ncols) { matrix_type tmp_typ = SparseType::Diagonal; octave_idx_type i; // Maybe the matrix is diagonal for (i = 0; i < ncols; i++) { if (a.cidx(i+1) != a.cidx(i) + 1) { tmp_typ = Full; break; } if (a.ridx(i) != i) { tmp_typ = SparseType::Permuted_Diagonal; break; } } if (tmp_typ == SparseType::Permuted_Diagonal) { bool found [ncols]; for (octave_idx_type j = 0; j < i; j++) found [j] = true; for (octave_idx_type j = i; j < ncols; j++) found [j] = false; for (octave_idx_type j = i; j < ncols; j++) { if ((a.cidx(j+1) != a.cidx(j) + 1) || found [a.ridx(j)]) { tmp_typ = Full; break; } found [a.ridx(j)] = true; } } typ = tmp_typ; } if (typ == Full) { // Search for banded, upper and lower triangular matrices bool singular = false; upper_band = 0; lower_band = 0; for (octave_idx_type j = 0; j < ncols; j++) { bool zero_on_diagonal = true; for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++) if (a.ridx(i) == j) { zero_on_diagonal = false; break; } if (zero_on_diagonal) { singular = true; break; } if (a.cidx(j+1) - a.cidx(j) > 0) { octave_idx_type ru = a.ridx(a.cidx(j)); octave_idx_type rl = a.ridx(a.cidx(j+1)-1); if (j - ru > upper_band) upper_band = j - ru; if (rl - j > lower_band) lower_band = rl - j; } } if (!singular) { bandden = double (nnz) / (double (ncols) * (double (lower_band) + double (upper_band)) - 0.5 * double (upper_band + 1) * double (upper_band) - 0.5 * double (lower_band + 1) * double (lower_band)); if (sp_bandden != 1. && bandden > sp_bandden) { if (upper_band == 1 && lower_band == 1) typ = SparseType::Tridiagonal; else typ = SparseType::Banded; octave_idx_type nnz_in_band = (upper_band + lower_band + 1) * nrows - (1 + upper_band) * upper_band / 2 - (1 + lower_band) * lower_band / 2; if (nnz_in_band == nnz) dense = true; else dense = false; } else if (upper_band == 0) typ = SparseType::Lower; else if (lower_band == 0) typ = SparseType::Upper; if (upper_band == lower_band) maybe_hermitian = true; } if (typ == Full) { // Search for a permuted triangular matrix, and test if // permutation is singular // XXX FIXME XXX Perhaps this should be based on a dmperm algorithm bool found = false; nperm = nrows; perm = new octave_idx_type [nperm]; for (octave_idx_type i = 0; i < nperm; i++) { found = false; for (octave_idx_type j = 0; j < ncols; j++) { if ((a.cidx(j+1) - a.cidx(j)) > 0 && a.ridx(a.cidx(j+1)-1) == i) { perm [i] = j; found = true; break; } } if (!found) break; } if (found) typ = SparseType::Permuted_Upper; else { OCTAVE_LOCAL_BUFFER (octave_idx_type, tmp, nperm); for (octave_idx_type i = 0; i < nperm; i++) { perm [i] = -1; tmp [i] = -1; } for (octave_idx_type j = 0; j < ncols; j++) for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++) perm [a.ridx(i)] = j; found = true; for (octave_idx_type i = 0; i < nperm; i++) if (perm[i] == -1) { found = false; break; } else { tmp[perm[i]] = 1; } if (found) for (octave_idx_type i = 0; i < nperm; i++) if (tmp[i] == -1) { found = false; break; } if (found) typ = SparseType::Permuted_Lower; else { delete [] perm; nperm = 0; } } } } if (maybe_hermitian && (typ == Full || typ == Tridiagonal || typ == Banded)) { // Check for symmetry, with positive real diagonal, which // has a very good chance of being symmetric positive // definite.. bool is_herm = true; for (octave_idx_type j = 0; j < ncols; j++) { bool diag_positive = false; for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++) { octave_idx_type ri = a.ridx(i); if (ri == j) { if (a.data(i) == std::abs(a.data(i))) diag_positive = true; else break; } else { bool found = false; for (octave_idx_type k = a.cidx(ri); k < a.cidx(ri+1); k++) { if (a.ridx(k) == j) { if (a.data(i) == conj (a.data(k))) found = true; break; } } if (! found) { is_herm = false; break; } } } if (! diag_positive || ! is_herm) { is_herm = false; break; } } if (is_herm) { if (typ == Full) typ = Hermitian; else if (typ == Banded) typ = Banded_Hermitian; else typ = Tridiagonal_Hermitian; } } } } SparseType::SparseType (const SparseComplexMatrix &a) { octave_idx_type nrows = a.rows (); octave_idx_type ncols = a.cols (); octave_idx_type nnz = a.nnz (); if (Voctave_sparse_controls.get_key ("spumoni") != 0.) (*current_liboctave_warning_handler) ("Calculating Sparse Matrix Type"); nperm = 0; if (nrows != ncols) typ = SparseType::Rectangular; else { sp_bandden = Voctave_sparse_controls.get_key ("bandden"); bool maybe_hermitian = false; typ = SparseType::Full; if (nnz == ncols) { matrix_type tmp_typ = SparseType::Diagonal; octave_idx_type i; // Maybe the matrix is diagonal for (i = 0; i < ncols; i++) { if (a.cidx(i+1) != a.cidx(i) + 1) { tmp_typ = Full; break; } if (a.ridx(i) != i) { tmp_typ = SparseType::Permuted_Diagonal; break; } } if (tmp_typ == SparseType::Permuted_Diagonal) { bool found [ncols]; for (octave_idx_type j = 0; j < i; j++) found [j] = true; for (octave_idx_type j = i; j < ncols; j++) found [j] = false; for (octave_idx_type j = i; j < ncols; j++) { if ((a.cidx(j+1) != a.cidx(j) + 1) || found [a.ridx(j)]) { tmp_typ = Full; break; } found [a.ridx(j)] = true; } } typ = tmp_typ; } if (typ == Full) { // Search for banded, upper and lower triangular matrices bool singular = false; upper_band = 0; lower_band = 0; for (octave_idx_type j = 0; j < ncols; j++) { bool zero_on_diagonal = true; for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++) if (a.ridx(i) == j) { zero_on_diagonal = false; break; } if (zero_on_diagonal) { singular = true; break; } if (a.cidx(j+1) - a.cidx(j) > 0) { octave_idx_type ru = a.ridx(a.cidx(j)); octave_idx_type rl = a.ridx(a.cidx(j+1)-1); if (j - ru > upper_band) upper_band = j - ru; if (rl - j > lower_band) lower_band = rl - j; } } if (!singular) { bandden = double (nnz) / (double (ncols) * (double (lower_band) + double (upper_band)) - 0.5 * double (upper_band + 1) * double (upper_band) - 0.5 * double (lower_band + 1) * double (lower_band)); if (sp_bandden != 1. && bandden > sp_bandden) { if (upper_band == 1 && lower_band == 1) typ = SparseType::Tridiagonal; else typ = SparseType::Banded; octave_idx_type nnz_in_band = (upper_band + lower_band + 1) * nrows - (1 + upper_band) * upper_band / 2 - (1 + lower_band) * lower_band / 2; if (nnz_in_band == nnz) dense = true; else dense = false; } else if (upper_band == 0) typ = SparseType::Lower; else if (lower_band == 0) typ = SparseType::Upper; if (upper_band == lower_band) maybe_hermitian = true; } if (typ == Full) { // Search for a permuted triangular matrix, and test if // permutation is singular // XXX FIXME XXX Perhaps this should be based on a dmperm algorithm bool found = false; nperm = nrows; perm = new octave_idx_type [nperm]; for (octave_idx_type i = 0; i < nperm; i++) { found = false; for (octave_idx_type j = 0; j < ncols; j++) { if ((a.cidx(j+1) - a.cidx(j)) > 0 && a.ridx(a.cidx(j+1)-1) == i) { perm [i] = j; found = true; break; } } if (!found) break; } if (found) typ = SparseType::Permuted_Upper; else { OCTAVE_LOCAL_BUFFER (octave_idx_type, tmp, nperm); for (octave_idx_type i = 0; i < nperm; i++) { perm [i] = -1; tmp [i] = -1; } for (octave_idx_type j = 0; j < ncols; j++) for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++) perm [a.ridx(i)] = j; found = true; for (octave_idx_type i = 0; i < nperm; i++) if (perm[i] == -1) { found = false; break; } else { tmp[perm[i]] = 1; } if (found) for (octave_idx_type i = 0; i < nperm; i++) if (tmp[i] == -1) { found = false; break; } if (found) typ = SparseType::Permuted_Lower; else { delete [] perm; nperm = 0; } } } } if (maybe_hermitian && (typ == Full || typ == Tridiagonal || typ == Banded)) { // Check for symmetry, with positive real diagonal, which // has a very good chance of being symmetric positive // definite.. bool is_herm = true; for (octave_idx_type j = 0; j < ncols; j++) { bool diag_positive = false; for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++) { octave_idx_type ri = a.ridx(i); if (ri == j) { if (a.data(i) == std::abs(a.data(i))) diag_positive = true; else break; } else { bool found = false; for (octave_idx_type k = a.cidx(ri); k < a.cidx(ri+1); k++) { if (a.ridx(k) == j) { if (a.data(i) == a.data(k)) found = true; break; } } if (! found) { is_herm = false; break; } } } if (! diag_positive || ! is_herm) { is_herm = false; break; } } if (is_herm) { if (typ == Full) typ = Hermitian; else if (typ == Banded) typ = Banded_Hermitian; else typ = Tridiagonal_Hermitian; } } } } SparseType::SparseType (const matrix_type t) : typ (SparseType::Unknown), nperm (0) { sp_bandden = Voctave_sparse_controls.get_key ("bandden"); if (t == SparseType::Full || t == SparseType::Diagonal || t == SparseType::Permuted_Diagonal || t == SparseType::Upper || t == SparseType::Lower || t == SparseType::Tridiagonal || t == SparseType::Tridiagonal_Hermitian || t == SparseType::Rectangular) typ = t; else (*current_liboctave_warning_handler) ("Invalid sparse matrix type"); } SparseType::SparseType (const matrix_type t, const octave_idx_type np, const octave_idx_type *p) : typ (SparseType::Unknown), nperm (0) { sp_bandden = Voctave_sparse_controls.get_key ("bandden"); if (t == SparseType::Permuted_Upper || t == SparseType::Permuted_Lower) { typ = t; nperm = np; perm = new octave_idx_type [nperm]; for (octave_idx_type i = 0; i < nperm; i++) perm[i] = p[i]; } else (*current_liboctave_warning_handler) ("Invalid sparse matrix type"); } SparseType::SparseType (const matrix_type t, const octave_idx_type ku, const octave_idx_type kl) : typ (SparseType::Unknown), nperm (0) { sp_bandden = Voctave_sparse_controls.get_key ("bandden"); if (t == SparseType::Banded || t == SparseType::Banded_Hermitian) { typ = t; upper_band = ku; lower_band = kl; } else (*current_liboctave_warning_handler) ("Invalid sparse matrix type"); } SparseType::~SparseType (void) { if (nperm != 0) { delete [] perm; } } SparseType& SparseType::operator = (const SparseType& a) { if (this != &a) { typ = a.typ; sp_bandden = a.sp_bandden; bandden = a.bandden; upper_band = a.upper_band; lower_band = a.lower_band; dense = a.dense; nperm = a.nperm; if (nperm != 0) { perm = new octave_idx_type [nperm]; for (octave_idx_type i = 0; i < nperm; i++) perm[i] = a.perm[i]; } } return *this; } int SparseType::type (bool quiet) { if (typ != SparseType::Unknown && sp_bandden == Voctave_sparse_controls.get_key ("bandden")) { if (!quiet && Voctave_sparse_controls.get_key ("spumoni") != 0.) (*current_liboctave_warning_handler) ("Using Cached Sparse Matrix Type"); return typ; } if (typ != SparseType::Unknown && Voctave_sparse_controls.get_key ("spumoni") != 0.) (*current_liboctave_warning_handler) ("Invalidating Sparse Matrix Type"); typ = SparseType::Unknown; return typ; } int SparseType::type (const SparseMatrix &a) { if (typ != SparseType::Unknown && sp_bandden == Voctave_sparse_controls.get_key ("bandden")) { if (Voctave_sparse_controls.get_key ("spumoni") != 0.) (*current_liboctave_warning_handler) ("Using Cached Sparse Matrix Type"); return typ; } SparseType tmp_typ (a); typ = tmp_typ.typ; sp_bandden = tmp_typ.sp_bandden; bandden = tmp_typ.bandden; upper_band = tmp_typ.upper_band; lower_band = tmp_typ.lower_band; dense = tmp_typ.dense; nperm = tmp_typ.nperm; if (nperm != 0) { perm = new octave_idx_type [nperm]; for (octave_idx_type i = 0; i < nperm; i++) perm[i] = tmp_typ.perm[i]; } return typ; } int SparseType::type (const SparseComplexMatrix &a) { if (typ != SparseType::Unknown && sp_bandden == Voctave_sparse_controls.get_key ("bandden")) { if (Voctave_sparse_controls.get_key ("spumoni") != 0.) (*current_liboctave_warning_handler) ("Using Cached Sparse Matrix Type"); return typ; } SparseType tmp_typ (a); typ = tmp_typ.typ; sp_bandden = tmp_typ.sp_bandden; bandden = tmp_typ.bandden; upper_band = tmp_typ.upper_band; lower_band = tmp_typ.lower_band; dense = tmp_typ.dense; nperm = tmp_typ.nperm; if (nperm != 0) { perm = new octave_idx_type [nperm]; for (octave_idx_type i = 0; i < nperm; i++) perm[i] = tmp_typ.perm[i]; } return typ; } void SparseType::info (void) const { if (Voctave_sparse_controls.get_key ("spumoni") != 0.) { if (typ == SparseType::Unknown) (*current_liboctave_warning_handler) ("Unknown Sparse Matrix Type"); else if (typ == SparseType::Diagonal) (*current_liboctave_warning_handler) ("Diagonal Sparse Matrix"); else if (typ == SparseType::Permuted_Diagonal) (*current_liboctave_warning_handler) ("Permuted Diagonal Sparse Matrix"); else if (typ == SparseType::Upper) (*current_liboctave_warning_handler) ("Upper Triangular Sparse Matrix"); else if (typ == SparseType::Lower) (*current_liboctave_warning_handler) ("Lower Triangular Sparse Matrix"); else if (typ == SparseType::Permuted_Upper) (*current_liboctave_warning_handler) ("Permuted Upper Triangular Sparse Matrix"); else if (typ == SparseType::Permuted_Lower) (*current_liboctave_warning_handler) ("Permuted Lower Triangular Sparse Matrix"); else if (typ == SparseType::Banded) (*current_liboctave_warning_handler) ("Banded Sparse Matrix %d-1-%d (Density %f)", lower_band, upper_band, bandden); else if (typ == SparseType::Banded_Hermitian) (*current_liboctave_warning_handler) ("Banded Hermitian/Symmetric Sparse Matrix %d-1-%d (Density %f)", lower_band, upper_band, bandden); else if (typ == SparseType::Hermitian) (*current_liboctave_warning_handler) ("Hermitian/Symmetric Sparse Matrix"); else if (typ == SparseType::Tridiagonal) (*current_liboctave_warning_handler) ("Tridiagonal Sparse Matrix"); else if (typ == SparseType::Tridiagonal_Hermitian) (*current_liboctave_warning_handler) ("Hermitian/Symmetric Tridiagonal Sparse Matrix"); else if (typ == SparseType::Rectangular) (*current_liboctave_warning_handler) ("Rectangular Sparse Matrix"); else if (typ == SparseType::Full) (*current_liboctave_warning_handler) ("Full Sparse Matrix"); } } void SparseType::mark_as_symmetric (void) { if (typ == SparseType::Tridiagonal || typ == SparseType::Tridiagonal_Hermitian) typ = SparseType::Tridiagonal_Hermitian; else if (typ == SparseType::Banded || typ == SparseType::Banded_Hermitian) typ = SparseType::Banded_Hermitian; else if (typ == SparseType::Full || typ == SparseType::Hermitian || typ == SparseType::Unknown) typ = SparseType::Hermitian; else (*current_liboctave_error_handler) ("Can not mark current matrix type as symmetric"); } void SparseType::mark_as_unsymmetric (void) { if (typ == SparseType::Tridiagonal || typ == SparseType::Tridiagonal_Hermitian) typ = SparseType::Tridiagonal; else if (typ == SparseType::Banded || typ == SparseType::Banded_Hermitian) typ = SparseType::Banded; else if (typ == SparseType::Full || typ == SparseType::Hermitian || typ == SparseType::Unknown) typ = SparseType::Full; } void SparseType::mark_as_permuted (const octave_idx_type np, const octave_idx_type *p) { nperm = np; perm = new octave_idx_type [nperm]; for (octave_idx_type i = 0; i < nperm; i++) perm[i] = p[i]; if (typ == SparseType::Diagonal || typ == SparseType::Permuted_Diagonal) typ = SparseType::Permuted_Diagonal; else if (typ == SparseType::Upper || typ == SparseType::Permuted_Upper) typ = SparseType::Permuted_Upper; else if (typ == SparseType::Lower || typ == SparseType::Permuted_Lower) typ = SparseType::Permuted_Lower; else (*current_liboctave_error_handler) ("Can not mark current matrix type as symmetric"); } void SparseType::mark_as_unpermuted (void) { if (nperm) { nperm = 0; delete [] perm; } if (typ == SparseType::Diagonal || typ == SparseType::Permuted_Diagonal) typ = SparseType::Diagonal; else if (typ == SparseType::Upper || typ == SparseType::Permuted_Upper) typ = SparseType::Upper; else if (typ == SparseType::Lower || typ == SparseType::Permuted_Lower) typ = SparseType::Lower; } SparseType SparseType::transpose (void) const { SparseType retval (*this); if (typ == SparseType::Upper) retval.typ = SparseType::Lower; else if (typ == SparseType::Permuted_Upper) retval.typ = SparseType::Permuted_Lower; else if (typ == SparseType::Lower) retval.typ = Upper; else if (typ == SparseType::Permuted_Lower) retval.typ = Permuted_Upper; else if (typ == SparseType::Banded) { retval.upper_band = lower_band; retval.lower_band = upper_band; } return retval; } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */