Mercurial > hg > octave-nkf
diff liboctave/MatrixType.cc @ 5785:6b9cec830d72
[project @ 2006-05-03 19:32:46 by dbateman]
author | dbateman |
---|---|
date | Wed, 03 May 2006 19:32:48 +0000 |
parents | |
children | 13aa80fc7839 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/liboctave/MatrixType.cc @@ -0,0 +1,1199 @@ +/* + +Copyright (C) 2006 David Bateman +Copyright (C) 2006 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 "MatrixType.h" +#include "dMatrix.h" +#include "CMatrix.h" +#include "dSparse.h" +#include "CSparse.h" +#include "oct-spparms.h" + +// FIXME There is a large code duplication here + +MatrixType::MatrixType (void) : typ (MatrixType::Unknown), full (false), + nperm (0) +{ + sp_bandden = Voctave_sparse_controls.get_key ("bandden"); +} + +MatrixType::MatrixType (const MatrixType &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), full (a.full), 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]; + } +} + +MatrixType::MatrixType (const Matrix &a) +{ + octave_idx_type nrows = a.rows (); + octave_idx_type ncols = a.cols (); + nperm = 0; + full = true; + + if (ncols == nrows) + { + bool upper = true; + bool lower = true; + bool hermitian = true; + + for (octave_idx_type j = 0; j < ncols; j++) + { + if (j < nrows) + { + if (a.elem (j,j) == 0.) + { + upper = false; + lower = false; + hermitian = false; + break; + } + if (a.elem (j,j) < 0.) + hermitian = false; + } + for (octave_idx_type i = 0; i < j; i++) + if (lower && a.elem (i,j) != 0.) + { + lower = false; + break; + } + for (octave_idx_type i = j+1; i < nrows; i++) + { + if (hermitian && a.elem (i, j) != a.elem (j, i)) + hermitian = false; + if (upper && a.elem (i,j) != 0) + upper = false; + } + if (!upper && !lower && !hermitian) + break; + } + + if (upper) + typ = MatrixType::Upper; + else if (lower) + typ = MatrixType::Lower; + else if (hermitian) + typ = MatrixType::Hermitian; + else if (ncols == nrows) + typ = MatrixType::Full; + } + else + typ = MatrixType::Rectangular; +} + +MatrixType::MatrixType (const ComplexMatrix &a) +{ + octave_idx_type nrows = a.rows (); + octave_idx_type ncols = a.cols (); + nperm = 0; + full = true; + + if (ncols == nrows) + { + bool upper = true; + bool lower = true; + bool hermitian = true; + + for (octave_idx_type j = 0; j < ncols; j++) + { + if (j < ncols) + { + if (imag(a.elem (j,j)) == 0. && + real(a.elem (j,j)) == 0.) + { + upper = false; + lower = false; + hermitian = false; + break; + } + + if (imag(a.elem (j,j)) != 0. || + real(a.elem (j,j)) < 0.) + hermitian = false; + } + for (octave_idx_type i = 0; i < j; i++) + if (lower && (real(a.elem (i,j)) != 0 || imag(a.elem (i,j)) != 0)) + { + lower = false; + break; + } + for (octave_idx_type i = j+1; i < nrows; i++) + { + if (hermitian && a.elem (i, j) != conj(a.elem (j, i))) + hermitian = false; + if (upper && (real(a.elem (i,j)) != 0 || + imag(a.elem (i,j)) != 0)) + upper = false; + } + if (!upper && !lower && !hermitian) + break; + } + + if (upper) + typ = MatrixType::Upper; + else if (lower) + typ = MatrixType::Lower; + else if (hermitian) + typ = MatrixType::Hermitian; + else if (ncols == nrows) + typ = MatrixType::Full; + } + else + typ = MatrixType::Rectangular; +} + +MatrixType::MatrixType (const SparseMatrix &a) +{ + octave_idx_type nrows = a.rows (); + octave_idx_type ncols = a.cols (); + octave_idx_type nm = (ncols < nrows ? ncols : nrows); + octave_idx_type nnz = a.nzmax (); + full = false; + + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Calculating Sparse Matrix Type"); + + nperm = 0; + + sp_bandden = Voctave_sparse_controls.get_key ("bandden"); + bool maybe_hermitian = false; + typ = MatrixType::Full; + + if (nnz == nm) + { + matrix_type tmp_typ = MatrixType::Diagonal; + octave_idx_type i; + // Maybe the matrix is diagonal + for (i = 0; i < nm; i++) + { + if (a.cidx(i+1) != a.cidx(i) + 1) + { + tmp_typ = MatrixType::Full; + break; + } + if (a.ridx(i) != i) + { + tmp_typ = MatrixType::Permuted_Diagonal; + break; + } + } + + if (tmp_typ == MatrixType::Permuted_Diagonal) + { + std::vector<bool> found (nrows); + + for (octave_idx_type j = 0; j < i; j++) + found [j] = true; + for (octave_idx_type j = i; j < nrows; j++) + found [j] = false; + + for (octave_idx_type j = i; j < nm; j++) + { + if ((a.cidx(j+1) > a.cidx(j) + 1) || + ((a.cidx(j+1) == a.cidx(j) + 1) && found [a.ridx(j)])) + { + tmp_typ = MatrixType::Full; + break; + } + found [a.ridx(j)] = true; + } + } + typ = tmp_typ; + } + + if (typ == MatrixType::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 = false; + if (j < nrows) + { + 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)) + { + 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 (nrows == ncols && sp_bandden != 1. && bandden > sp_bandden) + { + if (upper_band == 1 && lower_band == 1) + typ = MatrixType::Tridiagonal; + else + typ = MatrixType::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 = MatrixType::Lower; + else if (lower_band == 0) + typ = MatrixType::Upper; + + if (upper_band == lower_band && nrows == ncols) + maybe_hermitian = true; + } + + if (typ == MatrixType::Full) + { + // Search for a permuted triangular matrix, and test if + // permutation is singular + + // FIXME + // Perhaps this should be based on a dmperm algorithm + bool found = false; + + nperm = ncols; + perm = new octave_idx_type [ncols]; + + for (octave_idx_type i = 0; i < ncols; i++) + perm [i] = -1; + + for (octave_idx_type i = 0; i < nm; 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 = MatrixType::Permuted_Upper; + if (ncols > nrows) + { + octave_idx_type k = nrows; + for (octave_idx_type i = 0; i < ncols; i++) + if (perm [i] == -1) + perm[i] = k++; + } + } + else if (a.cidx(nm) == a.cidx(ncols)) + { + nperm = nrows; + delete [] perm; + perm = new octave_idx_type [nrows]; + OCTAVE_LOCAL_BUFFER (octave_idx_type, tmp, nrows); + + for (octave_idx_type i = 0; i < nrows; 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 < nm; i++) + if (perm[i] == -1) + { + found = false; + break; + } + else + { + tmp[perm[i]] = 1; + } + + if (found) + { + octave_idx_type k = ncols; + for (octave_idx_type i = 0; i < nrows; i++) + { + if (tmp[i] == -1) + { + if (k < nrows) + { + perm[k++] = i; + } + else + { + found = false; + break; + } + } + } + } + + if (found) + typ = MatrixType::Permuted_Lower; + else + { + delete [] perm; + nperm = 0; + } + } + else + { + delete [] perm; + nperm = 0; + } + } + + // FIXME + // Disable lower under-determined and upper over-determined problems + // as being detected, and force to treat as singular. As this seems + // to cause issues + if (((typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) + && nrows > ncols) || + ((typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) + && nrows < ncols)) + { + typ = MatrixType::Rectangular; + if (typ == MatrixType::Permuted_Upper || + typ == MatrixType::Permuted_Lower) + delete [] perm; + nperm = 0; + } + + if (typ == MatrixType::Full && ncols != nrows) + typ = MatrixType::Rectangular; + + if (maybe_hermitian && (typ == MatrixType::Full || + typ == MatrixType::Tridiagonal || + typ == MatrixType::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 == MatrixType::Full) + typ = MatrixType::Hermitian; + else if (typ == MatrixType::Banded) + typ = MatrixType::Banded_Hermitian; + else + typ = MatrixType::Tridiagonal_Hermitian; + } + } + } +} + +MatrixType::MatrixType (const SparseComplexMatrix &a) +{ + octave_idx_type nrows = a.rows (); + octave_idx_type ncols = a.cols (); + octave_idx_type nm = (ncols < nrows ? ncols : nrows); + octave_idx_type nnz = a.nzmax (); + full = false; + + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) full = true; + + (*current_liboctave_warning_handler) + ("Calculating Sparse Matrix Type"); + + nperm = 0; + + sp_bandden = Voctave_sparse_controls.get_key ("bandden"); + bool maybe_hermitian = false; + typ = MatrixType::Full; + + if (nnz == nm) + { + matrix_type tmp_typ = MatrixType::Diagonal; + octave_idx_type i; + // Maybe the matrix is diagonal + for (i = 0; i < nm; i++) + { + if (a.cidx(i+1) != a.cidx(i) + 1) + { + tmp_typ = MatrixType::Full; + break; + } + if (a.ridx(i) != i) + { + tmp_typ = MatrixType::Permuted_Diagonal; + break; + } + } + + if (tmp_typ == MatrixType::Permuted_Diagonal) + { + std::vector<bool> found (nrows); + + for (octave_idx_type j = 0; j < i; j++) + found [j] = true; + for (octave_idx_type j = i; j < nrows; j++) + found [j] = false; + + for (octave_idx_type j = i; j < nm; j++) + { + if ((a.cidx(j+1) > a.cidx(j) + 1) || + ((a.cidx(j+1) == a.cidx(j) + 1) && found [a.ridx(j)])) + { + tmp_typ = MatrixType::Full; + break; + } + found [a.ridx(j)] = true; + } + } + typ = tmp_typ; + } + + if (typ == MatrixType::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 = false; + if (j < nrows) + { + 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)) + { + 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 (nrows == ncols && sp_bandden != 1. && bandden > sp_bandden) + { + if (upper_band == 1 && lower_band == 1) + typ = MatrixType::Tridiagonal; + else + typ = MatrixType::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 = MatrixType::Lower; + else if (lower_band == 0) + typ = MatrixType::Upper; + + if (upper_band == lower_band && nrows == ncols) + maybe_hermitian = true; + } + + if (typ == MatrixType::Full) + { + // Search for a permuted triangular matrix, and test if + // permutation is singular + + // FIXME + // Perhaps this should be based on a dmperm algorithm + bool found = false; + + nperm = ncols; + perm = new octave_idx_type [ncols]; + + for (octave_idx_type i = 0; i < ncols; i++) + perm [i] = -1; + + for (octave_idx_type i = 0; i < nm; 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 = MatrixType::Permuted_Upper; + if (ncols > nrows) + { + octave_idx_type k = nrows; + for (octave_idx_type i = 0; i < ncols; i++) + if (perm [i] == -1) + perm[i] = k++; + } + } + else if (a.cidx(nm) == a.cidx(ncols)) + { + nperm = nrows; + delete [] perm; + perm = new octave_idx_type [nrows]; + OCTAVE_LOCAL_BUFFER (octave_idx_type, tmp, nrows); + + for (octave_idx_type i = 0; i < nrows; 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 < nm; i++) + if (perm[i] == -1) + { + found = false; + break; + } + else + { + tmp[perm[i]] = 1; + } + + if (found) + { + octave_idx_type k = ncols; + for (octave_idx_type i = 0; i < nrows; i++) + { + if (tmp[i] == -1) + { + if (k < nrows) + { + perm[k++] = i; + } + else + { + found = false; + break; + } + } + } + } + + if (found) + typ = MatrixType::Permuted_Lower; + else + { + delete [] perm; + nperm = 0; + } + } + else + { + delete [] perm; + nperm = 0; + } + } + + // FIXME + // Disable lower under-determined and upper over-determined problems + // as being detected, and force to treat as singular. As this seems + // to cause issues + if (((typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) + && nrows > ncols) || + ((typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) + && nrows < ncols)) + { + typ = MatrixType::Rectangular; + if (typ == MatrixType::Permuted_Upper || + typ == MatrixType::Permuted_Lower) + delete [] perm; + nperm = 0; + } + + if (typ == MatrixType::Full && ncols != nrows) + typ = MatrixType::Rectangular; + + if (maybe_hermitian && (typ == MatrixType::Full || + typ == MatrixType::Tridiagonal || + typ == MatrixType::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 == MatrixType::Full) + typ = MatrixType::Hermitian; + else if (typ == MatrixType::Banded) + typ = MatrixType::Banded_Hermitian; + else + typ = MatrixType::Tridiagonal_Hermitian; + } + } + } +} +MatrixType::MatrixType (const matrix_type t, bool _full) : + typ (MatrixType::Unknown), nperm (0) +{ + sp_bandden = Voctave_sparse_controls.get_key ("bandden"); + full = _full; + + if (t == MatrixType::Full || t == MatrixType::Diagonal || + t == MatrixType::Permuted_Diagonal || t == MatrixType::Upper || + t == MatrixType::Lower || t == MatrixType::Tridiagonal || + t == MatrixType::Tridiagonal_Hermitian || t == MatrixType::Rectangular) + typ = t; + else + (*current_liboctave_warning_handler) ("Invalid matrix type"); +} + +MatrixType::MatrixType (const matrix_type t, const octave_idx_type np, + const octave_idx_type *p, bool _full) : + typ (MatrixType::Unknown), nperm (0) +{ + sp_bandden = Voctave_sparse_controls.get_key ("bandden"); + full = _full; + + if (t == MatrixType::Permuted_Upper || t == MatrixType::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 matrix type"); +} + +MatrixType::MatrixType (const matrix_type t, const octave_idx_type ku, + const octave_idx_type kl, bool _full) : + typ (MatrixType::Unknown), nperm (0) +{ + sp_bandden = Voctave_sparse_controls.get_key ("bandden"); + full = _full; + + if (t == MatrixType::Banded || t == MatrixType::Banded_Hermitian) + { + typ = t; + upper_band = ku; + lower_band = kl; + } + else + (*current_liboctave_warning_handler) ("Invalid sparse matrix type"); +} + +MatrixType::~MatrixType (void) +{ + if (nperm != 0) + { + delete [] perm; + } +} + +MatrixType& +MatrixType::operator = (const MatrixType& 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; + full = a.full; + 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 +MatrixType::type (bool quiet) +{ + if (typ != MatrixType::Unknown && (full || + sp_bandden == Voctave_sparse_controls.get_key ("bandden"))) + { + if (!quiet && + Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Using Cached Matrix Type"); + + return typ; + } + + if (typ != MatrixType::Unknown && + Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Invalidating Matrix Type"); + + typ = MatrixType::Unknown; + + return typ; +} + +int +MatrixType::type (const SparseMatrix &a) +{ + if (typ != MatrixType::Unknown && (full || + sp_bandden == Voctave_sparse_controls.get_key ("bandden"))) + { + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Using Cached Matrix Type"); + + return typ; + } + + MatrixType 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; + full = tmp_typ.full; + 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 +MatrixType::type (const SparseComplexMatrix &a) +{ + if (typ != MatrixType::Unknown && (full || + sp_bandden == Voctave_sparse_controls.get_key ("bandden"))) + { + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Using Cached Matrix Type"); + + return typ; + } + + MatrixType 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; + full = tmp_typ.full; + 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 +MatrixType::type (const Matrix &a) +{ + if (typ != MatrixType::Unknown) + { + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Using Cached Matrix Type"); + + return typ; + } + + MatrixType tmp_typ (a); + typ = tmp_typ.typ; + full = tmp_typ.full; + 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 +MatrixType::type (const ComplexMatrix &a) +{ + if (typ != MatrixType::Unknown) + { + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) + (*current_liboctave_warning_handler) + ("Using Cached Matrix Type"); + + return typ; + } + + MatrixType tmp_typ (a); + typ = tmp_typ.typ; + full = tmp_typ.full; + 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 +MatrixType::info () const +{ + if (Voctave_sparse_controls.get_key ("spumoni") != 0.) + { + if (typ == MatrixType::Unknown) + (*current_liboctave_warning_handler) + ("Unknown Matrix Type"); + else if (typ == MatrixType::Diagonal) + (*current_liboctave_warning_handler) + ("Diagonal Sparse Matrix"); + else if (typ == MatrixType::Permuted_Diagonal) + (*current_liboctave_warning_handler) + ("Permuted Diagonal Sparse Matrix"); + else if (typ == MatrixType::Upper) + (*current_liboctave_warning_handler) + ("Upper Triangular Matrix"); + else if (typ == MatrixType::Lower) + (*current_liboctave_warning_handler) + ("Lower Triangular Matrix"); + else if (typ == MatrixType::Permuted_Upper) + (*current_liboctave_warning_handler) + ("Permuted Upper Triangular Matrix"); + else if (typ == MatrixType::Permuted_Lower) + (*current_liboctave_warning_handler) + ("Permuted Lower Triangular Matrix"); + else if (typ == MatrixType::Banded) + (*current_liboctave_warning_handler) + ("Banded Sparse Matrix %d-1-%d (Density %f)", lower_band, + upper_band, bandden); + else if (typ == MatrixType::Banded_Hermitian) + (*current_liboctave_warning_handler) + ("Banded Hermitian/Symmetric Sparse Matrix %d-1-%d (Density %f)", + lower_band, upper_band, bandden); + else if (typ == MatrixType::Hermitian) + (*current_liboctave_warning_handler) + ("Hermitian/Symmetric Matrix"); + else if (typ == MatrixType::Tridiagonal) + (*current_liboctave_warning_handler) + ("Tridiagonal Sparse Matrix"); + else if (typ == MatrixType::Tridiagonal_Hermitian) + (*current_liboctave_warning_handler) + ("Hermitian/Symmetric Tridiagonal Sparse Matrix"); + else if (typ == MatrixType::Rectangular) + (*current_liboctave_warning_handler) + ("Rectangular/Singular Matrix"); + else if (typ == MatrixType::Full) + (*current_liboctave_warning_handler) + ("Full Matrix"); + } +} + +void +MatrixType::mark_as_symmetric (void) +{ + if (typ == MatrixType::Tridiagonal || + typ == MatrixType::Tridiagonal_Hermitian) + typ = MatrixType::Tridiagonal_Hermitian; + else if (typ == MatrixType::Banded || + typ == MatrixType::Banded_Hermitian) + typ = MatrixType::Banded_Hermitian; + else if (typ == MatrixType::Full || typ == MatrixType::Hermitian || + typ == MatrixType::Unknown) + typ = MatrixType::Hermitian; + else + (*current_liboctave_error_handler) + ("Can not mark current matrix type as symmetric"); +} + +void +MatrixType::mark_as_unsymmetric (void) +{ + if (typ == MatrixType::Tridiagonal || + typ == MatrixType::Tridiagonal_Hermitian) + typ = MatrixType::Tridiagonal; + else if (typ == MatrixType::Banded || + typ == MatrixType::Banded_Hermitian) + typ = MatrixType::Banded; + else if (typ == MatrixType::Full || typ == MatrixType::Hermitian || + typ == MatrixType::Unknown) + typ = MatrixType::Full; +} + +void +MatrixType::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 == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal) + typ = MatrixType::Permuted_Diagonal; + else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) + typ = MatrixType::Permuted_Upper; + else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) + typ = MatrixType::Permuted_Lower; + else + (*current_liboctave_error_handler) + ("Can not mark current matrix type as symmetric"); +} + +void +MatrixType::mark_as_unpermuted (void) +{ + if (nperm) + { + nperm = 0; + delete [] perm; + } + + if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal) + typ = MatrixType::Diagonal; + else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) + typ = MatrixType::Upper; + else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) + typ = MatrixType::Lower; +} + +MatrixType +MatrixType::transpose (void) const +{ + MatrixType retval (*this); + if (typ == MatrixType::Upper) + retval.typ = MatrixType::Lower; + else if (typ == MatrixType::Permuted_Upper) + retval.typ = MatrixType::Permuted_Lower; + else if (typ == MatrixType::Lower) + retval.typ = MatrixType::Upper; + else if (typ == MatrixType::Permuted_Lower) + retval.typ = MatrixType::Permuted_Upper; + else if (typ == MatrixType::Banded) + { + retval.upper_band = lower_band; + retval.lower_band = upper_band; + } + + return retval; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ +