The ChainCon Software (Release 0.03)
atmodel3.h
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 ///
3 /// \file
4 ///
5 /// Algebraic topological model computation: Algorithm 3, using the SNF;
6 /// combinatorial version - for coefficients in Z_2.
7 ///
8 /////////////////////////////////////////////////////////////////////////////
9 
10 // Copyright (C) 2009-2016 by Pawel Pilarczyk.
11 //
12 // This file is part of my research software package. This is free software:
13 // you can redistribute it and/or modify it under the terms of the GNU
14 // General Public License as published by the Free Software Foundation,
15 // either version 3 of the License, or (at your option) any later version.
16 //
17 // This software is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this software; see the file "license.txt". If not,
24 // please, see <http://www.gnu.org/licenses/>.
25 
26 // Started on March 24, 2009. Last revision: June 18, 2012.
27 
28 
29 #ifndef _CHAINCON_ATMODEL3_H_
30 #define _CHAINCON_ATMODEL3_H_
31 
32 
33 // include some standard C++ header files
34 #include <istream>
35 #include <ostream>
36 
37 // include selected header files from the CHomP library
38 #include "chomp/system/config.h"
39 #include "chomp/system/textfile.h"
40 #include "chomp/system/timeused.h"
41 #include "chomp/struct/hashsets.h"
42 #include "chomp/struct/multitab.h"
43 #include "chomp/struct/integer.h"
44 #include "chomp/homology/chains.h"
45 
46 // include relevant local header files
47 #include "chaincon/combchain.h"
48 #include "chaincon/comblinmap.h"
49 
50 
51 // --------------------------------------------------
52 // -------------------- AT model --------------------
53 // --------------------------------------------------
54 
55 #ifndef _product_is_identity_
56 #define _product_is_identity_
57 /// Verifies if the product of the given two matrices is an identity matrix.
58 /// For each column C of A, computes G(C) and checks this chain.
59 inline bool product_is_identity
60  (const chomp::homology::mmatrix<chomp::homology::integer> &A,
61  const chomp::homology::mmatrix<chomp::homology::integer> &G)
62 {
63  if (A. getncols () != G. getnrows ())
64  return false;
65  if (G. getncols () != A. getnrows ())
66  return false;
67 
68  using chomp::homology::integer;
69  using chomp::homology::chain;
70  integer one;
71  one = 1;
72 
73  int_t nCols = A. getncols ();
74  for (int_t nCol = 0; nCol < nCols; ++ nCol)
75  {
76  const chain<integer> &col (A. getcol (nCol));
77  chain<integer> img;
78  int_t size = col. size ();
79  for (int_t pos = 0; pos < size; ++ pos)
80  {
81  img. add (G. getcol (col. num (pos)),
82  col. coef (pos));
83  }
84  if ((img. size () != 1) ||
85  (img. num (0) != nCol) ||
86  (img. coef (0) != one))
87  {
88  return false;
89  }
90  }
91  return true;
92 } /* product_is_identity */
93 #endif // _product_is_identity_
94 
95 /// Computes an algebraic topological model for the given
96 /// filtered finite cell complex "K".
97 /// Cells that represent homology generators are appended to the vector "H".
98 /// The projection map "pi", the inclusion from "H" to the complex "K",
99 /// and the homology gradient vector field "phi"
100 /// are assumed to be initially zero and are constructed.
101 template <class CellT, class CellArray1, class CellArray2, class CellRestrT>
102 void algTopModel3 (const CellArray1 &K, CellArray2 &H,
106  const CellRestrT &restr)
107 {
108  using chomp::homology::chaincomplex;
109  using chomp::homology::chain;
110  using chomp::homology::mmatrix;
111  using chomp::homology::timeused;
112  using chomp::homology::sout;
113 // using chomp::homology::scon;
114  using chomp::homology::sbug;
115  using chomp::homology::integer;
116  using chomp::homology::hashedset;
117  using chomp::homology::multitable;
118 
119  // don't do anything for an empty complex
120  if (K. empty ())
121  return;
122 
123  // start measuring total computation time of this routine
124  timeused compTime;
125  compTime = 0;
126 
127  // construct a chain complex
128  sbug << "[AT Model Algorithm 3.]\n";
129  sout << "Constructing the chain complex of K...\n";
130  timeused constrTime;
131  constrTime = 0;
132 
133  // set up the ring of coefficients Z_2
134  integer::initialize (2);
135  integer zero;
136  zero = 0;
137  integer one;
138  one = 1;
139 
140  // create the chain complex
141  const int_t KSize = K. size ();
142  const int dim = K [KSize - 1]. dim ();
143  const int trace_generators = 1;
144  const int trace_bases = 1;
145  chaincomplex<integer> cx (dim, trace_generators, trace_bases);
146 
147  // go through all the cells in the filter and compute boundaries
148  multitable<hashedset<CellT> > cells;
149  for (int_t i = 0; i < KSize; ++ i)
150  {
151  // retrieve the i-th cell in the filter
152  const CellT &c = K [i];
153 
154  // determine the dimension of this cell
155  int d = c. dim ();
156  if (d < 0)
157  {
158  throw "Reduced homology not supported "
159  "in combinatorial Algorithm 3.\n"
160  "Please, use Algorithm 4 with Z_2 instead.";
161  }
162 
163  // add the cell to the right array of cells
164  int_t cNum = cells [d]. size ();
165  cells [d]. add (c);
166 
167  // compute the boundary of this cell
168  int_t bLen = c. boundaryLength ();
169  for (int_t j = 0; j < bLen; ++ j)
170  {
171  // create the j-th boundary cell
172  CellT bCell (c, j);
173 
174  // ignore the coefficient (temporarily)
175  // int bCoef = c. boundaryCoef (j);
176 
177  // determine the number of the boundary cell
178  int_t bNum = cells [d - 1]. getnumber (bCell);
179 
180  // ignore the cell is it is not in the set
181  if (bNum < 0)
182  continue;
183 
184  // add the boundary relation to the chain complex
185  cx. add (d, bNum, cNum, one);
186  }
187  }
188 
189  // make sure that the size of the chain complex is enough
190  for (int d = 0; d <= dim; ++ d)
191  {
192  cx. def_gen (d, cells [d]. size ());
193  }
194 
195  // show timing information
196  sout << "The chain complex created in " << constrTime << ".\n";
197 
198  // compute the SNF
199  sout << "Computing the SNF of the boundary operator...\n";
200  timeused snfTime;
201  snfTime = 0;
202 
203  int *level = 0;
204  bool quiet = false;
205  cx. simple_form (level, quiet);
206 
207  // show timing information
208  sout << "The SNF computed in " << snfTime << ".\n";
209 
210  // DEBUG: Check if the change of basis matrices are correct.
211  if (true)
212  {
213  timeused verifTime;
214  verifTime = 0;
215  sout << "Change of basis check: ";
216  for (int q = 0; q <= dim; ++ q)
217  {
218  const mmatrix<integer> &G (cx. gethomgen (q));
219  const mmatrix<integer> &A (cx. getchgbasis (q));
220  if (!product_is_identity (G, A) ||
221  !product_is_identity (A, G))
222  {
223  sout << "Failed at level " << q << ".\n";
224  throw "Wrong change of basis detected.";
225  }
226  }
227  sout << "Completed successfully in " << verifTime << ".\n";
228  }
229 
230  // compute the g.v.f. together with the projection and the inclusion
231  sout << "Composing an algebraic topological model from the SNF...\n";
232  timeused atModTime;
233  atModTime = 0;
234 
235  // prepare the lists of chain complex generators
236  // which are also homology generators
237 // multitable <hashedset<int_t> > homGener;
238 
239  // prepare the matrices for psi
240  multitable <mmatrix<integer> > psi;
241 
242  // scan through the entire chain complex in the SNF
243  const mmatrix<integer> zeroMatrix;
244  for (int q = 0; q <= dim; ++ q)
245  {
246  // prepare a number for subsequent generator representants
247  int_t gen_number = 0;
248 
249  // get the matrices computed for the Smith Normal Form:
250  // the boundary at level q
251  const mmatrix<integer> &Dq = cx. getboundary (q);
252  // the boundary at level q + 1
253  const mmatrix<integer> &Dq1 = (q < dim) ?
254  cx. getboundary (q + 1) : zeroMatrix;
255  // the change of basis from the new one to the original one
256  const mmatrix<integer> &Gq = cx. gethomgen (q);
257  // the change of basis from the original one to the new one
258  const mmatrix<integer> &Aq = cx. getchgbasis (q);
259 
260  // set the size of the matrix psi in dimension q - 1
261  if (q)
262  {
263  psi [q - 1]. define (cells [q]. size (),
264  cells [q - 1]. size ());
265  }
266 
267  // process the bases of the chain complex in the SNF
268  int ncells = cells [q]. size ();
269  for (int i = 0; i < ncells; ++ i)
270  {
271  // get the column of the matrix Dq
272  const chain<integer> &column = Dq. getcol (i);
273 
274  // if the column in the SNF is nonzero (coef in Z_2!)
275  if (!column. empty ())
276  {
277  int b = column. num (0);
278  if (!q)
279  throw "Negative psi index.";
280  psi [q - 1]. add (i, b, one);
281  }
282 
283  // if the column in the SNF is zero
284  else if ((q == dim) || (Dq1. getrow (i). empty ()))
285  {
286  // add the number of this cell
287  // to the list of homology generators
288  // homGener [q]. add (i);
289 
290  // determine the real homology generator
291  const chain<integer> &genChain =
292  Gq. getcol (i);
293 
294  // define a representant of this generator
295  const CellT &repr = cells [q] [gen_number];
296  ++ gen_number;
297  H. push_back (repr);
298 
299  // compute the inclusion map on it
300  int_t genSize = genChain. size ();
301  for (int_t j = 0; j < genSize; ++ j)
302  {
303  int_t n = genChain. num (j);
304  const CellT &genCell = cells [q] [n];
305  incl. add (repr, genCell);
306  }
307 
308  // add this term to the projection
309  const chain<integer> &piRow =
310  Aq. getrow (i);
311  int_t piRowSize = piRow. size ();
312  for (int_t j = 0; j < piRowSize; ++ j)
313  {
314  int_t num = piRow. num (j);
315  const CellT &cell = cells [q] [num];
316  pi. add (cell, repr);
317  }
318  }
319  }
320  }
321 
322  // compute the matrices for phi_q and compose them into one map:
323  // \phi_{q - 1} := A^{-1}_q \circ \psi_{q - 1} \circ A_{q - 1}
324  sout << "Transferring the computed maps to the original basis...\n";
325  for (int q = 1; q <= dim; ++ q)
326  {
327  // consider the three matrices to be multiplied
328  const mmatrix<integer> &M_A = cx. getchgbasis (q - 1);
329  const mmatrix<integer> &M_psi = psi [q - 1];
330  const mmatrix<integer> &M_A1 = cx. gethomgen (q);
331 
332  // determine the numbers of columns in the matrices
333  int_t sizeA = M_A. getncols ();
334  int_t sizePsi = M_psi. getncols ();
335  int_t sizeA1 = M_A1. getncols ();
336 
337  // for all the columns in the first matrix on the right...
338  for (int_t i = 0; i < sizeA; ++ i)
339  {
340  // take the column
341  const chain<integer> &column = M_A. getcol (i);
342 
343  // compute its image by psi
344  chain<integer> psiC;
345  int_t sizeC = column. size ();
346  for (int_t j = 0; j < sizeC; ++ j)
347  {
348  int_t n = column. num (j);
349  if (n >= sizePsi)
350  continue;
351  psiC. add (M_psi. getcol (n), one);
352  }
353 
354  // compute the image of this image by A1
355  chain<integer> phiColumn;
356  int_t sizePsiC = psiC. size ();
357  for (int j = 0; j < sizePsiC; ++ j)
358  {
359  int_t n = psiC. num (j);
360  if (n >= sizeA1)
361  continue;
362  phiColumn. add (M_A1. getcol (n), one);
363  }
364 
365  // decode the resulting chain and put it in phi
366  int_t sizePhiColumn = phiColumn. size ();
367  for (int j = 0; j < sizePhiColumn; ++ j)
368  {
369  int_t n = phiColumn. num (j);
370  phi. add (cells [q - 1] [i],
371  cells [q] [n]);
372  }
373  }
374  }
375 
376  // show timing information
377  sout << "AT model composed from the SNF in " << atModTime << ".\n";
378 
379  // show information on the total computation time of this routine
380  sout << "AT model computed in " << compTime << ".\n";
381 
382  return;
383 } /* algTopModel3 */
384 
385 
386 #endif // _CHAINCON_ATMODEL3_H_
387 
void algTopModel3(const CellArray1 &K, CellArray2 &H, tCombLinMap< CellT, CellT > &pi, tCombLinMap< CellT, CellT > &incl, tCombLinMap< CellT, CellT > &phi, const CellRestrT &restr)
Computes an algebraic topological model for the given filtered finite cell complex "K"...
Definition: atmodel3.h:102
A combinatorial chain, that is, a chain with Z_2 coefficients.
A combinatorial linear map (for coefficients in Z_2).
A combinatorial linear map.
Definition: comblinmap.h:56
bool product_is_identity(const chomp::homology::mmatrix< chomp::homology::integer > &A, const chomp::homology::mmatrix< chomp::homology::integer > &G)
Verifies if the product of the given two matrices is an identity matrix.
Definition: atmodel3.h:60