Mercurial > hg > octave-nkf
diff liboctave/SparseType.cc @ 5164:57077d0ddc8e
[project @ 2005-02-25 19:55:24 by jwe]
author | jwe |
---|---|
date | Fri, 25 Feb 2005 19:55:28 +0000 |
parents | |
children | 23b37da9fd5b |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/liboctave/SparseType.cc @@ -0,0 +1,696 @@ +/* + +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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#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 (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) + { + row_perm = new int [nperm]; + col_perm = new int [nperm]; + for (int i = 0; i < nperm; i++) + { + row_perm[i] = a.row_perm[i]; + col_perm[i] = a.col_perm[i]; + } + } +} + +SparseType::SparseType (const SparseMatrix &a) +{ + int nrows = a.rows (); + int ncols = a.cols (); + int nnz = a.nnz (); + + 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; + int 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 (int j = 0; j < i; j++) + found [j] = true; + for (int j = i; j < ncols; j++) + found [j] = false; + + for (int 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 (int j = 0; j < ncols; j++) + { + bool zero_on_diagonal = true; + for (int 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) + { + int ru = a.ridx(a.cidx(j)); + int 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; + + int 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 Write this test based on dmperm + + } + } + + 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 (int j = 0; j < ncols; j++) + { + bool diag_positive = false; + + for (int i = a.cidx(j); i < a.cidx(j+1); i++) + { + int 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 (int 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) +{ + int nrows = a.rows (); + int ncols = a.cols (); + int nnz = a.nnz (); + + 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; + int 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 (int j = 0; j < i; j++) + found [j] = true; + for (int j = i; j < ncols; j++) + found [j] = false; + + for (int 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 (int j = 0; j < ncols; j++) + { + bool zero_on_diagonal = true; + for (int 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) + { + int ru = a.ridx(a.cidx(j)); + int 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; + + int 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 Write this test based on dmperm + + } + } + + 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 (int j = 0; j < ncols; j++) + { + bool diag_positive = false; + + for (int i = a.cidx(j); i < a.cidx(j+1); i++) + { + int 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 (int 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 (void) +{ + if (nperm != 0) + { + delete [] row_perm; + delete [] col_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) + { + row_perm = new int [nperm]; + col_perm = new int [nperm]; + for (int i = 0; i < nperm; i++) + { + row_perm[i] = a.row_perm[i]; + col_perm[i] = a.col_perm[i]; + } + } + + } + return *this; +} + +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; + } + + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Calculating Sparse Matrix Type"); + + + 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) + { + row_perm = new int [nperm]; + col_perm = new int [nperm]; + for (int i = 0; i < nperm; i++) + { + row_perm[i] = tmp_typ.row_perm[i]; + col_perm[i] = tmp_typ.col_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; + } + + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Calculating Sparse Matrix Type"); + + + 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) + { + row_perm = new int [nperm]; + col_perm = new int [nperm]; + for (int i = 0; i < nperm; i++) + { + row_perm[i] = tmp_typ.row_perm[i]; + col_perm[i] = tmp_typ.col_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 %g-1-%g (Density %g)", lower_band, + upper_band, bandden); + else if (typ == SparseType::Banded_Hermitian) + (*current_liboctave_warning_handler) + ("Banded Hermitian/Symmetric Sparse Matrix %g-1-%g (Density %g)", + 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 int np, const int *pr, const int *pc) +{ + nperm = np; + row_perm = new int [nperm]; + col_perm = new int [nperm]; + for (int i = 0; i < nperm; i++) + { + row_perm[i] = pr[i]; + col_perm[i] = pc[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 [] row_perm; + delete [] col_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; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ +