• Main Page
  • Classes
  • Files
  • File List
  • File Members

chaincon/homgvf3.h

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////////
00002 ///
00003 /// \file
00004 ///
00005 /// Homology gradient vector field computation: Algorithm 3, using the SNF.
00006 ///
00007 /////////////////////////////////////////////////////////////////////////////
00008 
00009 // Copyright (C) 2009-2011 by Pawel Pilarczyk.
00010 //
00011 // This file is part of my research software package. This is free software:
00012 // you can redistribute it and/or modify it under the terms of the GNU
00013 // General Public License as published by the Free Software Foundation,
00014 // either version 3 of the License, or (at your option) any later version.
00015 //
00016 // This software is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 // GNU General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU General Public License
00022 // along with this software; see the file "license.txt". If not,
00023 // please, see <http://www.gnu.org/licenses/>.
00024 
00025 // Started on March 24, 2009. Last revision: March 24, 2011.
00026 
00027 
00028 #ifndef _CHAINCON_HOMGVF3_H_
00029 #define _CHAINCON_HOMGVF3_H_
00030 
00031 
00032 // include some standard C++ header files
00033 #include <istream>
00034 #include <ostream>
00035 
00036 // include selected header files from the CHomP library
00037 #include "chomp/system/config.h"
00038 #include "chomp/system/timeused.h"
00039 #include "chomp/system/textfile.h"
00040 #include "chomp/struct/hashsets.h"
00041 #include "chomp/struct/multitab.h"
00042 #include "chomp/struct/integer.h"
00043 #include "chomp/homology/chains.h"
00044 
00045 // include relevant local header files
00046 #include "chaincon/combchain.h"
00047 #include "chaincon/comblinmap.h"
00048 
00049 
00050 // --------------------------------------------------
00051 // ------------------ Homology GVF ------------------
00052 // --------------------------------------------------
00053 
00054 /// Verifies if the given mmatrix is an identity
00055 inline bool is_identity (const chomp::homology::mmatrix
00056         <chomp::homology::integer> &M)
00057 {
00058         int nCols = M. getncols ();
00059         for (int col = 0; col < nCols; ++ col)
00060         {
00061                 const chomp::homology::chain<chomp::homology::integer>
00062                         &column = M. getcol (col);
00063                 if (column. size () != 1)
00064                         return false;
00065                 if (column. num (0) != col)
00066                         return false;
00067         }
00068         return true;
00069 } /* is_identity */
00070 
00071 /// Computes the homology gradient vector field for the given
00072 /// filtered finite cell complex "K".
00073 /// Cells that represent homology generators are appended to the vector "H".
00074 /// The projection map "pi", the inclusion from "H" to the complex "K",
00075 /// and the homology gradient vector field "phi"
00076 /// are assumed to be initially zero and are constructed.
00077 template <class CellT, class CellArray1, class CellArray2>
00078 void homologyGVF3 (const CellArray1 &K, CellArray2 &H,
00079         tCombLinMap<CellT,CellT> &pi,
00080         tCombLinMap<CellT,CellT> &incl,
00081         tCombLinMap<CellT,CellT> &phi)
00082 {
00083         using chomp::homology::chaincomplex;
00084         using chomp::homology::chain;
00085         using chomp::homology::mmatrix;
00086         using chomp::homology::timeused;
00087         using chomp::homology::sout;
00088 //      using chomp::homology::scon;
00089         using chomp::homology::integer;
00090         using chomp::homology::hashedset;
00091         using chomp::homology::multitable;
00092 
00093         // don't do anything for an empty complex
00094         if (K. empty ())
00095                 return;
00096 
00097         // start measuring total computation time of this routine
00098         timeused compTime;
00099         compTime = 0;
00100 
00101         // construct a chain complex
00102         sout << "Constructing the chain complex of K...\n";
00103         timeused constrTime;
00104         constrTime = 0;
00105 
00106         // set up the ring of coefficients Z_2
00107         integer::initialize (2);
00108         integer zero;
00109         zero = 0;
00110         integer one;
00111         one = 1;
00112 
00113         // create the chain complex
00114         int_t KSize = K. size ();
00115         int dim = K [KSize - 1]. dim ();
00116         chaincomplex<integer> cx (dim, 1, 1);
00117 
00118         // go through all the cells in the filter and compute boundaries
00119         multitable<hashedset<CellT> > cells;
00120         for (int_t i = 0; i < KSize; ++ i)
00121         {
00122                 // retrieve the i-th cell in the filter
00123                 const CellT &c = K [i];
00124 
00125                 // determine the dimension of this cell
00126                 int d = c. dim ();
00127 
00128                 // add the cell to the right array of cells
00129                 int_t cNum = cells [d]. size ();
00130                 cells [d]. add (c);
00131 
00132                 // compute the boundary of this cell
00133                 int_t bLen = c. boundaryLength ();
00134                 for (int_t j = 0; j < bLen; ++ j)
00135                 {
00136                         // create the j-th boundary cell
00137                         CellT bCell (c, j);
00138 
00139                         // ignore the coefficient (temporarily)
00140                         // int bCoef = c. boundaryCoef (j);
00141 
00142                         // determine the number of the boundary cell
00143                         int_t bNum = cells [d - 1]. getnumber (bCell);
00144 
00145                         // add the boundary relation to the chain complex
00146                         cx. add (d, bNum, cNum, one);
00147                 }
00148         }
00149 
00150         // make sure that the size of the chain complex is enough
00151         for (int d = 0; d <= dim; ++ d)
00152         {
00153                 cx. def_gen (d, cells [d]. size ());
00154         }
00155 
00156         // show timing information
00157         sout << "The chain complex created in " << constrTime << ".\n";
00158 
00159         // compute the SNF
00160         sout << "Computing the SNF of the boundary operator...\n";
00161         timeused snfTime;
00162         snfTime = 0;
00163 
00164         int *level = 0;
00165         bool quiet = false;
00166         cx. simple_form (level, quiet);
00167 
00168         // DEBUG: Check if the change of basis matrices are correct.
00169         if (false)
00170         {
00171                 sout << "DEBUG CHECK: change of basis (this will take "
00172                         "a while)...\n";
00173                 for (int q = 0; q <= dim; ++ q)
00174                 {
00175                         mmatrix<integer> M, N;
00176                         M. multiply (cx. gethomgen (q),
00177                                 cx. getchgbasis (q));
00178                         N. multiply (cx. getchgbasis (q),
00179                                 cx. gethomgen (q));
00180                         if (!is_identity (M) || !is_identity (N))
00181                         {
00182                                 sout << "\nDEBUG ERROR: Wrong change of basis "
00183                                         "detected at level " << q << ".\n";
00184                         }
00185                 }
00186                 sout << "Note: The change of basis matrices were verified "
00187                         "successfully.\n";
00188         }
00189 
00190         // show timing information
00191         sout << "The SNF computed in " << snfTime << ".\n";
00192 
00193         // compute the g.v.f. together with the projection and the inclusion
00194         sout << "Composing a homology gradient vector field "
00195                 "from the SNF...\n";
00196         timeused gvfTime;
00197         gvfTime = 0;
00198 
00199         // prepare the lists of chain complex generators
00200         // which are also homology generators
00201 //      multitable <hashedset<int_t> > homGener;
00202 
00203         // prepare the matrices for psi
00204         multitable <mmatrix<integer> > psi;
00205 
00206         // scan through the entire chain complex in the SNF
00207         const mmatrix<integer> zeroMatrix;
00208         for (int q = 0; q <= dim; ++ q)
00209         {
00210                 // get the matrices computed for the Smith Normal Form:
00211                 // the boundary at level q
00212                 const mmatrix<integer> &Dq = cx. getboundary (q);
00213                 // the boundary at level q + 1
00214                 const mmatrix<integer> &Dq1 = (q < dim) ?
00215                         cx. getboundary (q + 1) : zeroMatrix;
00216                 // the change of basis from the new one to the original one
00217                 const mmatrix<integer> &Gq = cx. gethomgen (q);
00218                 // the change of basis from the original one to the new one
00219                 const mmatrix<integer> &Aq = cx. getchgbasis (q);
00220 
00221                 // set the size of the matrix psi in dimension q - 1
00222                 if (q)
00223                 {
00224                         psi [q - 1]. define (cells [q]. size (),
00225                                 cells [q - 1]. size ());
00226                 }
00227 
00228                 // process the bases of the chain complex in the SNF
00229                 int ncells = cells [q]. size ();
00230                 for (int i = 0; i < ncells; ++ i)
00231                 {
00232                         // get the column of the matrix Dq
00233                         const chain<integer> &column = Dq. getcol (i);
00234 
00235                         // if the column in the SNF is nonzero (coef in Z_2!)
00236                         if (!column. empty ())
00237                         {
00238                                 int b = column. num (0);
00239                                 if (!q)
00240                                         throw "Negative psi index.";
00241                                 psi [q - 1]. add (i, b, one);
00242                         }
00243                         
00244                         // if the column in the SNF is zero
00245                         else if ((q == dim) || (Dq1. getrow (i). empty ()))
00246                         {
00247                                 // add the number of this cell
00248                                 // to the list of homology generators
00249                         //      homGener [q]. add (i);
00250 
00251                                 // determine the real homology generator
00252                                 const chain<integer> &genChain =
00253                                         Gq. getcol (i);
00254 
00255                                 // take the first entry as a representant
00256                                 const CellT &repr =
00257                                         cells [q] [genChain. num (0)];
00258                                 H. push_back (repr);
00259 
00260                                 // compute the inclusion map on it
00261                                 int_t genSize = genChain. size ();
00262                                 for (int_t j = 0; j < genSize; ++ j)
00263                                 {
00264                                         int_t n = genChain. num (j);
00265                                         const CellT &genCell = cells [q] [n];
00266                                         incl. add (repr, genCell);
00267                                 }
00268 
00269                                 // add this term to the projection
00270                                 const chain<integer> &piRow =
00271                                         Aq. getrow (i);
00272                                 int_t piRowSize = piRow. size ();
00273                                 for (int_t j = 0; j < piRowSize; ++ j)
00274                                 {
00275                                         int_t num = piRow. num (j);
00276                                         const CellT &cell = cells [q] [num];
00277                                         pi. add (cell, repr);
00278                                 }
00279                         }
00280                 }
00281         }
00282 
00283         // compute the matrices for phi_q and compose them into one map:
00284         // \phi_{q - 1} := A^{-1}_q \circ \psi_{q - 1} \circ A_{q - 1}
00285         sout << "Transferring the computed gvf to the original basis...\n";
00286         for (int q = 1; q <= dim; ++ q)
00287         {
00288                 // consider the three matrices to be multiplied
00289                 const mmatrix<integer> &M_A = cx. getchgbasis (q - 1);
00290                 const mmatrix<integer> &M_psi = psi [q - 1];
00291                 const mmatrix<integer> &M_A1 = cx. gethomgen (q);
00292 
00293                 // determine the numbers of columns in the matrices
00294                 int_t sizeA = M_A. getncols ();
00295                 int_t sizePsi = M_psi. getncols ();
00296                 int_t sizeA1 = M_A1. getncols ();
00297 
00298                 // for all the columns in the first matrix on the right...
00299                 for (int_t i = 0; i < sizeA; ++ i)
00300                 {
00301                         // take the column
00302                         const chain<integer> &column = M_A. getcol (i);
00303 
00304                         // compute its image by psi
00305                         chain<integer> psiC;
00306                         int_t sizeC = column. size ();
00307                         for (int_t j = 0; j < sizeC; ++ j)
00308                         {
00309                                 int_t n = column. num (j);
00310                                 if (n >= sizePsi)
00311                                         continue;
00312                                 psiC. add (M_psi. getcol (n), one);
00313                         }
00314 
00315                         // compute the image of this image by A1
00316                         chain<integer> phiColumn;
00317                         int_t sizePsiC = psiC. size ();
00318                         for (int j = 0; j < sizePsiC; ++ j)
00319                         {
00320                                 int_t n = psiC. num (j);
00321                                 if (n >= sizeA1)
00322                                         continue;
00323                                 phiColumn. add (M_A1. getcol (n), one);
00324                         }
00325 
00326                         // decode the resulting chain and put it in phi
00327                         int_t sizePhiColumn = phiColumn. size ();
00328                         for (int j = 0; j < sizePhiColumn; ++ j)
00329                         {
00330                                 int_t n = phiColumn. num (j);
00331                                 phi. add (cells [q - 1] [i],
00332                                         cells [q] [n]);
00333                         }
00334                 }
00335         }
00336 
00337         // show timing information
00338         sout << "Homology gvf composed from the SNF in " << gvfTime << ".\n";
00339 
00340         // show information on the total computation time of this routine
00341         sout << "Homology gvf computed in " << compTime << ".\n";
00342 
00343         return;
00344 } /* homologyGVF3 */
00345 
00346 
00347 #endif // _CHAINCON_HOMGVF3_H_
00348 

Generated on Tue Apr 5 2011 00:06:32 for Chain Contraction Software by  doxygen 1.7.2