MatrixType.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-2012 David Bateman
00004 Copyright (C) 2006 Andy Adler
00005 Copyright (C) 2009 VZLU Prague
00006 
00007 This file is part of Octave.
00008 
00009 Octave is free software; you can redistribute it and/or modify it
00010 under the terms of the GNU General Public License as published by the
00011 Free Software Foundation; either version 3 of the License, or (at your
00012 option) any later version.
00013 
00014 Octave is distributed in the hope that it will be useful, but WITHOUT
00015 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00017 for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with Octave; see the file COPYING.  If not, see
00021 <http://www.gnu.org/licenses/>.
00022 
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028 
00029 #include <vector>
00030 
00031 #include "MatrixType.h"
00032 #include "dMatrix.h"
00033 #include "CMatrix.h"
00034 #include "dSparse.h"
00035 #include "CSparse.h"
00036 #include "oct-spparms.h"
00037 #include "oct-locbuf.h"
00038 
00039 // FIXME There is a large code duplication here
00040 
00041 MatrixType::MatrixType (void)
00042   : typ (MatrixType::Unknown),
00043     sp_bandden (octave_sparse_params::get_bandden()),
00044     bandden (0), upper_band (0),
00045     lower_band (0), dense (false), full (false), nperm (0), perm (0) { }
00046 
00047 MatrixType::MatrixType (const MatrixType &a)
00048   : typ (a.typ), sp_bandden (a.sp_bandden), bandden (a.bandden),
00049     upper_band (a.upper_band), lower_band (a.lower_band),
00050     dense (a.dense), full (a.full), nperm (a.nperm), perm (0)
00051 {
00052   if (nperm != 0)
00053     {
00054       perm = new octave_idx_type [nperm];
00055       for (octave_idx_type i = 0; i < nperm; i++)
00056         perm[i] = a.perm[i];
00057     }
00058 }
00059 
00060 template<class T>
00061 MatrixType::matrix_type
00062 matrix_real_probe (const MArray<T>& a)
00063 {
00064   MatrixType::matrix_type typ;
00065   octave_idx_type nrows = a.rows ();
00066   octave_idx_type ncols = a.cols ();
00067 
00068   const T zero = 0;
00069 
00070   if (ncols == nrows)
00071     {
00072       bool upper = true;
00073       bool lower = true;
00074       bool hermitian = true;
00075 
00076       // do the checks for lower/upper/hermitian all in one pass.
00077       OCTAVE_LOCAL_BUFFER(T, diag, ncols);
00078 
00079       for (octave_idx_type j = 0;
00080            j < ncols && upper; j++)
00081         {
00082           T d = a.elem (j,j);
00083           upper = upper && (d != zero);
00084           lower = lower && (d != zero);
00085           hermitian = hermitian && (d > zero);
00086           diag[j] = d;
00087         }
00088 
00089       for (octave_idx_type j = 0;
00090            j < ncols && (upper || lower || hermitian); j++)
00091         {
00092           for (octave_idx_type i = 0; i < j; i++)
00093             {
00094               double aij = a.elem (i,j), aji = a.elem (j,i);
00095               lower = lower && (aij == zero);
00096               upper = upper && (aji == zero);
00097               hermitian = hermitian && (aij == aji
00098                                         && aij*aij < diag[i]*diag[j]);
00099             }
00100         }
00101 
00102       if (upper)
00103         typ = MatrixType::Upper;
00104       else if (lower)
00105         typ = MatrixType::Lower;
00106       else if (hermitian)
00107         typ = MatrixType::Hermitian;
00108       else
00109         typ = MatrixType::Full;
00110     }
00111   else
00112     typ = MatrixType::Rectangular;
00113 
00114   return typ;
00115 }
00116 
00117 template<class T>
00118 MatrixType::matrix_type
00119 matrix_complex_probe (const MArray<std::complex<T> >& a)
00120 {
00121   MatrixType::matrix_type typ;
00122   octave_idx_type nrows = a.rows ();
00123   octave_idx_type ncols = a.cols ();
00124 
00125   const T zero = 0;
00126   // get the real type
00127 
00128   if (ncols == nrows)
00129     {
00130       bool upper = true;
00131       bool lower = true;
00132       bool hermitian = true;
00133 
00134       // do the checks for lower/upper/hermitian all in one pass.
00135       OCTAVE_LOCAL_BUFFER(T, diag, ncols);
00136 
00137       for (octave_idx_type j = 0;
00138            j < ncols && upper; j++)
00139         {
00140           std::complex<T> d = a.elem (j,j);
00141           upper = upper && (d != zero);
00142           lower = lower && (d != zero);
00143           hermitian = hermitian && (d.real() > zero && d.imag() == zero);
00144           diag[j] = d.real();
00145         }
00146 
00147       for (octave_idx_type j = 0;
00148            j < ncols && (upper || lower || hermitian); j++)
00149         {
00150           for (octave_idx_type i = 0; i < j; i++)
00151             {
00152               std::complex<T> aij = a.elem (i,j), aji = a.elem (j,i);
00153               lower = lower && (aij == zero);
00154               upper = upper && (aji == zero);
00155               hermitian = hermitian && (aij == std::conj (aji)
00156                                         && std::norm (aij) < diag[i]*diag[j]);
00157             }
00158         }
00159 
00160 
00161       if (upper)
00162         typ = MatrixType::Upper;
00163       else if (lower)
00164         typ = MatrixType::Lower;
00165       else if (hermitian)
00166         typ = MatrixType::Hermitian;
00167       else if (ncols == nrows)
00168         typ = MatrixType::Full;
00169     }
00170   else
00171     typ = MatrixType::Rectangular;
00172 
00173   return typ;
00174 }
00175 
00176 MatrixType::MatrixType (const Matrix &a)
00177   : typ (MatrixType::Unknown),
00178     sp_bandden (0), bandden (0), upper_band (0), lower_band (0),
00179     dense (false), full (true), nperm (0), perm (0)
00180 {
00181   typ = matrix_real_probe (a);
00182 }
00183 
00184 MatrixType::MatrixType (const ComplexMatrix &a)
00185   : typ (MatrixType::Unknown),
00186     sp_bandden (0), bandden (0), upper_band (0), lower_band (0),
00187     dense (false), full (true), nperm (0), perm (0)
00188 {
00189   typ = matrix_complex_probe (a);
00190 }
00191 
00192 
00193 MatrixType::MatrixType (const FloatMatrix &a)
00194   : typ (MatrixType::Unknown),
00195     sp_bandden (0), bandden (0), upper_band (0), lower_band (0),
00196     dense (false), full (true), nperm (0), perm (0)
00197 {
00198   typ = matrix_real_probe (a);
00199 }
00200 
00201 MatrixType::MatrixType (const FloatComplexMatrix &a)
00202   : typ (MatrixType::Unknown),
00203     sp_bandden (0), bandden (0), upper_band (0), lower_band (0),
00204     dense (false), full (true), nperm (0), perm (0)
00205 {
00206   typ = matrix_complex_probe (a);
00207 }
00208 
00209 MatrixType::MatrixType (const SparseMatrix &a)
00210   : typ (MatrixType::Unknown),
00211     sp_bandden (0), bandden (0), upper_band (0), lower_band (0),
00212     dense (false), full (false), nperm (0), perm (0)
00213 {
00214   octave_idx_type nrows = a.rows ();
00215   octave_idx_type ncols = a.cols ();
00216   octave_idx_type nm = (ncols < nrows ? ncols : nrows);
00217   octave_idx_type nnz = a.nnz ();
00218 
00219   if (octave_sparse_params::get_key ("spumoni") != 0.)
00220     (*current_liboctave_warning_handler)
00221       ("Calculating Sparse Matrix Type");
00222 
00223   sp_bandden = octave_sparse_params::get_bandden();
00224   bool maybe_hermitian = false;
00225   typ = MatrixType::Full;
00226 
00227   if (nnz == nm)
00228     {
00229       matrix_type tmp_typ = MatrixType::Diagonal;
00230       octave_idx_type i;
00231       // Maybe the matrix is diagonal
00232       for (i = 0; i < nm; i++)
00233         {
00234           if (a.cidx(i+1) != a.cidx(i) + 1)
00235             {
00236               tmp_typ = MatrixType::Full;
00237               break;
00238             }
00239           if (a.ridx(i) != i)
00240             {
00241               tmp_typ = MatrixType::Permuted_Diagonal;
00242               break;
00243             }
00244         }
00245 
00246       if (tmp_typ == MatrixType::Permuted_Diagonal)
00247         {
00248           std::vector<bool> found (nrows);
00249 
00250           for (octave_idx_type j = 0; j < i; j++)
00251             found [j] = true;
00252           for (octave_idx_type j = i; j < nrows; j++)
00253             found [j] = false;
00254 
00255           for (octave_idx_type j = i; j < nm; j++)
00256             {
00257               if ((a.cidx(j+1) > a.cidx(j) + 1)  ||
00258                   ((a.cidx(j+1) == a.cidx(j) + 1) && found [a.ridx(j)]))
00259                 {
00260                   tmp_typ = MatrixType::Full;
00261                   break;
00262                 }
00263               found [a.ridx(j)] = true;
00264             }
00265         }
00266       typ = tmp_typ;
00267     }
00268 
00269   if (typ == MatrixType::Full)
00270     {
00271       // Search for banded, upper and lower triangular matrices
00272       bool singular = false;
00273       upper_band = 0;
00274       lower_band = 0;
00275       for (octave_idx_type j = 0; j < ncols; j++)
00276         {
00277           bool zero_on_diagonal = false;
00278           if (j < nrows)
00279             {
00280               zero_on_diagonal = true;
00281               for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++)
00282                 if (a.ridx(i) == j)
00283                   {
00284                     zero_on_diagonal = false;
00285                     break;
00286                   }
00287             }
00288 
00289           if (zero_on_diagonal)
00290             {
00291               singular = true;
00292               break;
00293             }
00294 
00295           if (a.cidx(j+1) != a.cidx(j))
00296             {
00297               octave_idx_type ru = a.ridx(a.cidx(j));
00298               octave_idx_type rl = a.ridx(a.cidx(j+1)-1);
00299 
00300               if (j - ru > upper_band)
00301                 upper_band = j - ru;
00302 
00303               if (rl - j > lower_band)
00304                 lower_band = rl - j;
00305             }
00306         }
00307 
00308       if (!singular)
00309         {
00310           bandden = double (nnz) /
00311             (double (ncols) * (double (lower_band) +
00312                                double (upper_band)) -
00313              0.5 * double (upper_band + 1) * double (upper_band) -
00314              0.5 * double (lower_band + 1) * double (lower_band));
00315 
00316           if (nrows == ncols && sp_bandden != 1. && bandden > sp_bandden)
00317             {
00318               if (upper_band == 1 && lower_band == 1)
00319                 typ = MatrixType::Tridiagonal;
00320               else
00321                 typ = MatrixType::Banded;
00322 
00323               octave_idx_type nnz_in_band =
00324                 (upper_band + lower_band + 1) * nrows -
00325                 (1 + upper_band) * upper_band / 2 -
00326                 (1 + lower_band) * lower_band / 2;
00327               if (nnz_in_band == nnz)
00328                 dense = true;
00329               else
00330                 dense = false;
00331             }
00332           else if (upper_band == 0)
00333             typ = MatrixType::Lower;
00334           else if (lower_band == 0)
00335             typ = MatrixType::Upper;
00336 
00337           if (upper_band == lower_band && nrows == ncols)
00338             maybe_hermitian = true;
00339         }
00340 
00341       if (typ == MatrixType::Full)
00342         {
00343           // Search for a permuted triangular matrix, and test if
00344           // permutation is singular
00345 
00346           // FIXME
00347           // Perhaps this should be based on a dmperm algorithm
00348           bool found = false;
00349 
00350           nperm = ncols;
00351           perm = new octave_idx_type [ncols];
00352 
00353           for (octave_idx_type i = 0; i < ncols; i++)
00354             perm [i] = -1;
00355 
00356           for (octave_idx_type i = 0; i < nm; i++)
00357             {
00358               found = false;
00359 
00360               for (octave_idx_type j = 0; j < ncols; j++)
00361                 {
00362                   if ((a.cidx(j+1) - a.cidx(j)) > 0 &&
00363                       (a.ridx(a.cidx(j+1)-1) == i))
00364                     {
00365                       perm [i] = j;
00366                       found = true;
00367                       break;
00368                     }
00369                 }
00370 
00371               if (!found)
00372                 break;
00373             }
00374 
00375           if (found)
00376             {
00377               typ = MatrixType::Permuted_Upper;
00378               if (ncols > nrows)
00379                 {
00380                   octave_idx_type k = nrows;
00381                   for (octave_idx_type i = 0; i < ncols; i++)
00382                     if (perm [i] == -1)
00383                       perm[i] = k++;
00384                 }
00385             }
00386           else if (a.cidx(nm) == a.cidx(ncols))
00387             {
00388               nperm = nrows;
00389               delete [] perm;
00390               perm = new octave_idx_type [nrows];
00391               OCTAVE_LOCAL_BUFFER (octave_idx_type, tmp, nrows);
00392 
00393               for (octave_idx_type i = 0; i < nrows; i++)
00394                 {
00395                   perm [i] = -1;
00396                   tmp [i] = -1;
00397                 }
00398 
00399               for (octave_idx_type j = 0; j < ncols; j++)
00400                 for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++)
00401                     perm [a.ridx(i)] = j;
00402 
00403               found = true;
00404               for (octave_idx_type i = 0; i < nm; i++)
00405                 if (perm[i] == -1)
00406                   {
00407                     found = false;
00408                     break;
00409                   }
00410                 else
00411                   {
00412                     tmp[perm[i]] = 1;
00413                   }
00414 
00415               if (found)
00416                 {
00417                   octave_idx_type k = ncols;
00418                   for (octave_idx_type i = 0; i < nrows; i++)
00419                     {
00420                       if (tmp[i] == -1)
00421                         {
00422                           if (k < nrows)
00423                             {
00424                               perm[k++] = i;
00425                             }
00426                           else
00427                             {
00428                               found = false;
00429                               break;
00430                             }
00431                         }
00432                     }
00433                 }
00434 
00435               if (found)
00436                 typ = MatrixType::Permuted_Lower;
00437               else
00438                 {
00439                   delete [] perm;
00440                   nperm = 0;
00441                 }
00442             }
00443           else
00444             {
00445               delete [] perm;
00446               nperm = 0;
00447             }
00448         }
00449 
00450       // FIXME
00451       // Disable lower under-determined and upper over-determined problems
00452       // as being detected, and force to treat as singular. As this seems
00453       // to cause issues
00454       if (((typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
00455            && nrows > ncols) ||
00456           ((typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
00457            && nrows < ncols))
00458         {
00459           if (typ == MatrixType::Permuted_Upper ||
00460               typ == MatrixType::Permuted_Lower)
00461             delete [] perm;
00462           nperm = 0;
00463           typ = MatrixType::Rectangular;
00464         }
00465 
00466       if (typ == MatrixType::Full && ncols != nrows)
00467         typ = MatrixType::Rectangular;
00468 
00469       if (maybe_hermitian && (typ == MatrixType::Full ||
00470                               typ == MatrixType::Tridiagonal ||
00471                               typ == MatrixType::Banded))
00472         {
00473           bool is_herm = true;
00474 
00475           // first, check whether the diagonal is positive & extract it
00476           ColumnVector diag (ncols);
00477 
00478           for (octave_idx_type j = 0; is_herm && j < ncols; j++)
00479             {
00480               is_herm = false;
00481               for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++)
00482                 {
00483                   if (a.ridx(i) == j)
00484                     {
00485                       double d = a.data(i);
00486                       is_herm = d > 0.;
00487                       diag(j) = d;
00488                       break;
00489                     }
00490                 }
00491             }
00492 
00493 
00494           // next, check symmetry and 2x2 positiveness
00495 
00496           for (octave_idx_type j = 0; is_herm && j < ncols; j++)
00497             for (octave_idx_type i = a.cidx(j); is_herm && i < a.cidx(j+1); i++)
00498               {
00499                 octave_idx_type k = a.ridx(i);
00500                 is_herm = k == j;
00501                 if (is_herm)
00502                   continue;
00503                 double d = a.data(i);
00504                 if (d*d < diag(j)*diag(k))
00505                   {
00506                     for (octave_idx_type l = a.cidx(k); l < a.cidx(k+1); l++)
00507                       {
00508                         if (a.ridx(l) == j)
00509                           {
00510                             is_herm = a.data(l) == d;
00511                             break;
00512                           }
00513                       }
00514                   }
00515               }
00516 
00517           if (is_herm)
00518             {
00519               if (typ == MatrixType::Full)
00520                 typ = MatrixType::Hermitian;
00521               else if (typ == MatrixType::Banded)
00522                 typ = MatrixType::Banded_Hermitian;
00523               else
00524                 typ = MatrixType::Tridiagonal_Hermitian;
00525             }
00526         }
00527     }
00528 }
00529 
00530 MatrixType::MatrixType (const SparseComplexMatrix &a)
00531   : typ (MatrixType::Unknown),
00532     sp_bandden (0), bandden (0), upper_band (0), lower_band (0),
00533     dense (false), full (false), nperm (0), perm (0)
00534 {
00535   octave_idx_type nrows = a.rows ();
00536   octave_idx_type ncols = a.cols ();
00537   octave_idx_type nm = (ncols < nrows ? ncols : nrows);
00538   octave_idx_type nnz = a.nnz ();
00539 
00540   if (octave_sparse_params::get_key ("spumoni") != 0.)
00541     (*current_liboctave_warning_handler)
00542       ("Calculating Sparse Matrix Type");
00543 
00544   sp_bandden = octave_sparse_params::get_bandden();
00545   bool maybe_hermitian = false;
00546   typ = MatrixType::Full;
00547 
00548   if (nnz == nm)
00549     {
00550       matrix_type tmp_typ = MatrixType::Diagonal;
00551       octave_idx_type i;
00552       // Maybe the matrix is diagonal
00553       for (i = 0; i < nm; i++)
00554         {
00555           if (a.cidx(i+1) != a.cidx(i) + 1)
00556             {
00557               tmp_typ = MatrixType::Full;
00558               break;
00559             }
00560           if (a.ridx(i) != i)
00561             {
00562               tmp_typ = MatrixType::Permuted_Diagonal;
00563               break;
00564             }
00565         }
00566 
00567       if (tmp_typ == MatrixType::Permuted_Diagonal)
00568         {
00569           std::vector<bool> found (nrows);
00570 
00571           for (octave_idx_type j = 0; j < i; j++)
00572             found [j] = true;
00573           for (octave_idx_type j = i; j < nrows; j++)
00574             found [j] = false;
00575 
00576           for (octave_idx_type j = i; j < nm; j++)
00577             {
00578               if ((a.cidx(j+1) > a.cidx(j) + 1)  ||
00579                   ((a.cidx(j+1) == a.cidx(j) + 1) && found [a.ridx(j)]))
00580                 {
00581                   tmp_typ = MatrixType::Full;
00582                   break;
00583                 }
00584               found [a.ridx(j)] = true;
00585             }
00586         }
00587       typ = tmp_typ;
00588     }
00589 
00590   if (typ == MatrixType::Full)
00591     {
00592       // Search for banded, upper and lower triangular matrices
00593       bool singular = false;
00594       upper_band = 0;
00595       lower_band = 0;
00596       for (octave_idx_type j = 0; j < ncols; j++)
00597         {
00598           bool zero_on_diagonal = false;
00599           if (j < nrows)
00600             {
00601               zero_on_diagonal = true;
00602               for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++)
00603                 if (a.ridx(i) == j)
00604                   {
00605                     zero_on_diagonal = false;
00606                     break;
00607                   }
00608             }
00609 
00610           if (zero_on_diagonal)
00611             {
00612               singular = true;
00613               break;
00614             }
00615 
00616           if (a.cidx(j+1) != a.cidx(j))
00617             {
00618               octave_idx_type ru = a.ridx(a.cidx(j));
00619               octave_idx_type rl = a.ridx(a.cidx(j+1)-1);
00620 
00621               if (j - ru > upper_band)
00622                 upper_band = j - ru;
00623 
00624               if (rl - j > lower_band)
00625                 lower_band = rl - j;
00626             }
00627         }
00628 
00629       if (!singular)
00630         {
00631           bandden = double (nnz) /
00632             (double (ncols) * (double (lower_band) +
00633                                double (upper_band)) -
00634              0.5 * double (upper_band + 1) * double (upper_band) -
00635              0.5 * double (lower_band + 1) * double (lower_band));
00636 
00637           if (nrows == ncols && sp_bandden != 1. && bandden > sp_bandden)
00638             {
00639               if (upper_band == 1 && lower_band == 1)
00640                 typ = MatrixType::Tridiagonal;
00641               else
00642                 typ = MatrixType::Banded;
00643 
00644               octave_idx_type nnz_in_band =
00645                 (upper_band + lower_band + 1) * nrows -
00646                 (1 + upper_band) * upper_band / 2 -
00647                 (1 + lower_band) * lower_band / 2;
00648               if (nnz_in_band == nnz)
00649                 dense = true;
00650               else
00651                 dense = false;
00652             }
00653           else if (upper_band == 0)
00654             typ = MatrixType::Lower;
00655           else if (lower_band == 0)
00656             typ = MatrixType::Upper;
00657 
00658           if (upper_band == lower_band && nrows == ncols)
00659             maybe_hermitian = true;
00660         }
00661 
00662       if (typ == MatrixType::Full)
00663         {
00664           // Search for a permuted triangular matrix, and test if
00665           // permutation is singular
00666 
00667           // FIXME
00668           // Perhaps this should be based on a dmperm algorithm
00669           bool found = false;
00670 
00671           nperm = ncols;
00672           perm = new octave_idx_type [ncols];
00673 
00674           for (octave_idx_type i = 0; i < ncols; i++)
00675             perm [i] = -1;
00676 
00677           for (octave_idx_type i = 0; i < nm; i++)
00678             {
00679               found = false;
00680 
00681               for (octave_idx_type j = 0; j < ncols; j++)
00682                 {
00683                   if ((a.cidx(j+1) - a.cidx(j)) > 0 &&
00684                       (a.ridx(a.cidx(j+1)-1) == i))
00685                     {
00686                       perm [i] = j;
00687                       found = true;
00688                       break;
00689                     }
00690                 }
00691 
00692               if (!found)
00693                 break;
00694             }
00695 
00696           if (found)
00697             {
00698               typ = MatrixType::Permuted_Upper;
00699               if (ncols > nrows)
00700                 {
00701                   octave_idx_type k = nrows;
00702                   for (octave_idx_type i = 0; i < ncols; i++)
00703                     if (perm [i] == -1)
00704                       perm[i] = k++;
00705                 }
00706             }
00707           else if (a.cidx(nm) == a.cidx(ncols))
00708             {
00709               nperm = nrows;
00710               delete [] perm;
00711               perm = new octave_idx_type [nrows];
00712               OCTAVE_LOCAL_BUFFER (octave_idx_type, tmp, nrows);
00713 
00714               for (octave_idx_type i = 0; i < nrows; i++)
00715                 {
00716                   perm [i] = -1;
00717                   tmp [i] = -1;
00718                 }
00719 
00720               for (octave_idx_type j = 0; j < ncols; j++)
00721                 for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++)
00722                     perm [a.ridx(i)] = j;
00723 
00724               found = true;
00725               for (octave_idx_type i = 0; i < nm; i++)
00726                 if (perm[i] == -1)
00727                   {
00728                     found = false;
00729                     break;
00730                   }
00731                 else
00732                   {
00733                     tmp[perm[i]] = 1;
00734                   }
00735 
00736               if (found)
00737                 {
00738                   octave_idx_type k = ncols;
00739                   for (octave_idx_type i = 0; i < nrows; i++)
00740                     {
00741                       if (tmp[i] == -1)
00742                         {
00743                           if (k < nrows)
00744                             {
00745                               perm[k++] = i;
00746                             }
00747                           else
00748                             {
00749                               found = false;
00750                               break;
00751                             }
00752                         }
00753                     }
00754                 }
00755 
00756               if (found)
00757                 typ = MatrixType::Permuted_Lower;
00758               else
00759                 {
00760                   delete [] perm;
00761                   nperm = 0;
00762                 }
00763             }
00764           else
00765             {
00766               delete [] perm;
00767               nperm = 0;
00768             }
00769         }
00770 
00771       // FIXME
00772       // Disable lower under-determined and upper over-determined problems
00773       // as being detected, and force to treat as singular. As this seems
00774       // to cause issues
00775       if (((typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
00776            && nrows > ncols) ||
00777           ((typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
00778            && nrows < ncols))
00779         {
00780           if (typ == MatrixType::Permuted_Upper ||
00781               typ == MatrixType::Permuted_Lower)
00782             delete [] perm;
00783           nperm = 0;
00784           typ = MatrixType::Rectangular;
00785         }
00786 
00787       if (typ == MatrixType::Full && ncols != nrows)
00788         typ = MatrixType::Rectangular;
00789 
00790       if (maybe_hermitian && (typ == MatrixType::Full ||
00791                               typ == MatrixType::Tridiagonal ||
00792                               typ == MatrixType::Banded))
00793         {
00794           bool is_herm = true;
00795 
00796           // first, check whether the diagonal is positive & extract it
00797           ColumnVector diag (ncols);
00798 
00799           for (octave_idx_type j = 0; is_herm && j < ncols; j++)
00800             {
00801               is_herm = false;
00802               for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++)
00803                 {
00804                   if (a.ridx(i) == j)
00805                     {
00806                       Complex d = a.data(i);
00807                       is_herm = d.real() > 0. && d.imag() == 0.;
00808                       diag(j) = d.real();
00809                       break;
00810                     }
00811                 }
00812             }
00813 
00814           // next, check symmetry and 2x2 positiveness
00815 
00816           for (octave_idx_type j = 0; is_herm && j < ncols; j++)
00817             for (octave_idx_type i = a.cidx(j); is_herm && i < a.cidx(j+1); i++)
00818               {
00819                 octave_idx_type k = a.ridx(i);
00820                 is_herm = k == j;
00821                 if (is_herm)
00822                   continue;
00823                 Complex d = a.data(i);
00824                 if (std::norm (d) < diag(j)*diag(k))
00825                   {
00826                     d = std::conj (d);
00827                     for (octave_idx_type l = a.cidx(k); l < a.cidx(k+1); l++)
00828                       {
00829                         if (a.ridx(l) == j)
00830                           {
00831                             is_herm = a.data(l) == d;
00832                             break;
00833                           }
00834                       }
00835                   }
00836               }
00837 
00838 
00839           if (is_herm)
00840             {
00841               if (typ == MatrixType::Full)
00842                 typ = MatrixType::Hermitian;
00843               else if (typ == MatrixType::Banded)
00844                 typ = MatrixType::Banded_Hermitian;
00845               else
00846                 typ = MatrixType::Tridiagonal_Hermitian;
00847             }
00848         }
00849     }
00850 }
00851 MatrixType::MatrixType (const matrix_type t, bool _full)
00852   : typ (MatrixType::Unknown),
00853     sp_bandden (octave_sparse_params::get_bandden()),
00854     bandden (0), upper_band (0), lower_band (0),
00855     dense (false), full (_full), nperm (0), perm (0)
00856 {
00857   if (t == MatrixType::Unknown || t == MatrixType::Full
00858       || t == MatrixType::Diagonal || t == MatrixType::Permuted_Diagonal
00859       || t == MatrixType::Upper || t == MatrixType::Lower
00860       || t == MatrixType::Tridiagonal || t == MatrixType::Tridiagonal_Hermitian
00861       || t == MatrixType::Rectangular)
00862     typ = t;
00863   else
00864     (*current_liboctave_warning_handler) ("Invalid matrix type");
00865 }
00866 
00867 MatrixType::MatrixType (const matrix_type t, const octave_idx_type np,
00868                         const octave_idx_type *p, bool _full)
00869   : typ (MatrixType::Unknown),
00870     sp_bandden (octave_sparse_params::get_bandden()),
00871     bandden (0), upper_band (0), lower_band (0),
00872     dense (false), full (_full), nperm (0), perm (0)
00873 {
00874   if ((t == MatrixType::Permuted_Upper || t == MatrixType::Permuted_Lower) &&
00875       np > 0 && p != 0)
00876     {
00877       typ = t;
00878       nperm = np;
00879       perm = new octave_idx_type [nperm];
00880       for (octave_idx_type i = 0; i < nperm; i++)
00881         perm[i] = p[i];
00882     }
00883   else
00884     (*current_liboctave_warning_handler) ("Invalid matrix type");
00885 }
00886 
00887 MatrixType::MatrixType (const matrix_type t, const octave_idx_type ku,
00888                         const octave_idx_type kl, bool _full)
00889   : typ (MatrixType::Unknown),
00890     sp_bandden (octave_sparse_params::get_bandden()),
00891     bandden (0), upper_band (0), lower_band (0),
00892     dense (false), full (_full), nperm (0), perm (0)
00893 {
00894   if (t == MatrixType::Banded || t == MatrixType::Banded_Hermitian)
00895     {
00896       typ = t;
00897       upper_band = ku;
00898       lower_band = kl;
00899     }
00900   else
00901     (*current_liboctave_warning_handler) ("Invalid sparse matrix type");
00902 }
00903 
00904 MatrixType::~MatrixType (void)
00905 {
00906   if (nperm != 0)
00907     {
00908       delete [] perm;
00909     }
00910 }
00911 
00912 MatrixType&
00913 MatrixType::operator = (const MatrixType& a)
00914 {
00915   if (this != &a)
00916     {
00917       typ = a.typ;
00918       sp_bandden = a.sp_bandden;
00919       bandden = a.bandden;
00920       upper_band = a.upper_band;
00921       lower_band = a.lower_band;
00922       dense = a.dense;
00923       full = a.full;
00924 
00925       if (nperm)
00926         {
00927           delete[] perm;
00928         }
00929 
00930       if (a.nperm != 0)
00931         {
00932           perm = new octave_idx_type [a.nperm];
00933           for (octave_idx_type i = 0; i < a.nperm; i++)
00934             perm[i] = a.perm[i];
00935         }
00936 
00937       nperm = a.nperm;
00938     }
00939 
00940   return *this;
00941 }
00942 
00943 int
00944 MatrixType::type (bool quiet)
00945 {
00946   if (typ != MatrixType::Unknown && (full ||
00947       sp_bandden == octave_sparse_params::get_bandden()))
00948     {
00949       if (!quiet &&
00950           octave_sparse_params::get_key ("spumoni") != 0.)
00951         (*current_liboctave_warning_handler)
00952           ("Using Cached Matrix Type");
00953 
00954       return typ;
00955     }
00956 
00957   if (typ != MatrixType::Unknown &&
00958       octave_sparse_params::get_key ("spumoni") != 0.)
00959     (*current_liboctave_warning_handler)
00960       ("Invalidating Matrix Type");
00961 
00962   typ = MatrixType::Unknown;
00963 
00964   return typ;
00965 }
00966 
00967 int
00968 MatrixType::type (const SparseMatrix &a)
00969 {
00970   if (typ != MatrixType::Unknown && (full ||
00971       sp_bandden == octave_sparse_params::get_bandden()))
00972     {
00973       if (octave_sparse_params::get_key ("spumoni") != 0.)
00974         (*current_liboctave_warning_handler)
00975           ("Using Cached Matrix Type");
00976 
00977       return typ;
00978     }
00979 
00980   MatrixType tmp_typ (a);
00981   typ = tmp_typ.typ;
00982   sp_bandden = tmp_typ.sp_bandden;
00983   bandden = tmp_typ.bandden;
00984   upper_band = tmp_typ.upper_band;
00985   lower_band = tmp_typ.lower_band;
00986   dense = tmp_typ.dense;
00987   full = tmp_typ.full;
00988   nperm = tmp_typ.nperm;
00989 
00990   if (nperm != 0)
00991     {
00992       perm = new octave_idx_type [nperm];
00993       for (octave_idx_type i = 0; i < nperm; i++)
00994         perm[i] = tmp_typ.perm[i];
00995     }
00996 
00997   return typ;
00998 }
00999 
01000 int
01001 MatrixType::type (const SparseComplexMatrix &a)
01002 {
01003   if (typ != MatrixType::Unknown && (full ||
01004       sp_bandden == octave_sparse_params::get_bandden()))
01005     {
01006       if (octave_sparse_params::get_key ("spumoni") != 0.)
01007         (*current_liboctave_warning_handler)
01008           ("Using Cached Matrix Type");
01009 
01010       return typ;
01011     }
01012 
01013   MatrixType tmp_typ (a);
01014   typ = tmp_typ.typ;
01015   sp_bandden = tmp_typ.sp_bandden;
01016   bandden = tmp_typ.bandden;
01017   upper_band = tmp_typ.upper_band;
01018   lower_band = tmp_typ.lower_band;
01019   dense = tmp_typ.dense;
01020   full = tmp_typ.full;
01021   nperm = tmp_typ.nperm;
01022 
01023   if (nperm != 0)
01024     {
01025       perm = new octave_idx_type [nperm];
01026       for (octave_idx_type i = 0; i < nperm; i++)
01027         perm[i] = tmp_typ.perm[i];
01028     }
01029 
01030   return typ;
01031 }
01032 
01033 int
01034 MatrixType::type (const Matrix &a)
01035 {
01036   if (typ != MatrixType::Unknown)
01037     {
01038       if (octave_sparse_params::get_key ("spumoni") != 0.)
01039         (*current_liboctave_warning_handler)
01040           ("Using Cached Matrix Type");
01041 
01042       return typ;
01043     }
01044 
01045   MatrixType tmp_typ (a);
01046   typ = tmp_typ.typ;
01047   full = tmp_typ.full;
01048   nperm = tmp_typ.nperm;
01049 
01050   if (nperm != 0)
01051     {
01052       perm = new octave_idx_type [nperm];
01053       for (octave_idx_type i = 0; i < nperm; i++)
01054         perm[i] = tmp_typ.perm[i];
01055     }
01056 
01057   return typ;
01058 }
01059 
01060 int
01061 MatrixType::type (const ComplexMatrix &a)
01062 {
01063   if (typ != MatrixType::Unknown)
01064     {
01065       if (octave_sparse_params::get_key ("spumoni") != 0.)
01066         (*current_liboctave_warning_handler)
01067           ("Using Cached Matrix Type");
01068 
01069       return typ;
01070     }
01071 
01072   MatrixType tmp_typ (a);
01073   typ = tmp_typ.typ;
01074   full = tmp_typ.full;
01075   nperm = tmp_typ.nperm;
01076 
01077   if (nperm != 0)
01078     {
01079       perm = new octave_idx_type [nperm];
01080       for (octave_idx_type i = 0; i < nperm; i++)
01081         perm[i] = tmp_typ.perm[i];
01082     }
01083 
01084   return typ;
01085 }
01086 
01087 int
01088 MatrixType::type (const FloatMatrix &a)
01089 {
01090   if (typ != MatrixType::Unknown)
01091     {
01092       if (octave_sparse_params::get_key ("spumoni") != 0.)
01093         (*current_liboctave_warning_handler)
01094           ("Using Cached Matrix Type");
01095 
01096       return typ;
01097     }
01098 
01099   MatrixType tmp_typ (a);
01100   typ = tmp_typ.typ;
01101   full = tmp_typ.full;
01102   nperm = tmp_typ.nperm;
01103 
01104   if (nperm != 0)
01105     {
01106       perm = new octave_idx_type [nperm];
01107       for (octave_idx_type i = 0; i < nperm; i++)
01108         perm[i] = tmp_typ.perm[i];
01109     }
01110 
01111   return typ;
01112 }
01113 
01114 int
01115 MatrixType::type (const FloatComplexMatrix &a)
01116 {
01117   if (typ != MatrixType::Unknown)
01118     {
01119       if (octave_sparse_params::get_key ("spumoni") != 0.)
01120         (*current_liboctave_warning_handler)
01121           ("Using Cached Matrix Type");
01122 
01123       return typ;
01124     }
01125 
01126   MatrixType tmp_typ (a);
01127   typ = tmp_typ.typ;
01128   full = tmp_typ.full;
01129   nperm = tmp_typ.nperm;
01130 
01131   if (nperm != 0)
01132     {
01133       perm = new octave_idx_type [nperm];
01134       for (octave_idx_type i = 0; i < nperm; i++)
01135         perm[i] = tmp_typ.perm[i];
01136     }
01137 
01138   return typ;
01139 }
01140 
01141 void
01142 MatrixType::info () const
01143 {
01144   if (octave_sparse_params::get_key ("spumoni") != 0.)
01145     {
01146       if (typ == MatrixType::Unknown)
01147         (*current_liboctave_warning_handler)
01148           ("Unknown Matrix Type");
01149       else if (typ == MatrixType::Diagonal)
01150         (*current_liboctave_warning_handler)
01151           ("Diagonal Sparse Matrix");
01152       else if (typ == MatrixType::Permuted_Diagonal)
01153         (*current_liboctave_warning_handler)
01154           ("Permuted Diagonal Sparse Matrix");
01155       else if (typ == MatrixType::Upper)
01156         (*current_liboctave_warning_handler)
01157           ("Upper Triangular Matrix");
01158       else if (typ == MatrixType::Lower)
01159         (*current_liboctave_warning_handler)
01160           ("Lower Triangular Matrix");
01161       else if (typ == MatrixType::Permuted_Upper)
01162         (*current_liboctave_warning_handler)
01163           ("Permuted Upper Triangular Matrix");
01164       else if (typ == MatrixType::Permuted_Lower)
01165         (*current_liboctave_warning_handler)
01166           ("Permuted Lower Triangular Matrix");
01167       else if (typ == MatrixType::Banded)
01168         (*current_liboctave_warning_handler)
01169           ("Banded Sparse Matrix %d-1-%d (Density %f)", lower_band,
01170            upper_band, bandden);
01171       else if (typ == MatrixType::Banded_Hermitian)
01172         (*current_liboctave_warning_handler)
01173           ("Banded Hermitian/Symmetric Sparse Matrix %d-1-%d (Density %f)",
01174            lower_band, upper_band, bandden);
01175       else if (typ == MatrixType::Hermitian)
01176         (*current_liboctave_warning_handler)
01177           ("Hermitian/Symmetric Matrix");
01178       else if (typ == MatrixType::Tridiagonal)
01179         (*current_liboctave_warning_handler)
01180           ("Tridiagonal Sparse Matrix");
01181       else if (typ == MatrixType::Tridiagonal_Hermitian)
01182         (*current_liboctave_warning_handler)
01183           ("Hermitian/Symmetric Tridiagonal Sparse Matrix");
01184       else if (typ == MatrixType::Rectangular)
01185         (*current_liboctave_warning_handler)
01186           ("Rectangular/Singular Matrix");
01187       else if (typ == MatrixType::Full)
01188         (*current_liboctave_warning_handler)
01189           ("Full Matrix");
01190     }
01191 }
01192 
01193 void
01194 MatrixType::mark_as_symmetric (void)
01195 {
01196   if (typ == MatrixType::Tridiagonal ||
01197       typ == MatrixType::Tridiagonal_Hermitian)
01198     typ = MatrixType::Tridiagonal_Hermitian;
01199   else if (typ == MatrixType::Banded ||
01200            typ == MatrixType::Banded_Hermitian)
01201     typ = MatrixType::Banded_Hermitian;
01202   else if (typ == MatrixType::Full || typ == MatrixType::Hermitian ||
01203            typ == MatrixType::Unknown)
01204     typ = MatrixType::Hermitian;
01205   else
01206     (*current_liboctave_error_handler)
01207       ("Can not mark current matrix type as symmetric");
01208 }
01209 
01210 void
01211 MatrixType::mark_as_unsymmetric (void)
01212 {
01213   if (typ == MatrixType::Tridiagonal ||
01214       typ == MatrixType::Tridiagonal_Hermitian)
01215     typ = MatrixType::Tridiagonal;
01216   else if (typ == MatrixType::Banded ||
01217            typ == MatrixType::Banded_Hermitian)
01218     typ = MatrixType::Banded;
01219   else if (typ == MatrixType::Full || typ == MatrixType::Hermitian ||
01220            typ == MatrixType::Unknown)
01221     typ = MatrixType::Full;
01222 }
01223 
01224 void
01225 MatrixType::mark_as_permuted (const octave_idx_type np, const octave_idx_type *p)
01226 {
01227   nperm = np;
01228   perm = new octave_idx_type [nperm];
01229   for (octave_idx_type i = 0; i < nperm; i++)
01230     perm[i] = p[i];
01231 
01232   if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal)
01233     typ = MatrixType::Permuted_Diagonal;
01234   else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
01235     typ = MatrixType::Permuted_Upper;
01236   else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
01237     typ = MatrixType::Permuted_Lower;
01238   else
01239     (*current_liboctave_error_handler)
01240       ("Can not mark current matrix type as symmetric");
01241 }
01242 
01243 void
01244 MatrixType::mark_as_unpermuted (void)
01245 {
01246   if (nperm)
01247     {
01248       nperm = 0;
01249       delete [] perm;
01250     }
01251 
01252   if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal)
01253     typ = MatrixType::Diagonal;
01254   else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
01255     typ = MatrixType::Upper;
01256   else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
01257     typ = MatrixType::Lower;
01258 }
01259 
01260 MatrixType
01261 MatrixType::transpose (void) const
01262 {
01263   MatrixType retval (*this);
01264   if (typ == MatrixType::Upper)
01265     retval.typ = MatrixType::Lower;
01266   else if (typ == MatrixType::Permuted_Upper)
01267     retval.typ = MatrixType::Permuted_Lower;
01268   else if (typ == MatrixType::Lower)
01269     retval.typ = MatrixType::Upper;
01270   else if (typ == MatrixType::Permuted_Lower)
01271     retval.typ = MatrixType::Permuted_Upper;
01272   else if (typ == MatrixType::Banded)
01273     {
01274       retval.upper_band = lower_band;
01275       retval.lower_band = upper_band;
01276     }
01277 
01278   return retval;
01279 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines