The ChainCon Software (Release 0.03)
atmodel3r.h
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 ///
3 /// \file
4 ///
5 /// Algebraic topological model computation: Algorithm 3, using the SNF;
6 /// version for an arbitrary commutative ring of coefficients.
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_ATMODEL3R_H_
30 #define _CHAINCON_ATMODEL3R_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/chain.h"
48 #include "chaincon/linmap.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 /// A friend of the 'integer' class (from the CHomP package)
96 /// that converts 'integer' objects to numbers of type 'int'.
97 class integerFriend: public chomp::homology::integer
98 {
99 public:
100  /// Constructor of the object from an 'integer' object.
101  integerFriend (const chomp::homology::integer &e):
102  chomp::homology::integer (e) {}
103 
104  /// Converts to the ordinary integer type.
105  operator int () const {return static_cast<int> (num);}
106 }; /* integerFriend */
107 
108 /// Translation of CHomP's 'integer' to an 'int' number.
109 /// This is an ugly function that uses an object of a friend class
110 /// in order to peek into the internals of the 'integer' object.
111 inline int integer2int (const chomp::homology::integer &e)
112 {
113  return static_cast<int> (integerFriend (e));
114 } /* integer2int */
115 
116 /// Computes an algebraic topological model for the given
117 /// filtered finite cell complex "K".
118 /// Cells that represent homology generators are appended to the vector "H".
119 /// The projection map "pi", the inclusion from "H" to the complex "K",
120 /// and the homology gradient vector field "phi"
121 /// are assumed to be initially zero and are constructed.
122 /// Note: This procedure is not well tested in case of Z_p with p != 2.
123 template <class CellT, class CoefT, class CellArray1, class CellArray2,
124  class CellRestrT>
125 void algTopModel3 (const CellArray1 &K, CellArray2 &H,
129  const CellRestrT &restr)
130 {
131  using chomp::homology::chaincomplex;
132  using chomp::homology::chain;
133  using chomp::homology::mmatrix;
134  using chomp::homology::timeused;
135  using chomp::homology::sout;
136 // using chomp::homology::scon;
137  using chomp::homology::sbug;
138  using chomp::homology::integer;
139  using chomp::homology::hashedset;
140  using chomp::homology::multitable;
141 
142  // don't do anything for an empty complex
143  if (K. empty ())
144  return;
145 
146  // start measuring total computation time of this routine
147  timeused compTime;
148  compTime = 0;
149 
150  // construct a chain complex
151  sbug << "[AT Model Algorithm 3r.]\n";
152  sout << "Constructing the chain complex of K...\n";
153  timeused constrTime;
154  constrTime = 0;
155 
156  // set up the appropriate ring of coefficients
157  integer::initialize (CoefT::getp ());
158  integer zero;
159  zero = 0;
160  integer one;
161  one = 1;
162 
163  // create the chain complex
164  const int_t KSize = K. size ();
165  const int dim = K [KSize - 1]. dim ();
166  const int trace_generators = 1;
167  const int trace_bases = 1;
168  chaincomplex<integer> cx (dim, trace_generators, trace_bases);
169 
170  // go through all the cells in the filter and compute boundaries
171  multitable<hashedset<CellT> > cells;
172  for (int_t i = 0; i < KSize; ++ i)
173  {
174  // retrieve the i-th cell in the filter
175  const CellT &c = K [i];
176 
177  // determine the dimension of this cell
178  int d = c. dim ();
179  if (d < 0)
180  {
181  throw "Reduced homology not supported "
182  "in Algorithm 3.\n"
183  "Please, use Algorithm 4 instead.";
184  }
185 
186  // add the cell to the right array of cells
187  int_t cNum = cells [d]. size ();
188  cells [d]. add (c);
189 
190  // compute the boundary of this cell
191  int_t bLen = c. boundaryLength ();
192  for (int_t j = 0; j < bLen; ++ j)
193  {
194  // create the j-th boundary cell
195  CellT bCell (c, j);
196 
197  // determine the number of the boundary cell
198  int_t bNum = cells [d - 1]. getnumber (bCell);
199 
200  // ignore the cell is it is not in the set
201  if (bNum < 0)
202  continue;
203 
204  // determine the coefficient
205  integer bCoef;
206  bCoef = c. boundaryCoef (j);
207 
208  // add the boundary relation to the chain complex
209  cx. add (d, bNum, cNum, bCoef);
210  }
211  }
212 
213  // make sure that the size of the chain complex is enough
214  // to contain all the cells
215  for (int d = 0; d <= dim; ++ d)
216  {
217  cx. def_gen (d, cells [d]. size ());
218  }
219 
220  // show timing information
221  sout << "The chain complex created in " << constrTime << ".\n";
222 
223  // compute the SNF
224  sout << "Computing the SNF of the boundary operator...\n";
225  timeused snfTime;
226  snfTime = 0;
227 
228  int *level = 0;
229  bool quiet = false;
230  cx. simple_form (level, quiet);
231 
232 // for (int q = dim; q >= 0; -- q)
233 // {
234 // sbug << "DEBUG: Simple form [" << q << "]:\n" <<
235 // cx. getboundary (q);
236 // }
237 
238  // show timing information
239  sout << "The SNF computed in " << snfTime << ".\n";
240 
241  // DEBUG: Check if the change of basis matrices are correct.
242  if (true)
243  {
244  timeused verifTime;
245  verifTime = 0;
246  sout << "Change of basis check: ";
247  for (int q = 0; q <= dim; ++ q)
248  {
249  const mmatrix<integer> &G (cx. gethomgen (q));
250  const mmatrix<integer> &A (cx. getchgbasis (q));
251  if (!product_is_identity (G, A) ||
252  !product_is_identity (A, G))
253  {
254  sout << "Failed at level " << q << ".\n";
255  throw "Wrong change of basis detected.";
256  }
257  }
258  sout << "Completed successfully in " << verifTime << ".\n";
259  }
260 
261  // compute the g.v.f. together with the projection and the inclusion
262  sout << "Composing an algebraic topological model from the SNF...\n";
263  timeused composingTime;
264  composingTime = 0;
265 
266  // prepare the lists of chain complex generators
267  // which are also homology generators
268 // multitable <hashedset<int_t> > homGener;
269 
270  // prepare the matrices for psi
271  multitable <mmatrix<integer> > psi;
272 
273  // scan through the entire chain complex in the SNF
274  const mmatrix<integer> zeroMatrix;
275  for (int q = 0; q <= dim; ++ q)
276  {
277  // prepare a number for subsequent generator representants
278  int_t gen_number = 0;
279 
280  // get the matrices computed for the Smith Normal Form:
281  // the boundary at level q
282  const mmatrix<integer> &Dq = cx. getboundary (q);
283  // the boundary at level q + 1
284  const mmatrix<integer> &Dq1 = (q < dim) ?
285  cx. getboundary (q + 1) : zeroMatrix;
286  // the change of basis from the new one to the original one
287  const mmatrix<integer> &Gq = cx. gethomgen (q);
288  // the change of basis from the original one to the new one
289  const mmatrix<integer> &Aq = cx. getchgbasis (q);
290 
291  // set the size of the matrix psi in dimension q - 1
292  if (q)
293  {
294  psi [q - 1]. define (cells [q]. size (),
295  cells [q - 1]. size ());
296  }
297 
298  // process the bases of the chain complex in the SNF
299  int ncells = cells [q]. size ();
300  for (int i = 0; i < ncells; ++ i)
301  {
302  // get the column of the matrix Dq
303  const chain<integer> &column = Dq. getcol (i);
304 
305  // if the column in the SNF is nonzero
306  if (!column. empty ())
307  {
308  integer e (column. coef (0));
309  if (e. delta () != 1)
310  {
311  throw "Non-invertible coefficient "
312  "encountered in the SNF.";
313  }
314  int b = column. num (0);
315  if (!q)
316  throw "Negative psi index.";
317  psi [q - 1]. add (i, b, e /* one? */);
318  }
319 
320  // if the column in the SNF is zero
321  else if ((q == dim) || (Dq1. getrow (i). empty ()))
322  {
323  // add the number of this cell
324  // to the list of homology generators
325  // homGener [q]. add (i);
326 
327  // determine the real homology generator
328  const chain<integer> &genChain =
329  Gq. getcol (i);
330 
331  // define a representant of this generator
332  const CellT &repr = cells [q] [gen_number];
333  ++ gen_number;
334  H. push_back (repr);
335 
336  // compute the inclusion map on it
337  int_t genSize = genChain. size ();
338  for (int_t j = 0; j < genSize; ++ j)
339  {
340  int_t n = genChain. num (j);
341  integer e = genChain. coef (j);
342  const CellT &genCell = cells [q] [n];
343  incl. add (repr, genCell,
344  CoefT (integer2int (e)));
345  }
346 
347  // add this term to the projection
348  const chain<integer> &piRow =
349  Aq. getrow (i);
350  int_t piRowSize = piRow. size ();
351  for (int_t j = 0; j < piRowSize; ++ j)
352  {
353  int_t num = piRow. num (j);
354  integer e = piRow. coef (j);
355  const CellT &cell = cells [q] [num];
356  pi. add (cell, repr,
357  CoefT (integer2int (e)));
358  }
359  }
360  }
361  }
362 
363  // compute the matrices for phi_q and compose them into one map:
364  // \phi_{q - 1} := A^{-1}_q \circ \psi_{q - 1} \circ A_{q - 1}
365  sout << "Transferring the computed maps to the original basis...\n";
366  for (int q = 1; q <= dim; ++ q)
367  {
368  // consider the three matrices to be multiplied
369  const mmatrix<integer> &M_A = cx. getchgbasis (q - 1);
370  const mmatrix<integer> &M_psi = psi [q - 1];
371  const mmatrix<integer> &M_A1 = cx. gethomgen (q);
372 
373  // determine the numbers of columns in the matrices
374  int_t sizeA = M_A. getncols ();
375  int_t sizePsi = M_psi. getncols ();
376  int_t sizeA1 = M_A1. getncols ();
377 
378  // for all the columns in the first matrix on the right...
379  for (int_t i = 0; i < sizeA; ++ i)
380  {
381  // take the column
382  const chain<integer> &column = M_A. getcol (i);
383 
384  // compute its image by psi
385  chain<integer> psiC;
386  int_t sizeC = column. size ();
387  for (int_t j = 0; j < sizeC; ++ j)
388  {
389  int_t n = column. num (j);
390  if (n >= sizePsi)
391  continue;
392  const integer &e = column. coef (j);
393  psiC. add (M_psi. getcol (n), e /* one? */);
394  }
395 
396  // compute the image of this image by A1
397  chain<integer> phiColumn;
398  int_t sizePsiC = psiC. size ();
399  for (int j = 0; j < sizePsiC; ++ j)
400  {
401  int_t n = psiC. num (j);
402  if (n >= sizeA1)
403  continue;
404  const integer &e = psiC. coef (j);
405  phiColumn. add (M_A1. getcol (n), e /* one? */);
406  }
407 
408  // decode the resulting chain and put it in phi
409  int_t sizePhiColumn = phiColumn. size ();
410  for (int j = 0; j < sizePhiColumn; ++ j)
411  {
412  int_t n = phiColumn. num (j);
413  integer e = phiColumn. coef (j);
414  phi. add (cells [q - 1] [i], cells [q] [n],
415  CoefT (integer2int (e)));
416  }
417  }
418  }
419 
420  // show timing information
421  sout << "AT model composed from the SNF in " << composingTime <<
422  ".\n";
423 
424  // show information on the total computation time of this routine
425  sout << "AT model computed in " << compTime << ".\n";
426 
427  return;
428 } /* algTopModel3 */
429 
430 
431 #endif // _CHAINCON_ATMODEL3R_H_
432 
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: atmodel3r.h:60
A linear map for coefficients in an arbitrary commutative ring.
A friend of the &#39;integer&#39; class (from the CHomP package) that converts &#39;integer&#39; objects to numbers o...
Definition: atmodel3r.h:97
void algTopModel3(const CellArray1 &K, CellArray2 &H, tLinMap< CellT, CellT, CoefT > &pi, tLinMap< CellT, CellT, CoefT > &incl, tLinMap< CellT, CellT, CoefT > &phi, const CellRestrT &restr)
Computes an algebraic topological model for the given filtered finite cell complex "K"...
Definition: atmodel3r.h:125
A linear map.
Definition: linmap.h:55
int integer2int(const chomp::homology::integer &e)
Translation of CHomP&#39;s &#39;integer&#39; to an &#39;int&#39; number.
Definition: atmodel3r.h:111
integerFriend(const chomp::homology::integer &e)
Constructor of the object from an &#39;integer&#39; object.
Definition: atmodel3r.h:101
A chain with coefficients in an arbitrary commutative ring.