homology.h

Go to the documentation of this file.
00001 
00002 
00003 
00038 
00039 // Copyright (C) 1997-2010 by Pawel Pilarczyk.
00040 //
00041 // This file is part of the Homology Library.  This library is free software;
00042 // you can redistribute it and/or modify it under the terms of the GNU
00043 // General Public License as published by the Free Software Foundation;
00044 // either version 2 of the License, or (at your option) any later version.
00045 //
00046 // This library is distributed in the hope that it will be useful,
00047 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00048 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00049 // GNU General Public License for more details.
00050 //
00051 // You should have received a copy of the GNU General Public License along
00052 // with this software; see the file "license.txt".  If not, write to the
00053 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00054 // MA 02111-1307, USA.
00055 
00056 // Started on August 14, 2003. Last revision: October 22, 2008.
00057 
00058 
00059 #ifndef _CHOMP_HOMOLOGY_HOMOLOGY_H_
00060 #define _CHOMP_HOMOLOGY_HOMOLOGY_H_
00061 
00062 #include "chomp/system/config.h"
00063 #include "chomp/system/textfile.h"
00064 #include "chomp/system/timeused.h"
00065 #include "chomp/system/arg.h"
00066 #include "chomp/struct/words.h"
00067 #include "chomp/struct/localvar.h"
00068 #include "chomp/homology/homtools.h"
00069 #include "chomp/cubes/bincube.h"
00070 #include "chomp/cubes/twolayer.h"
00071 
00072 namespace chomp {
00073 
00077 namespace homology {
00078 
00079 
00081 typedef chaincomplex<integer> ChainComplex;
00082 
00084 typedef chainmap<integer> ChainMap;
00085 
00087 typedef chain<integer> Chain;
00088 
00090 typedef hashedset<simplex> SetOfSimplices;
00091 
00093 typedef gcomplex<simplex,integer> SimplicialComplex;
00094 
00095 
00096 // --------------------------------------------------
00097 // ------------ DECODE AND SHOW HOMOLOGY ------------
00098 // --------------------------------------------------
00099 // This is a set of procedures which help interprete
00100 // the various form of homology encoding.
00101 
00104 template <class euclidom>
00105 int BettiNumber (const chain<euclidom> &c)
00106 {
00107         int betti = 0;
00108         for (int i = 0; i < c. size (); ++ i)
00109         {
00110                 if (c. coef (i). delta () == 1)
00111                         ++ betti;
00112         }
00113         return betti;
00114 } /* BettiNumber */
00115 
00120 template <class euclidom>
00121 int TorsionCoefficient (const chain<euclidom> &c, int start = 0)
00122 {
00123         if (start < 0)
00124                 return -1;
00125         while (start < c. size ())
00126         {
00127                 if (c. coef (start). delta () != 1)
00128                         return start;
00129                 else
00130                         ++ start;
00131         }
00132         return -1;
00133 } /* TorsionCoefficient */
00134 
00137 template <class euclidom>
00138 inline void ShowHomology (const chain<euclidom> &c)
00139 {
00140         int countfree = 0;
00141         bool writeplus = false;
00142 
00143         // write the homology module exactly in the order it appears in 'c'
00144         for (int i = 0; i < c. size (); ++ i)
00145         {
00146                 // if the coefficient is invertible, it will be shown later
00147                 if (c. coef (i). delta () == 1)
00148                         ++ countfree;
00149                 // otherwise show the corresponding torsion part now
00150                 else
00151                 {
00152                         sout << (writeplus ? " + " : "") <<
00153                                 euclidom::ringsymbol () << "_" <<
00154                                 c. coef (i);
00155                         writeplus = true;
00156                 }
00157 
00158                 // if there were some free ingredients show them if necessary
00159                 if (countfree && ((i == c. size () - 1) ||
00160                         (c. coef (i + 1). delta () != 1)))
00161                 {
00162                         sout << (writeplus ? " + " : "") <<
00163                                 euclidom::ringsymbol ();
00164                         if (countfree > 1)
00165                                 sout << "^" << countfree;
00166                         countfree = 0;
00167                         writeplus = true;
00168                 }
00169         }
00170 
00171         // if there was nothing to show, then just show zero
00172         if (!c. size ())
00173                 sout << "0";
00174 
00175         return;
00176 } /* ShowHomology */
00177 
00180 template <class euclidom>
00181 void ShowHomology (const chain<euclidom> *hom, int maxlevel)
00182 {
00183         if (!hom)
00184                 return;
00185 
00186         for (int q = 0; q <= maxlevel; ++ q)
00187         {
00188                 sout << "H_" << q << " = ";
00189                 ShowHomology (hom [q]);
00190                 sout << '\n';
00191         }
00192         return;
00193 } /* ShowHomology */
00194 
00197 template <class euclidom>
00198 inline void ShowHomology (const chainmap<euclidom> &hmap)
00199 {
00200         hmap. show (sout, "\tf", "x", "y");
00201         return;
00202 } /* ShowHomology */
00203 
00208 template <class euclidom>
00209 inline void ShowGenerator (const chain<euclidom> &c)
00210 {
00211         c. show (sout, "c");
00212         return;
00213 } /* ShowGenerator */
00214 
00218 template <class euclidom>
00219 void ShowGenerators (const chain<euclidom> *c, int count)
00220 {
00221         for (int i = 0; i < count; ++ i)
00222         {
00223                 sout << 'g' << (i + 1) << " = ";
00224                 ShowGenerator (c [i]);
00225                 sout << '\n';
00226         }
00227         return;
00228 } /* ShowGenerators */
00229 
00233 template <class euclidom>
00234 void ShowGenerators (chain<euclidom> const * const * const gen,
00235         const chain<euclidom> *hom, int maxlevel)
00236 {
00237         for (int q = 0; q <= maxlevel; ++ q)
00238         {
00239                 if (!hom [q]. size ())
00240                         continue;
00241                 sout << "[H_" << q << "]\n";
00242                 ShowGenerators (gen [q], hom [q]. size ());
00243                 sout << '\n';
00244         }
00245         return;
00246 } /* ShowGenerators */
00247 
00251 template <class euclidom>
00252 void ShowGenerators (const chaincomplex<euclidom> &c,
00253         const chain<euclidom> *hom, int maxlevel)
00254 {
00255         for (int q = 0; q <= maxlevel; ++ q)
00256         {
00257                 if (!hom [q]. size ())
00258                         continue;
00259                 sout << "[H_" << q << "]\n";
00260                 for (int i = 0; i < hom [q]. size (); ++ i)
00261                 {
00262                         ShowGenerator (c. gethomgen (q, hom [q]. num (i)));
00263                         sout << '\n';
00264                 }
00265                 sout << '\n';
00266         }
00267         return;
00268 } /* ShowGenerators */
00269 
00272 template <class cell,class euclidom>
00273 void ShowGenerator (const chain<euclidom> &c, const hashedset<cell> &s)
00274 {
00275         if (!c. size ())
00276                 sout << '0';
00277         for (int i = 0; i < c. size (); ++ i)
00278         {
00279                 euclidom e = c. coef (i);
00280                 if (e == 1)
00281                         sout << (i ? " + " : "") << s [c. num (i)];
00282                 else if (-e == 1)
00283                         sout << (i ? " - " : "-") << s [c. num (i)];
00284                 else
00285                 {
00286                         sout << (i ? " + " : "") << e << " * " <<
00287                                 s [c. num (i)];
00288                 }
00289         }
00290         return;
00291 } /* ShowGenerator */
00292 
00296 template <class cell,class euclidom>
00297 void ShowGenerators (const chain<euclidom> *c, int count,
00298         const hashedset<cell> &s)
00299 {
00300         for (int i = 0; i < count; ++ i)
00301         {
00302                 sout << 'g' << (i + 1) << " = ";
00303                 ShowGenerator (c [i], s);
00304                 sout << '\n';
00305         }
00306         return;
00307 } /* ShowGenerators */
00308 
00311 template <class euclidom,class cell>
00312 void ShowGenerators (chain<euclidom> * const *gen,
00313         const chain<euclidom> *hom,
00314         int maxlevel, const gcomplex<cell,euclidom> &gcompl)
00315 {
00316         for (int q = 0; q <= maxlevel; ++ q)
00317         {
00318                 if (!hom [q]. size ())
00319                         continue;
00320                 sout << "[H_" << q << "]\n";
00321                 ShowGenerators (gen [q], hom [q]. size (), gcompl [q]);
00322                 sout << '\n';
00323         }
00324         return;
00325 } /* ShowGenerators */
00326 
00327 
00328 // --------------------------------------------------
00329 // ---------------- HOMOLOGY OF SETS ----------------
00330 // --------------------------------------------------
00331 // This is a set of procedures for the homology computation
00332 // of various sets: chain complexes, geometric complexes
00333 // (including cubical and simplicial complexes) and sets of cubes.
00334 
00339 template <class euclidom>
00340 chain<euclidom> **ExtractGenerators (const chaincomplex<euclidom> &cx,
00341         chain<euclidom> *hom, int maxlevel)
00342 // For instance: Chain **ExtractGenerators (const ChainComplex cx,
00343 //      Chain *hom, int maxlevel).
00344 {
00345         // if the maximal level is negative, then there is nothing to do
00346         if (maxlevel < 0)
00347                 return 0;
00348 
00349         // create a table of tables of chains
00350         chain<euclidom> **gen = new chain<euclidom> * [maxlevel + 1];
00351 
00352         // extract generators for each homology level separately
00353         for (int q = 0; q <= maxlevel; ++ q)
00354         {
00355                 // create a table of chains to hold the generators
00356                 gen [q] = (hom [q]. size ()) ?
00357                         new chain<euclidom> [hom [q]. size ()] : 0;
00358 
00359                 // copy the corresponding chain from internal data of 'cx'
00360                 for (int i = 0; i < hom [q]. size (); ++ i)
00361                 {
00362                         gen [q] [i] =
00363                                 cx. gethomgen (q, hom [q]. num (i));
00364                 }
00365         }
00366 
00367         return gen;
00368 } /* ExtractGenerators */
00369 
00379 template <class euclidom>
00380 int Homology (chaincomplex<euclidom> &cx, const char *Xname,
00381         chain<euclidom> *&hom)
00382 // For instance: int Homology (ChainComplex &cx, const char *Xname,
00383 //      Chain *&hom).
00384 {
00385         // initialize the empty table
00386         hom = 0;
00387 
00388         // determine the dimension of the chain complex
00389         int Xdim = cx. dim ();
00390         if (Xdim < 0)
00391                 return -1;
00392 
00393         // compute the homology of the chain complex of X
00394         sout << "Computing the homology of " << Xname << " over " <<
00395                 euclidom::ringname () << "...\n";
00396         cx. simple_form ((int *) 0, false);
00397         cx. simple_homology (hom);
00398 
00399         // determine the highest non-trivial homology level
00400         int maxlevel = Xdim;
00401         while ((maxlevel >= 0) && (hom [maxlevel]. size () <= 0))
00402                 -- maxlevel;
00403 
00404         // if the homology is trivial, delete the allocated table (if any)
00405         if (hom && (maxlevel < 0))
00406         {
00407                 delete [] hom;
00408                 hom = 0;
00409         }
00410 
00411         return maxlevel;
00412 } /* Homology */
00413 
00425 template <class cell, class euclidom>
00426 int Homology (gcomplex<cell,euclidom> &Xcompl, const char *Xname,
00427         chain<euclidom> *&hom, chain<euclidom> ***gen = 0)
00428 // For instance: Homology (CubicalComplex &Xcompl, const char *Xname,
00429 //      Chain *&hom, Chain ***gen = 0).
00430 {
00431         // initialize the empty table
00432         hom = 0;
00433 
00434         // determine the dimension of the cubical complex
00435         int Xdim = Xcompl. dim ();
00436         if (Xdim < 0)
00437                 return -1;
00438 
00439         // create a chain complex from the cubical complex X without adding
00440         // boundaries, as this might be a relative complex with A removed
00441         chaincomplex<euclidom> cx (Xdim, !!gen);
00442         sout << "Creating the chain complex of " << Xname << "... ";
00443         createchaincomplex (cx, Xcompl);
00444         sout << "Done.\n";
00445 
00446         // forget the geometric cubical complex to release memory
00447         if (!gen)
00448         {
00449                 gcomplex<cell,euclidom> empty;
00450                 Xcompl = empty;
00451         }
00452 
00453         // compute the homology of this chain complex
00454         int maxlevel = Homology (cx, Xname, hom);
00455 
00456         // extract the generators of homology ('cx' will be lost on 'return')
00457         if (gen)
00458                 *gen = ExtractGenerators (cx, hom, maxlevel);
00459 
00460         return maxlevel;
00461 } /* Homology */
00462 
00469 template <class euclidom, class cubetype>
00470 int Homology (hashedset<cubetype> &Xcubes, const char *Xname,
00471         chain<euclidom> *&hom, chain<euclidom> ***gen = 0,
00472         gcomplex<typename cubetype::CellType,euclidom> **gcompl = 0)
00473 // For instance: Homology (SetOfCubes &Xcubes, const char *Xname,
00474 //      Chain *&hom, Chain ***gen = 0, CubicalComplex **gcompl = 0).
00475 {
00476         // define the type of a set of cubes
00477         typedef hashedset<cubetype> cubsettype;
00478 
00479         // define the type of a cubical cell
00480         typedef typename cubetype::CellType celltype;
00481 
00482         // initialize the empty table
00483         hom = 0;
00484 
00485         // if the set X is empty, the answer is obvious
00486         if (Xcubes. empty ())
00487                 return -1;
00488 
00489         // determine the dimension of X (note: X is nonempty!)
00490         int Xspacedim = Xcubes [0]. dim ();
00491 
00492         // allocate a suitable bit field set for the reduction and show msg
00493         knownbits [Xspacedim];
00494 
00495         // reduce the cubes in X
00496         cubsettype emptycubes;
00497         reducepair (Xcubes, emptycubes, emptycubes, Xname, 0);
00498 
00499         // transform the set of cubes X into a set of cells and forget Xcubes
00500         gcomplex<celltype,euclidom> *Xcompl =
00501                 new gcomplex<celltype,euclidom>;
00502         cubes2cells (Xcubes, *Xcompl, Xname);
00503         Xcubes = emptycubes;
00504 
00505         // collapse the set and add boundaries of cells
00506         collapse (*Xcompl, Xname);
00507 
00508         // if the complex is empty, the result is trivial
00509         if (Xcompl -> empty ())
00510         {
00511                 delete Xcompl;
00512                 return -1;
00513         }
00514 
00515         // make a correction to the dimension of X
00516         int Xdim = Xcompl -> dim ();
00517         if (Xdim != Xspacedim)
00518         {
00519                 sout << "Note: The dimension of " << Xname <<
00520                         " decreased from " << Xspacedim <<
00521                         " to " << Xdim << ".\n";
00522         }
00523 
00524         // compute the homology of the cubical complex
00525         int maxlevel = Homology (*Xcompl, Xname, hom, gen);
00526 
00527         // deallocate the cubical complex if necessary
00528         if (!gcompl)
00529                 delete Xcompl;
00530         else
00531                 *gcompl = Xcompl;
00532 
00533         return maxlevel;
00534 } /* Homology */
00535 
00544 template <class cell, class euclidom>
00545 int Homology (gcomplex<cell,euclidom> &Xcompl, const char *Xname,
00546         gcomplex<cell,euclidom> &Acompl, const char *Aname,
00547         chain<euclidom> *&hom, chain<euclidom> ***gen = 0)
00548 // For instance: Homology (CubicalComplex &Xcompl, const char *Xname,
00549 //      CubicalComplex &Acompl, const char *Aname, Chain *&hom,
00550 //      Chain ***gen = 0).
00551 {
00552         // initialize the empty table
00553         hom = 0;
00554 
00555         // determine the dimension of the first cubical complex
00556         int Xdim = Xcompl. dim ();
00557         if (Xdim < 0)
00558                 return -1;
00559 
00560         // prepare the right name for the pair (to be used later)
00561         word pairname;
00562         if (!Acompl. empty ())
00563                 pairname << '(' << Xname << "," << Aname << ')';
00564         else
00565                 pairname << Xname;
00566 
00567         // collapse the pair of sets into a relative cubical complex
00568         // and add boundaries of cells where necessary
00569         collapse (Xcompl, Acompl, Xname, Aname);
00570 
00571         // forget the remains of the other cubical complex
00572         gcomplex<cell,euclidom> emptycompl;
00573         Acompl = emptycompl;
00574 
00575         // make a correction to the dimension of X
00576         if (Xdim != Xcompl. dim ())
00577         {
00578                 sout << "Note: The dimension of " << Xname <<
00579                         " decreased from " << Xdim << " to " <<
00580                         Xcompl. dim () << ".\n";
00581         }
00582 
00583         // compute the homology of the relative cubical complex
00584         int maxlevel = Homology (Xcompl, pairname, hom, gen);
00585 
00586         // release memory used by the name of the pair and exit
00587         return maxlevel;
00588 } /* Homology */
00589 
00599 template <class euclidom, class cubetype>
00600 int Homology (hashedset<cubetype> &Xcubes, const char *Xname,
00601         hashedset<cubetype> &Acubes, const char *Aname,
00602         chain<euclidom> *&hom, chain<euclidom> ***gen = 0,
00603         gcomplex<typename cubetype::CellType,euclidom> **gcompl = 0)
00604 // For instance: int Homology (SetOfCubes &X, const char *Xname,
00605 //      SetOfCubes &A, const char *Aname, Chain *&hom,
00606 //      Chain ***gen = 0, CubicalComplex **gcompl = 0).
00607 {
00608         // define the type of a set of cubes
00609         typedef hashedset<cubetype> cubsettype;
00610 
00611         // define the type of a cubical cell
00612         typedef typename cubetype::CellType celltype;
00613 
00614         // initialize the empty table
00615         hom = 0;
00616 
00617         // if the set A is empty, call the other procedure
00618         if (Acubes. empty ())
00619                 return Homology (Xcubes, Xname, hom, gen, gcompl);
00620 
00621         // remove from X cubes which are in A
00622         removeAfromX (Xcubes, Acubes, Xname, Aname);
00623 
00624         // if the set X is empty, the answer is obvious
00625         if (Xcubes. empty ())
00626                 return -1;
00627 
00628         // leave in A only the neighbors of X\\A
00629         restrictAtoneighbors (Xcubes, Acubes, Xname, Aname);
00630 
00631         // determine the dimension of X (note: X is nonempty!)
00632         int Xspacedim = Xcubes [0]. dim ();
00633 
00634         // allocate a suitable bit field set for the reduction and show msg
00635         knownbits [Xspacedim];
00636 
00637         // expand A within X
00638         if (!gcompl)
00639                 expandAinX (Xcubes, Acubes, Xname, Aname);
00640 
00641         // if everything was moved to A, then the result is trivial
00642         if (Xcubes. empty ())
00643                 return -1;
00644 
00645         // restrict A to neighbors
00646         restrictAtoneighbors (Xcubes, Acubes, Xname, Aname);
00647 
00648         // reduce the pair (X,A)
00649         cubsettype emptycubes;
00650         reducepair (Xcubes, Acubes, emptycubes, Xname, Aname);
00651 
00652         // if nothing remains in X, then the result is trivial
00653         if (Xcubes. empty ())
00654                 return -1;
00655 
00656         // prepare the right name for the difference of the two sets
00657         word diffname;
00658         diffname << Xname << '\\' << Aname;
00659 
00660         // transform the set of cubes X into a set of cells and forget Xcubes
00661         gcomplex<celltype,euclidom> *Xcompl =
00662                 new gcomplex<celltype,euclidom>;
00663         cubes2cells (Xcubes, *Xcompl, diffname);
00664         Xcubes = emptycubes;
00665 
00666         // transform the set of cubes A into a set of cubical cells
00667         gcomplex<celltype,euclidom> Acompl;
00668         cubes2cells (Acubes, Acompl, Aname);
00669         Acubes = emptycubes;
00670 
00671         // continue the homology computations
00672         int maxlevel = Homology (*Xcompl, Xname, Acompl, Aname, hom, gen);
00673 
00674         // deallocate the cubical complex if necessary
00675         if (!gcompl)
00676                 delete Xcompl;
00677         else
00678                 *gcompl = Xcompl;
00679 
00680         return maxlevel;
00681 } /* Homology */
00682 
00683 
00684 // --------------------------------------------------
00685 // ---------------- HOMOLOGY OF MAPS ----------------
00686 // --------------------------------------------------
00687 // This is a set of procedures for the homology computation
00688 // of chain maps and combinatorial cubical multivalued maps.
00689 
00706 template <class euclidom>
00707 chainmap<euclidom> *HomologyMap (const chainmap<euclidom> &cmap,
00708         const chain<euclidom> *hom_cx,
00709         const chain<euclidom> *hom_cy, int maxlevel)
00710 // For instance: ChainMap *HomologyMap (const ChainMap &cmap,
00711 //      const Chain *hom_cx, const Chain *hom_cy, int maxlevel).
00712 {
00713         // if the maximal level is wrong, return 0
00714         if (maxlevel < 0)
00715                 return 0;
00716 
00717         // allocate chain complexes of appropriate dimension and a chain map
00718         chaincomplex<euclidom> hx (maxlevel);
00719         chaincomplex<euclidom> hy (maxlevel);
00720         chainmap<euclidom> *hmap = new chainmap<euclidom> (hx, hy);
00721 
00722         // create the chain complexes reflecting the homology module(s)
00723         hx. take_homology (hom_cx);
00724         hy. take_homology (hom_cy);
00725 
00726         // create the chain map accordingly
00727         hmap -> take_homology (cmap, hom_cx, hom_cy);
00728         return hmap;
00729 } /* HomologyMap */
00730 
00734 template <class euclidom>
00735 chainmap<euclidom> *HomologyMap (const chainmap<euclidom> &cmap,
00736         const chain<euclidom> *hom_cx, int maxlevel)
00737 // For instance: ChainMap *HomologyMap (const ChainMap &cmap,
00738 //      const Chain *hom_cx, int maxlevel).
00739 {
00740         // if the maximal level is wrong, return 0
00741         if (maxlevel < 0)
00742                 return 0;
00743 
00744         // allocate chain complexes of appropriate dimension and a chain map
00745         chaincomplex<euclidom> hx (maxlevel);
00746         chainmap<euclidom> *hmap = new chainmap<euclidom> (hx, hx);
00747 
00748         // create the chain complexes reflecting the homology module(s)
00749         hx. take_homology (hom_cx);
00750 
00751         // create the chain map accordingly
00752         hmap -> take_homology (cmap, hom_cx, hom_cx);
00753         return hmap;
00754 } /* HomologyMap */
00755 
00768 template <class euclidom, class cubetype>
00769 int Homology (mvmap<cubetype,cubetype> &Fcubmap, const char *Fname,
00770         hashedset<cubetype> &Xcubes, const char *Xname,
00771         hashedset<cubetype> &Acubes, const char *Aname,
00772         hashedset<cubetype> &Ycubes, const char *Yname,
00773         hashedset<cubetype> &Bcubes, const char *Bname,
00774         chain<euclidom> *&hom_cx, int &maxlevel_cx,
00775         chain<euclidom> *&hom_cy, int &maxlevel_cy,
00776         chainmap<euclidom> *&hom_f,
00777         bool inclusion = false, int careful = 0x01,
00778         chain<euclidom> ***gfgen = 0,
00779         gcomplex<typename cubetype::CellType,euclidom> **gfcompl = 0,
00780         chain<euclidom> ***gygen = 0,
00781         gcomplex<typename cubetype::CellType,euclidom> **gycompl = 0)
00782 {
00783         // define the type of a set of cubes
00784         typedef hashedset<cubetype> cubsettype;
00785 
00786         // define the type of a cubical cell
00787         typedef typename cubetype::CellType celltype;
00788 
00789         // define the type of a combinatorial cubical multivalued map
00790         typedef mvmap<cubetype,cubetype> cubmaptype;
00791 
00792         // transform the 'careful' bits into separate variables
00793         bool verify = careful & 0x01;
00794         bool checkacyclic = careful & 0x02;
00795 
00796         // prepare the right names for X\A and Y\B
00797         word XAname, YBname;
00798         if (!Acubes. empty ())
00799                 XAname << Xname << '\\' << Aname;
00800         else
00801                 XAname << Xname;
00802         if (!Bcubes. empty ())
00803                 YBname << Yname << '\\' << Bname;
00804         else
00805                 YBname << Yname;
00806 
00807         // ----- prepare the sets of cubes -----
00808 
00809         // if the pointers to both sets are the same, then this is an error
00810         if (&Xcubes == &Ycubes)
00811                 throw "You must clone the sets passed to Homology.";
00812 
00813         // remove from X cubes which are in A
00814         removeAfromX (Xcubes, Acubes, Xname, Aname);
00815 
00816         // leave in A only the neighbors of X\\A
00817         restrictAtoneighbors (Xcubes, Acubes, Xname, Aname);
00818 
00819         // remove from Y cubes which are in B
00820         removeAfromX (Ycubes, Bcubes, Yname, Bname);
00821 
00822         // if one of the main sets is empty, the answer is trivial
00823         if (Xcubes. empty () || Ycubes. empty ())
00824                 return -1;
00825 
00826         // remember the original size of the set A and of the set X
00827         int_t origAsize = Acubes. size ();
00828         int_t origXsize = Xcubes. size ();
00829 
00830         // determine the dimension of X and Y (both sets are non-empty)
00831         int Xspacedim = Xcubes [0]. dim ();
00832         int Yspacedim = Ycubes [0]. dim ();
00833 
00834         // check if F (X\A) \subset Y
00835         if (verify)
00836                 checkimagecontained (Fcubmap, Xcubes, Ycubes, Bcubes,
00837                         XAname, Yname);
00838 
00839         // check if F (A) \subset B
00840         if (verify && !Acubes. empty ())
00841                 checkimagecontained (Fcubmap, Acubes, Bcubes, Aname, Bname);
00842 
00843         // check if F (A) is disjoint from Y
00844         if (verify && !Acubes. empty ())
00845                 checkimagedisjoint (Fcubmap, Acubes, Ycubes, Aname, YBname);
00846 
00847         // verify if X\A \subset Y and A \subset B if inclusion is considered
00848         if (verify && inclusion)
00849                 checkinclusion (Xcubes, Ycubes, Bcubes, XAname, Yname);
00850         if (verify && inclusion)
00851                 checkinclusion (Acubes, Bcubes, Aname, Bname);
00852 
00853         // ----- reduce the sets of cubes -----
00854 
00855         // allocate a suitable bit field set for the reduction and show msg
00856         knownbits [Xspacedim];
00857         knownbits [Yspacedim];
00858 
00859         // reduce the pair of sets of cubes (X,A) without acyclicity check
00860         if (!checkacyclic)
00861         {
00862                 // reduce the pair (X,A)
00863                 cubsettype empty;
00864                 reducepair (Xcubes, Acubes, empty, Xname, Aname);
00865 
00866                 // if nothing remains in X, then the result is trivial
00867                 if (Xcubes. empty ())
00868                         return -1;
00869         }
00870 
00871         // expand A towards X and modify (Y,B) accordingly
00872         if (!Acubes. empty () && !gfgen && !gygen)
00873         {
00874                 expandAinX (Xcubes, Acubes, Ycubes, Bcubes, Fcubmap,
00875                         Xname, Aname, Bname, inclusion, checkacyclic);
00876         }
00877 
00878         // reduce the pair (X,A) or the set X with acyclicity check
00879         if (checkacyclic && !Acubes. empty ())
00880         {
00881                 // leave in A only the neighbors of X\\A
00882                 restrictAtoneighbors (Xcubes, Acubes, Xname, Aname);
00883 
00884                 // reduce the pair (X,A) with acyclicity check
00885                 cubsettype emptycubes;
00886                 reducepair (Xcubes, Acubes, Fcubmap, emptycubes,
00887                         Xname, Aname);
00888 
00889                 // if nothing remains in X, then the result is trivial
00890                 if (Xcubes. empty ())
00891                         return -1;
00892         }
00893 
00894         // reduce the pair (X,A) even further
00895         if (!checkacyclic && !Acubes. empty ())
00896         {
00897                 // leave in A only the neighbors of X\\A
00898                 restrictAtoneighbors (Xcubes, Acubes, Xname, Aname);
00899 
00900                 // continue the reduction of the pair (X,A)
00901                 cubsettype empty;
00902                 reducepair (Xcubes, Acubes, empty, Xname, Aname);
00903         }
00904 
00905         // indicate that the acyclicity of the map should be verified
00906         if (!verify)
00907         {
00908                 if (!checkacyclic && ((origAsize != Acubes. size ()) ||
00909                         (origXsize != Xcubes. size ())))
00910                 {
00911                         sout << "*** Important note: " << Xname << " or " <<
00912                                 Aname << " changed. You must make sure\n"
00913                                 "*** that the restriction of " << Fname <<
00914                                 " to the new sets is acyclic.\n";
00915                 }
00916                 else
00917                 {
00918                         sout << "*** Note: The program assumes "
00919                                 "that the input map is acyclic.\n";
00920                 }
00921         }
00922 
00923         // create the set of cubes to keep in Y as the image of the domain
00924         // and include the domain if the inclusion is considered
00925         cubsettype Ykeepcubes;
00926         sout << "Computing the image of the map... ";
00927         for (int_t i = 0; i < Xcubes. size (); ++ i)
00928                 Ykeepcubes. add (Fcubmap (Xcubes [i]));
00929         for (int_t i = 0; i < Acubes. size (); ++ i)
00930                 Ykeepcubes. add (Fcubmap (Acubes [i]));
00931         if (inclusion)
00932         {
00933                 sout << "and of the inclusion... ";
00934                 Ykeepcubes. add (Xcubes);
00935                 Ykeepcubes. add (Acubes);
00936         }
00937         sout << Ykeepcubes. size () << " cubes.\n";
00938 
00939         // reduce the pair of cubical sets (Y,B) towards the image of F
00940         if (Xspacedim == Yspacedim)
00941         {
00942                 if (!gygen)
00943                         expandAinX (Ycubes, Bcubes, Yname, Bname);
00944                 restrictAtoneighbors (Ycubes, Bcubes, Yname, Bname,
00945                         &Ykeepcubes);
00946                 reducepair (Ycubes, Bcubes, Ykeepcubes, Yname, Bname);
00947         }
00948 
00949         // forget the cubes to keep in Y as no longer of any use
00950         if (!Ykeepcubes. empty ())
00951         {
00952                 cubsettype empty;
00953                 Ykeepcubes = empty;
00954         }
00955 
00956         // ----- create the cubical complexes -----
00957 
00958         // transform the set of cubes X into a set of cells and forget Xcubes
00959         gcomplex<celltype,euclidom> Xcompl;
00960         cubes2cells (Xcubes, Xcompl, XAname, false);
00961 
00962         // transform the set of cubes A into a set of cubical cells
00963         gcomplex<celltype,euclidom> Acompl;
00964         cubes2cells (Acubes, Acompl, Aname, false);
00965 
00966         // transform the cubes in Y into cubical cells and forget the cubes
00967         gcomplex<celltype,euclidom> *Ycompl =
00968                 new gcomplex<celltype,euclidom>;
00969         cubes2cells (Ycubes, *Ycompl, YBname);
00970 
00971         // transform the cubes in B into cubical cells and forget the cubes
00972         gcomplex<celltype,euclidom> Bcompl;
00973         cubes2cells (Bcubes, Bcompl, Bname);
00974 
00975         // determine the dimension of X and Y as cubical complexes
00976         int Xdim = Xcompl. dim ();
00977         int Ydim = Ycompl -> dim ();
00978 
00979         // ----- collapse the cubical sets (X,A) -----
00980 
00981         // reduce the pair of sets (Xcompl, Acompl) while adding to them
00982         // boundaries of all the cells
00983         gcomplex<celltype,euclidom> emptycompl;
00984         collapse (Xcompl, Acompl, emptycompl, Xname, Aname,
00985                 true, true, false);
00986 
00987         // if nothing remains in X, then the result is trivial
00988         if (Xcompl. empty ())
00989                 return -1;
00990 
00991         // make a correction to the dimension of X
00992         if (Xdim != Xcompl. dim ())
00993         {
00994                 sout << "Note: The dimension of " << Xname << " decreased "
00995                         "from " << Xdim << " to " << Xcompl. dim () << ".\n";
00996 
00997                 Xdim = Xcompl. dim ();
00998         }
00999 
01000         // ----- create a reduced graph of F -----
01001 
01002         // create the map F defined on the cells in its domain
01003         mvcellmap<celltype,euclidom,cubetype> Fcellcubmap (Xcompl);
01004         sout << "Creating the map " << Fname << " on cells in " <<
01005                 Xname << "... ";
01006         int_t countimages = createimages (Fcellcubmap, Fcubmap, Fcubmap,
01007                 Xcubes, Acubes);
01008         sout << countimages << " cubes added.\n";
01009 
01010         // create the map F defined on the cells in its domain subcomplex A
01011         mvcellmap<celltype,euclidom,cubetype> FcellcubmapA (Acompl);
01012         if (!Acompl. empty ())
01013         {
01014                 sout << "Creating the map " << Fname << " on cells in " <<
01015                         Aname << "... ";
01016                 int_t count = createimages (FcellcubmapA, Fcubmap, Acubes);
01017                 sout << count << " cubes added.\n";
01018         }
01019 
01020         // get rid of the sets of cubes X and A as no longer needed,
01021         // as well as the cubical map
01022         {
01023                 cubsettype emptycubes;
01024                 Acubes = emptycubes;
01025                 Xcubes = emptycubes;
01026                 cubmaptype emptymap;
01027                 Fcubmap = emptymap;
01028         }
01029 
01030         // create the graph of F as a cubical cell complex
01031         sout << "Creating a cell map for " << Fname << "... ";
01032         mvcellmap<celltype,euclidom,celltype> Fcellmap (Xcompl);
01033         bool acyclic = createcellmap (Fcellcubmap, FcellcubmapA,
01034                 Fcellmap, verify);
01035         sout << "Done.\n";
01036         if (verify && !acyclic)
01037         {
01038                 sout << "*** SERIOUS PROBLEM: The map is not "
01039                         "acyclic. THE RESULT WILL BE WRONG.\n"
01040                         "*** You must verify the acyclicity of the "
01041                         "initial map with 'chkmvmap'\n"
01042                         "*** and, if successful, set the "
01043                         "'careful reduction' bit.\n";
01044         }
01045         if (verify && acyclic)
01046         {
01047                 sout << "Note: It has been verified successfully "
01048                         "that the map is acyclic.\n";
01049         }
01050 
01051         sout << "Creating the graph of " << Fname << "... ";
01052         gcomplex<celltype,euclidom> *Fcompl =
01053                 new gcomplex<celltype,euclidom>;
01054         creategraph (Fcellmap, *Fcompl, false);
01055         sout << Fcompl -> size () << " cells added.\n";
01056 
01057         // forget the cubical maps on the cells and the cubical complex of X
01058         mvcellmap<celltype,euclidom,cubetype> emptycellcubmap;
01059         Fcellcubmap = emptycellcubmap;
01060         FcellcubmapA = emptycellcubmap;
01061         mvcellmap<celltype,euclidom,celltype> emptycellmap (emptycompl);
01062         Fcellmap = emptycellmap;
01063         Xcompl = emptycompl;
01064 
01065         // ----- collapse the cubical sets (Y,B) -----
01066 
01067         // decrease the dimension of B to the dimension of Y
01068         decreasedimension (Bcompl, Ydim, Bname);
01069 
01070         // create a full cubical complex (with all the faces) of Y\B
01071         addboundaries (*Ycompl, Bcompl, 0, false, Yname, Bname);
01072 
01073         // forget the cubical complex of B
01074         if (!Bcompl. empty ())
01075         {
01076                 sout << "Forgetting " << Bcompl. size () << " cells from " <<
01077                         Bname << ".\n";
01078                 gcomplex<celltype,euclidom> empty;
01079                 Bcompl = empty;
01080         }
01081 
01082         // collapse the codomain of the map towards the image of F
01083         gcomplex<celltype,euclidom> Ykeepcompl;
01084         sout << "Computing the image of " << Fname << "... ";
01085         project (*Fcompl, Ykeepcompl, *Ycompl, Xspacedim, Yspacedim,
01086                 0, 0, false);
01087         if (inclusion)
01088         {
01089                 project (*Fcompl, Ykeepcompl, *Ycompl, 0, Xspacedim,
01090                         Yspacedim, 0, false);
01091         }
01092         sout << Ykeepcompl. size () << " cells.\n";
01093 
01094         sout << "Collapsing " << Yname << " to img of " << Xname << "... ";
01095         int_t countremoved = Ycompl -> collapse (emptycompl, Ykeepcompl,
01096                 0, 0, 0);
01097         sout << 2 * countremoved << " cells removed, " <<
01098                 Ycompl -> size () << " left.\n";
01099 
01100         // forget the cells to keep in Y
01101         if (!Ykeepcompl. empty ())
01102         {
01103                 gcomplex<celltype,euclidom> empty;
01104                 Ykeepcompl = empty;
01105         }
01106 
01107         // make a correction to the dimension of Y
01108         if (Ydim != Ycompl -> dim ())
01109         {
01110                 sout << "Note: The dimension of " << Yname << " decreased "
01111                         "from " << Ydim << " to " << Ycompl -> dim () <<
01112                         ".\n";
01113 
01114                 Ydim = Ycompl -> dim ();
01115         }
01116 
01117         // ----- create chain complexes from the cubical sets ------
01118 
01119         // create a chain complex from the graph of F (it is relative)
01120         chaincomplex<euclidom> cgraph (Fcompl -> dim (), !!gfgen);
01121         sout << "Creating the chain complex of the graph of " << Fname <<
01122                 "... ";
01123         createchaincomplex (cgraph, *Fcompl);
01124         sout << "Done.\n";
01125 
01126         // create the chain complex from Y (this is a relative complex)
01127         chaincomplex<euclidom> cy (Ydim, !!gygen);
01128         sout << "Creating the chain complex of " << Yname << "... ";
01129         createchaincomplex (cy, *Ycompl);
01130         sout << "Done.\n";
01131 
01132         // create the projection map from the graph of the map to Y
01133         chainmap<euclidom> cmap (cgraph, cy);
01134         sout << "Creating the chain map of the projection... ";
01135         createprojection (*Fcompl, *Ycompl, cmap, Xspacedim, Yspacedim, 0);
01136         sout << "Done.\n";
01137 
01138         // if this is an index map, create the projection map from the graph
01139         // of the map to X composed with the inclusion into Y
01140         chainmap<euclidom> imap (cgraph, cy);
01141         if (inclusion)
01142         {
01143                 sout << "Creating the chain map of the inclusion... ";
01144                 createprojection (*Fcompl, *Ycompl, imap, 0, Xspacedim,
01145                         Yspacedim);
01146                 sout << "Done.\n";
01147         }
01148 
01149         // forget the graph of F if it is not going to be used anymore
01150         if (gfcompl)
01151                 (*gfcompl) = Fcompl;
01152         else
01153                 delete Fcompl;
01154 
01155         // forget the cubical complex Y unless requested to keep it
01156         if (gycompl)
01157                 (*gycompl) = Ycompl;
01158         else
01159                 delete Ycompl;
01160 
01161         // ----- compute and show homology, save generators -----
01162 
01163         // prepare the name of the graph of F
01164         word gFname;
01165         gFname << "the graph of " << Fname;
01166 
01167         // compute the homology of the chain complex of the graph of the map
01168         maxlevel_cx = Homology (cgraph, gFname, hom_cx);
01169 
01170         // extract the computed generators of the graph if requested to
01171         if (gfgen)
01172                 *gfgen = ExtractGenerators (cgraph, hom_cx, maxlevel_cx);
01173 
01174         // compute the homology of the chain complex of Y
01175         maxlevel_cy = Homology (cy, Yname, hom_cy);
01176 
01177         // extract the computed generators of Y if requested to
01178         if (gygen)
01179                 *gygen = ExtractGenerators (cy, hom_cy, maxlevel_cy);
01180 
01181         // ----- show the map(s) -----
01182 
01183         // prepare the data structures for the homology
01184         chaincomplex<euclidom> hgraph (maxlevel_cx);
01185         chaincomplex<euclidom> hy (maxlevel_cy);
01186         chainmap<euclidom> *hmap = new chainmap<euclidom> (hgraph, hy);
01187         chainmap<euclidom> hincl (hgraph, hy);
01188 //      chainmap<euclidom> *hcomp = new chainmap<euclidom> (hgraph, hgraph);
01189         chainmap<euclidom> *hcomp = new chainmap<euclidom> (hy, hy);
01190 
01191         // show the map induced in homology by the chain map
01192         sout << "The map induced in homology is as follows:\n";
01193         hgraph. take_homology (hom_cx);
01194         hy. take_homology (hom_cy);
01195         hmap -> take_homology (cmap, hom_cx, hom_cy);
01196         hmap -> show (sout, "\tf", "x", "y");
01197 
01198         // show the map induced in homology by the inclusion map
01199         bool invertible = true;
01200         if (inclusion)
01201         {
01202                 sout << "The map induced in homology by the inclusion:\n";
01203                 hincl. take_homology (imap, hom_cx, hom_cy);
01204                 hincl. show (sout, "\ti", "x", "y");
01205 
01206                 try
01207                 {
01208                         hincl. invert ();
01209                 }
01210                 catch (...)
01211                 {
01212                         sout << "Oh, my goodness! This map is apparently "
01213                                 "not invertible.\n";
01214                         invertible = false;
01215                 }
01216 
01217                 if (invertible)
01218                 {
01219                         sout << "The inverse of the map "
01220                                 "induced by the inclusion:\n";
01221                         hincl. show (sout, "\tI", "y", "x");
01222 
01223                         // debug: verify if the map was inverted correctly
01224                         chainmap<euclidom> hincl1 (hgraph, hy);
01225                         hincl1. take_homology (imap, hom_cx, hom_cy);
01226                         chainmap<euclidom> hident (hy, hy);
01227                         hident. compose (hincl1, hincl);
01228                         sbug << "The composition of the inclusion and "
01229                                 "its inverse (should be the identity):\n";
01230                         hident. show (sbug, "\tid", "y", "y");
01231                         for (int i = 0; i <= hident. dim (); ++ i)
01232                         {
01233                                 const mmatrix<euclidom> &m = hident [i];
01234                                 if (m. getnrows () != m. getncols ())
01235                                         throw "INV: Inequal rows and cols.";
01236                                 euclidom zero, one;
01237                                 zero = 0;
01238                                 one = 1;
01239                                 for (int c = 0; c < m. getncols (); ++ c)
01240                                 {
01241                                         for (int r = 0; r < m. getnrows ();
01242                                                 ++ r)
01243                                         {
01244                                                 if ((r == c) && (m. get
01245                                                         (r, c) == one))
01246                                                 {
01247                                                         continue;
01248                                                 }
01249                                                 if (m. get (r, c) == zero)
01250                                                         continue;
01251                                                 throw "INV: Non-identity.";
01252                                         }
01253                                 }
01254                         }
01255                         // debug: end of the verification
01256 
01257                         sout << "The composition of F and the inverse "
01258                                 "of the map induced by the inclusion:\n";
01259                 //      hcomp -> compose (hincl, *hmap);
01260                         hcomp -> compose (*hmap, hincl);
01261                 //      hcomp -> show (sout, "\tF", "x", "x");
01262                         hcomp -> show (sout, "\tF", "y", "y");
01263                 }
01264         }
01265 
01266         // set the appropriate map
01267         if (inclusion && invertible)
01268         {
01269                 hom_f = hcomp;
01270                 delete hmap;
01271         }
01272         else
01273         {
01274                 hom_f = hmap;
01275                 delete hcomp;
01276         }
01277 
01278         // throw an exception if the map is not invertible
01279         if (inclusion && !invertible)
01280                 throw "Unable to invert the inclusion map.";
01281 
01282         return ((maxlevel_cx < maxlevel_cy) ? maxlevel_cx : maxlevel_cy);
01283 } /* Homology */
01284 
01286 template <class euclidom, class cubetype>
01287 int Homology (mvmap<cubetype,cubetype> &Fcubmap,
01288         hashedset<cubetype> &Xcubes, hashedset<cubetype> &Acubes,
01289         hashedset<cubetype> &Ycubes, hashedset<cubetype> &Bcubes,
01290         chain<euclidom> *&hom_cx, int &maxlevel_cx,
01291         chain<euclidom> *&hom_cy, int &maxlevel_cy,
01292         chainmap<euclidom> *&hom_f,
01293         bool inclusion = false, int careful = 0x01,
01294         chain<euclidom> ***gfgen = 0,
01295         gcomplex<typename cubetype::CellType,euclidom> **gfcompl = 0,
01296         chain<euclidom> ***gygen = 0,
01297         gcomplex<typename cubetype::CellType,euclidom> **gycompl = 0)
01298 {
01299         return Homology (Fcubmap, "F", Xcubes, "X", Acubes, "A",
01300                 Ycubes, "Y", Bcubes, "B", hom_cx, maxlevel_cx,
01301                 hom_cy, maxlevel_cy, hom_f, inclusion, careful,
01302                 gfgen, gfcompl, gygen, gycompl);
01303 } /* Homology */
01304 
01308 template <class euclidom, class cubetype>
01309 int Homology (mvmap<cubetype,cubetype> &Fcubmap, const char *Fname,
01310         hashedset<cubetype> &Xcubes, const char *Xname,
01311         hashedset<cubetype> &Acubes, const char *Aname,
01312         chain<euclidom> *&hom, int &maxlevel,
01313         chainmap<euclidom> *&hom_f, int careful = 0x01,
01314         chain<euclidom> ***gfgen = 0,
01315         gcomplex<typename cubetype::CellType,euclidom> **gfcompl = 0,
01316         chain<euclidom> ***gygen = 0,
01317         gcomplex<typename cubetype::CellType,euclidom> **gycompl = 0)
01318 {
01319         hashedset<cubetype> Ycubes = Xcubes, Bcubes = Acubes;
01320         chain<euclidom> *hom_cy = 0;
01321         int maxlevel_cy;
01322         int result = Homology (Fcubmap, Fname, Xcubes, Xname, Acubes, Aname,
01323                 Ycubes, Xname, Bcubes, Aname, hom, maxlevel,
01324                 hom_cy, maxlevel_cy, hom_f, true, careful,
01325                 gfgen, gfcompl, gygen, gycompl);
01326         delete [] hom_cy;
01327         return result;
01328 } /* Homology */
01329 
01331 template <class euclidom, class cubetype>
01332 int Homology (mvmap<cubetype,cubetype> &Fcubmap,
01333         hashedset<cubetype> &Xcubes, hashedset<cubetype> &Acubes,
01334         chain<euclidom> *&hom, int &maxlevel,
01335         chainmap<euclidom> *&hom_f, int careful = 0x01,
01336         chain<euclidom> ***gfgen = 0,
01337         gcomplex<typename cubetype::CellType,euclidom> **gfcompl = 0,
01338         chain<euclidom> ***gygen = 0,
01339         gcomplex<typename cubetype::CellType,euclidom> **gycompl = 0)
01340 {
01341         return Homology (Fcubmap, "F", Xcubes, "X", Acubes, "A", hom,
01342                 maxlevel, hom_f, careful, gfgen, gfcompl, gygen, gycompl);
01343 } /* Homology */
01344 
01345 
01346 // --------------------------------------------------
01347 // --------- TWO-LAYER HOMOLOGY COMPUTATION ---------
01348 // --------------------------------------------------
01349 
01353 template <class euclidom, class cubetype>
01354 int Homology2l (mvmap<cubetype,cubetype> &Fcubmap0, const char *Fname,
01355         hashedset<cubetype> &Xcubes0, const char *Xname,
01356         hashedset<cubetype> &Acubes0, const char *Aname,
01357         chain<euclidom> *&hom_cx, int &maxlevel,
01358         chainmap<euclidom> *&hom_f, int careful = 0x01,
01359         chain<euclidom> ***gfgen = 0,
01360         gcomplex<tCell2l<typename cubetype::CellType>,euclidom>
01361         **gfcompl = 0, chain<euclidom> ***gygen = 0,
01362         gcomplex<tCell2l<typename cubetype::CellType>,euclidom>
01363         **gycompl = 0)
01364 {
01365         // define the type of a 2-layer cube and 2-layer cell
01366         typedef tCube2l<cubetype> cube2ltype;
01367         typedef typename cube2ltype::CellType cell2ltype;
01368 
01369         // turn off locally the usage of binary decision diagrams
01370         local_var<int> TurnOffMaxBddDim (MaxBddDim, 0);
01371 
01372         // transform the 'careful' bits into separate variables
01373         bool verify = careful & 0x01;
01374         bool checkacyclic = careful & 0x02;
01375 
01376         // remove from X cubes which are in A
01377         removeAfromX (Xcubes0, Acubes0, "X", "A");
01378 
01379         // leave in A only the neighbors of X\\A
01380         restrictAtoneighbors (Xcubes0, Acubes0, "X", "A");
01381 
01382         // if the set X is empty, the answer is obvious
01383         if (Xcubes0. empty ())
01384         {
01385                 sout << "X is a subset of A. The homology of (X,A) "
01386                         "is trivial and the map is 0.";
01387                 return -1;
01388         }
01389 
01390         // ----- define the layers ------
01391 
01392         // define the two-layer structure
01393         sout << "Defining the two-layer structure... ";
01394         cube2ltype::setlayers (Xcubes0, Acubes0);
01395 
01396         // transform the cubes in X and in A to the two-layer sets
01397         hashedset<cube2ltype> Xcubes;
01398         for (int_t i = 0; i < Xcubes0. size (); ++ i)
01399                 Xcubes. add (cube2ltype (Xcubes0 [i], 1));
01400         hashedset<cube2ltype> Acubes;
01401         for (int_t i = 0; i < Acubes0. size (); ++ i)
01402                 Acubes. add (cube2ltype (Acubes0 [i], 0));
01403 
01404         // say that defining the two-layer structure is done
01405         sout << cube2ltype::layer1 (). size () << "+" <<
01406                 cube2ltype::layer0 (). size () << " cubes, " <<
01407                 cell2ltype::identify (). size () << " cells.\n";
01408 
01409         // ----- transform the map ------
01410 
01411         // determine Y and B
01412         sout << "Creating the sets Y and B... ";
01413         hashedset<cube2ltype> Ycubes (Xcubes);
01414         hashedset<cube2ltype> Bcubes (Acubes);
01415         for (int_t i = 0; i < Xcubes0. size (); ++ i)
01416         {
01417                 const hashedset<cubetype> &img = Fcubmap0 (Xcubes0 [i]);
01418                 for (int_t j = 0; j < img. size (); ++ j)
01419                 {
01420                         if (!Xcubes0. check (img [j]))
01421                                 Bcubes. add (cube2ltype (img [j], 0));
01422                 }
01423         }
01424         for (int_t i = 0; i < Acubes0. size (); ++ i)
01425         {
01426                 const hashedset<cubetype> &img = Fcubmap0 (Acubes0 [i]);
01427                 for (int_t j = 0; j < img. size (); ++ j)
01428                         Bcubes. add (cube2ltype (img [j], 0));
01429         }
01430         sout << Ycubes. size () << " cubes in Y\\B, " <<
01431                 Bcubes. size () << " in B.\n";
01432 
01433         // lift the map to the two-layer structure
01434         mvmap<cube2ltype,cube2ltype> Fcubmap;
01435         for (int_t i = 0; i < Xcubes0. size (); ++ i)
01436         {
01437         //      Fcubmap [Xcubes [i]]. size ();
01438                 const hashedset<cubetype> &img = Fcubmap0 (Xcubes0 [i]);
01439                 if (img. empty ())
01440                         throw "Empty image of a box in X.\n";
01441                 for (int_t j = 0; j < img. size (); ++ j)
01442                 {
01443                         int layer = Xcubes0. check (img [j]) ? 1 : 0;
01444                         Fcubmap [Xcubes [i]]. add
01445                                 (cube2ltype (img [j], layer));
01446                 }
01447         }
01448         for (int_t i = 0; i < Acubes0. size (); ++ i)
01449         {
01450         //      Fcubmap [Acubes [i]]. size ();
01451                 const hashedset<cubetype> &img = Fcubmap0 (Acubes0 [i]);
01452                 if (img. empty ())
01453                         throw "Empty image of a box in A.\n";
01454                 for (int_t j = 0; j < img. size (); ++ j)
01455                         Fcubmap [Acubes [i]]. add
01456                                 (cube2ltype (img [j], 0));
01457         }
01458 
01459         // forget the initial single-layer sets and the map
01460         {
01461                 hashedset<cubetype> empty;
01462                 Xcubes0 = empty;
01463                 Acubes0 = empty;
01464         }
01465         {
01466                 mvmap<cubetype,cubetype> empty;
01467                 Fcubmap0 = empty;
01468         }
01469 
01470         // remember the original size of the set A and of the set X
01471         int_t origAsize = Acubes. size ();
01472         int_t origXsize = Xcubes. size ();
01473 
01474         // determine the dimension of X and Y if possible
01475         int Xspacedim = Xcubes. empty () ? -1 : Xcubes [0]. dim ();
01476         int Yspacedim = Ycubes. empty () ? -1 : Ycubes [0]. dim ();
01477 
01478         // ----- reduce the sets of cubes -----
01479 
01480         // prepare the set of cubes to keep in X (unused in this program)
01481         hashedset<cube2ltype> Xkeepcubes;
01482 
01483         // allocate a suitable bit field set for the reduction and show msg
01484         if (Xspacedim > 0)
01485                 knownbits [Xspacedim];
01486 
01487         // reduce the pair of sets of cubes (X,A) without acyclicity check
01488         if (!Acubes. empty () && !checkacyclic)
01489         {
01490                 // reduce the pair (X,A)
01491                 reducepair (Xcubes, Acubes, Xkeepcubes, "X", "A");
01492 
01493                 // if nothing remains in X, then the result is trivial
01494                 if (Xcubes. empty ())
01495                 {
01496                         sout << "There are no cubes left "
01497                                 "in X\\A. The homology of (X,A) "
01498                                 "is trivial and the map is 0.";
01499                         return -1;
01500                 }
01501         }
01502 
01503         // remember which inclusions have been verified
01504         bool inclFABchecked = false;
01505         bool inclFXYchecked = false;
01506 
01507         // do the careful or extended reduction
01508         if (checkacyclic)
01509         {
01510                 // check if F (X\A) \subset Y
01511                 if (verify)
01512                 {
01513                         checkimagecontained (Fcubmap,
01514                                 Xcubes, Ycubes, Bcubes,
01515                                 Acubes. empty () ? "X" : "X\\A", "Y");
01516                         inclFXYchecked = true;
01517                 }
01518                 // check if F (A) \subset B and if F (A) is disjoint from Y
01519                 if (verify && !Acubes. empty ())
01520                 {
01521                         checkimagecontained (Fcubmap, Acubes, Bcubes,
01522                                 "A", "B");
01523                         checkimagedisjoint (Fcubmap, Acubes, Ycubes,
01524                                 "A", "Y\\B");
01525                         inclFABchecked = true;
01526                 }
01527         }
01528         else if (!Acubes. empty ())
01529         {
01530                 // check if F (X\A) \subset Y
01531                 if (verify)
01532                 {
01533                         checkimagecontained (Fcubmap,
01534                                 Xcubes, Ycubes, Bcubes,
01535                                 Acubes. empty () ? "X" : "X\\A", "Y");
01536                         inclFXYchecked = true;
01537                 }
01538         }
01539 
01540         // expand A within X and modify (Y,B)
01541         if (!Acubes. empty ())
01542         {
01543                 // expand A towards X and modify (Y,B) accordingly
01544                 expandAinX (Xcubes, Acubes, Ycubes, Bcubes, Fcubmap,
01545                         "X", "A", "B", true /*indexmap*/, checkacyclic);
01546         }
01547 
01548         // reduce the pair (X,A) or the set X with acyclicity check
01549         if (checkacyclic)
01550         {
01551                 // leave in A only the neighbors of X\\A
01552                 restrictAtoneighbors (Xcubes, Acubes, "X", "A");
01553 
01554                 // reduce the pair (X,A) with acyclicity check
01555                 reducepair (Xcubes, Acubes, Fcubmap, Xkeepcubes, "X", "A");
01556 
01557                 // if nothing remains in X, then the result is trivial
01558                 if (Xcubes. empty ())
01559                 {
01560                         sout << "There are no cubes left "
01561                                 "in X\\A. The homology of (X,A) "
01562                                 "is trivial and the map is 0.";
01563                         return -1;
01564                 }
01565         }
01566 
01567         // reduce the pair (X,A) even further
01568         if (!checkacyclic && !Acubes. empty ())
01569         {
01570                 // leave in A only the neighbors of X\\A
01571                 restrictAtoneighbors (Xcubes, Acubes, "X", "A");
01572 
01573                 // continue the reduction of the pair (X,A)
01574                 reducepair (Xcubes, Acubes, Xkeepcubes, "X", "A");
01575         }
01576 
01577         // indicate that the acyclicity of the map should be verified
01578         if (!verify)
01579         {
01580                 if (!checkacyclic && ((origAsize != Acubes. size ()) ||
01581                         (origXsize != Xcubes. size ())))
01582                 {
01583                         sout << "*** Important note: X or A changed. "
01584                                 "You must make sure\n"
01585                                 "*** that the restriction of F "
01586                                 "to the new sets is acyclic.\n";
01587                 }
01588                 else
01589                 {
01590                         sout << "*** Note: The program assumes "
01591                                 "that the input map is acyclic.\n";
01592                 }
01593         }
01594 
01595         // check if F (X\A) \subset Y
01596         if (verify && !inclFXYchecked)
01597         {
01598                 checkimagecontained (Fcubmap, Xcubes, Ycubes, Bcubes,
01599                         Acubes. empty () ? "X" : "X\\A", "Y");
01600                 inclFXYchecked = true;
01601         }
01602 
01603         // check if F (A) \subset B [this should always be satisfied]
01604         if (verify && !inclFABchecked && !Acubes. empty ())
01605         {
01606                 checkimagecontained (Fcubmap, Acubes, Bcubes, "A", "B");
01607                 checkimagedisjoint (Fcubmap, Acubes, Ycubes, "A", "Y\\B");
01608                 inclFABchecked = true;
01609         }
01610 
01611         // set the union of the domain of the map of interest
01612         // and the image of the map as the cubes to keep in Y
01613         hashedset<cube2ltype> Ykeepcubes;
01614         addmapimg (Fcubmap, Xcubes, Acubes, Ykeepcubes,
01615                 true /*indexmap*/);
01616 
01617         // reduce the pair of cubical sets (Y,B) towards the image of F
01618         if (Xspacedim == Yspacedim)
01619         {
01620                 expandAinX (Ycubes, Bcubes, "Y", "B");
01621                 restrictAtoneighbors (Ycubes, Bcubes, "Y", "B", &Ykeepcubes);
01622                 reducepair (Ycubes, Bcubes, Ykeepcubes, "Y", "B");
01623         }
01624 
01625         // ----- create the cubical complexes -----
01626 
01627         // transform the set of cubes X into a set of cells,
01628         // but do not forget Xcubes yet
01629         gcomplex<cell2ltype,euclidom> Xcompl;
01630         cubes2cells (Xcubes, Xcompl, Acubes. size () ? "X\\A" : "X", false);
01631 
01632         // transform the set of cubes A into a set of cubical cells
01633         // but do not forget Acubes yet
01634         gcomplex<cell2ltype,euclidom> Acompl;
01635         cubes2cells (Acubes, Acompl, "A", false);
01636 
01637         // if the set X is empty, no computations are necessary
01638         if (Xcompl. empty ())
01639         {
01640                 if (!Acompl. empty ())
01641                         sout << "The set X is contained in A. "
01642                                 "The homology of (X,A) is trivial.";
01643                 else
01644                         sout << "The set X is empty. "
01645                                 "The homology of X is trivial.";
01646                 return -1;
01647         }
01648 
01649         // transform the cubes in Y into cubical cells and forget the cubes
01650         gcomplex<cell2ltype,euclidom> *Ycompl =
01651                 new gcomplex<cell2ltype,euclidom>;
01652         cubes2cells (Ycubes, *Ycompl, Bcubes. empty () ? "Y" : "Y\\B");
01653         if (!Ycubes. empty ())
01654         {
01655                 hashedset<cube2ltype> empty;
01656                 Ycubes = empty;
01657         }
01658 
01659         // transform the cubes in B into cubical cells and forget the cubes
01660         gcomplex<cell2ltype,euclidom> Bcompl;
01661         cubes2cells (Bcubes, Bcompl, "B");
01662         if (!Bcubes. empty ())
01663         {
01664                 hashedset<cube2ltype> empty;
01665                 Bcubes = empty;
01666         }
01667 
01668         // transform the cubes to keep in Y into cells and forget the cubes
01669         gcomplex<cell2ltype,euclidom> Ykeepcompl;
01670         cubes2cells (Ykeepcubes, Ykeepcompl, "Ykeep");
01671         if (!Ykeepcubes. empty ())
01672         {
01673                 hashedset<cube2ltype> empty;
01674                 Ykeepcubes = empty;
01675         }
01676 
01677         // determine the dimension of X and Y as cubical complexes
01678         int Xdim = Xcompl. dim ();
01679         if ((Xspacedim < 0) && (Xdim >= 0))
01680                 Xspacedim = Xcompl [Xdim] [0]. spacedim ();
01681         int Ydim = Ycompl -> dim ();
01682         if ((Yspacedim < 0) && (Ydim >= 0))
01683                 Yspacedim = (*Ycompl) [Ydim] [0]. spacedim ();
01684 
01685         // ----- collapse the cubical sets (X,A) -----
01686 
01687         // create an empty set of cells to keep in X
01688         gcomplex<cell2ltype,euclidom> Xkeepcompl;
01689 
01690         // reduce the pair of sets (Xcompl, Acompl) while adding to them
01691         // boundaries of all the cells
01692         collapse (Xcompl, Acompl, Xkeepcompl, "X", "A",
01693                 true, true, false);
01694 
01695         // if nothing remains in X, then the result is trivial
01696         if (Xcompl. empty ())
01697         {
01698                 sout << "Nothing remains in X. "
01699                         "The homology of (X,A) is trivial.";
01700                 return -1;
01701         }
01702 
01703         // forget the cells to keep in X
01704         if (!Xkeepcompl. empty ())
01705         {
01706                 gcomplex<cell2ltype,euclidom> empty;
01707                 Xkeepcompl = empty;
01708         }
01709 
01710         // make a correction to the dimension of X
01711         if (Xdim != Xcompl. dim ())
01712         {
01713                 sout << "Note: The dimension of X decreased from " <<
01714                         Xdim << " to " << Xcompl. dim () << ".\n";
01715 
01716                 Xdim = Xcompl. dim ();
01717         }
01718 
01719         // ----- create a reduced graph of F -----
01720 
01721         // create the map F defined on the cells in its domain
01722         mvcellmap<cell2ltype,euclidom,cube2ltype> Fcellcubmap (Xcompl);
01723         sout << "Creating the map F on cells in X... ";
01724         int_t countimages = createimages (Fcellcubmap, Fcubmap, Fcubmap,
01725                 Xcubes, Acubes);
01726         sout << countimages << " cubes added.\n";
01727 
01728         // forget the full cubical set X
01729         if (Xcubes. size ())
01730         {
01731                 hashedset<cube2ltype> empty;
01732                 Xcubes = empty;
01733         }
01734 
01735         // create the map F defined on the cells in its domain subcomplex A
01736         mvcellmap<cell2ltype,euclidom,cube2ltype> FcellcubmapA (Acompl);
01737         if (!Acompl. empty ())
01738         {
01739                 sout << "Creating the map F on cells in A... ";
01740                 int_t count = createimages (FcellcubmapA, Fcubmap, Acubes);
01741                 sout << count << " cubes added.\n";
01742         }
01743 
01744         // forget the full cubical set A
01745         if (Acubes. size ())
01746         {
01747                 hashedset<cube2ltype> empty;
01748                 Acubes = empty;
01749         }
01750 
01751         // create the graph of F as a cubical cell complex
01752         gcomplex<cell2ltype,euclidom> *Fcompl =
01753                 new gcomplex<cell2ltype,euclidom>;
01754         sout << "Creating a cell map for F... ";
01755         mvcellmap<cell2ltype,euclidom,cell2ltype> Fcellmap (Xcompl);
01756         bool acyclic = createcellmap (Fcellcubmap, FcellcubmapA,
01757                 Fcellmap, verify);
01758         sout << "Done.\n";
01759         if (checkacyclic && !acyclic)
01760         {
01761                 sout << "*** SERIOUS PROBLEM: The map is not "
01762                         "acyclic. THE RESULT WILL BE WRONG.\n"
01763                         "*** You must verify the acyclicity of the "
01764                         "initial map with 'chkmvmap'\n"
01765                         "*** and, if successful, run this program "
01766                         "with the '-a' switch.\n";
01767         }
01768         if (checkacyclic && acyclic)
01769         {
01770                 sout << "Note: It has been verified successfully "
01771                         "that the map is acyclic.\n";
01772         }
01773 
01774         sout << "Creating the graph of F... ";
01775         creategraph (Fcellmap, *Fcompl, false);
01776         sout << Fcompl -> size () << " cells added.\n";
01777 
01778         // forget the cubical map on the cells
01779         {
01780                 mvcellmap<cell2ltype,euclidom,cube2ltype> empty;
01781                 Fcellcubmap = empty;
01782                 FcellcubmapA = empty;
01783         }
01784 
01785         // ----- collapse the cubical sets (Y,B) -----
01786 
01787         // decrease the dimension of B to the dimension of Y
01788         decreasedimension (Bcompl, Ydim, "B");
01789 
01790         // create a full cubical complex (with all the faces) of Y\B
01791         if (!Ycompl -> empty ())
01792         {
01793                 addboundaries (*Ycompl, Bcompl, 0, false, "Y", "B");
01794 
01795                 // forget the cubical complex of B
01796                 if (!Bcompl. empty ())
01797                 {
01798                         sout << "Forgetting " << Bcompl. size () <<
01799                                 " cells from B.\n";
01800                         gcomplex<cell2ltype,euclidom> empty;
01801                         Bcompl = empty;
01802                 }
01803         }
01804 
01805         // collapse the codomain of the map towards the image of F
01806         {
01807                 sout << "Computing the image of F... ";
01808                 int_t prev = Ykeepcompl. size ();
01809                 project (*Fcompl, Ykeepcompl, *Ycompl, Xspacedim, Yspacedim,
01810                         0, 0, false);
01811                 project (*Fcompl, Ykeepcompl, *Ycompl, 0, Xspacedim,
01812                         Yspacedim, 0, false);
01813                 sout << (Ykeepcompl. size () - prev) << " cells added.\n";
01814 
01815                 sout << "Collapsing Y towards F(X)... ";
01816                 gcomplex<cell2ltype,euclidom> empty;
01817                 int_t count = Ycompl -> collapse (empty, Ykeepcompl,
01818                         0, 0, 0, 0);
01819                 sout << 2 * count << " cells removed, " <<
01820                         Ycompl -> size () << " left.\n";
01821         }
01822 
01823         // forget the cells to keep in Y
01824         if (!Ykeepcompl. empty ())
01825         {
01826                 gcomplex<cell2ltype,euclidom> empty;
01827                 Ykeepcompl = empty;
01828         }
01829 
01830         // make a correction to the dimension of Y
01831         if (Ydim != Ycompl -> dim ())
01832         {
01833                 sout << "Note: The dimension of Y decreased from " <<
01834                         Ydim << " to " << Ycompl -> dim () << ".\n";
01835 
01836                 Ydim = Ycompl -> dim ();
01837         }
01838 
01839         // ----- create chain complexes from the cubical sets ------
01840 
01841         // create a chain complex from X (this is a relative chain complex!)
01842 //      chaincomplex<euclidom> cx (Xcompl. dim (), false /*generators*/);
01843 
01844         // create a chain complex from the graph of F (it is relative)
01845         chaincomplex<euclidom> cgraph (Fcompl -> dim (), false);
01846         sout << "Creating the chain complex of the graph of F... ";
01847         createchaincomplex (cgraph, *Fcompl);
01848         sout << "Done.\n";
01849 
01850         // create the chain complex from Y (this is a relative complex)
01851         chaincomplex<euclidom> cy (Ydim, false);
01852         sout << "Creating the chain complex of Y... ";
01853         createchaincomplex (cy, *Ycompl);
01854         sout << "Done.\n";
01855 
01856         // create the projection map from the graph of the map to Y
01857         chainmap<euclidom> cmap (cgraph, cy);
01858         sout << "Creating the chain map of the projection... ";
01859         createprojection (*Fcompl, *Ycompl, cmap, Xspacedim,
01860                 Yspacedim, 0);
01861         sout << "Done.\n";
01862 
01863         // if this is an index map, create the projection map from the graph
01864         // of the map to X composed with the inclusion into Y
01865         chainmap<euclidom> imap (cgraph, cy);
01866         sout << "Creating the chain map of the inclusion... ";
01867         createprojection (*Fcompl, *Ycompl, imap, 0, Xspacedim, Yspacedim);
01868         sout << "Done.\n";
01869 
01870         // forget the graph of F if it is not going to be used anymore
01871         if (gfcompl)
01872                 (*gfcompl) = Fcompl;
01873         else
01874                 delete Fcompl;
01875 
01876         // forget the cubical complex Y unless requested to keep it
01877         if (gycompl)
01878                 (*gycompl) = Ycompl;
01879         else
01880                 delete Ycompl;
01881 
01882         // ----- compute and show homology, save generators -----
01883 
01884         // prepare the name of the graph of F
01885         word gFname;
01886         gFname << "the graph of " << Fname;
01887 
01888         // compute the homology of the chain complex of the graph of the map
01889         int maxlevel_cx = Homology (cgraph, gFname, hom_cx);
01890 
01891         // extract the computed generators of the graph if requested to
01892         if (gfgen)
01893                 *gfgen = ExtractGenerators (cgraph, hom_cx, maxlevel_cx);
01894 
01895         // compute the homology of the chain complex of Y
01896         chain<euclidom> *hom_cy = 0;
01897         int maxlevel_cy = Homology (cy, Xname, hom_cy);
01898 
01899         // extract the computed generators of Y if requested to
01900         if (gygen)
01901                 *gygen = ExtractGenerators (cy, hom_cy, maxlevel_cy);
01902 
01903         // ----- show the map(s) -----
01904 
01905         // determine the maximal non-trivial homology level for maps
01906         int homdimgraph = cgraph. dim ();
01907         while ((homdimgraph >= 0) && (!hom_cx [homdimgraph]. size ()))
01908                 -- homdimgraph;
01909         int homdimy = cy. dim ();
01910         while ((homdimy >= 0) && (!hom_cy [homdimy]. size ()))
01911                 -- homdimy;
01912 //      sout << "Maximal homology level considered for the map "
01913 //              "is " << homdim << ".\n";
01914 
01915         // prepare the data structures for the homology
01916         chaincomplex<euclidom> hgraph (homdimgraph);
01917         chaincomplex<euclidom> hy (homdimy);
01918         chainmap<euclidom> *hmap = new chainmap<euclidom> (hgraph, hy);
01919         chainmap<euclidom> hincl (hgraph, hy);
01920         chainmap<euclidom> *hcomp = new chainmap<euclidom> (hgraph, hgraph);
01921 
01922         // show the map induced in homology by the chain map
01923         sout << "The map induced in homology is as follows:\n";
01924         hgraph. take_homology (hom_cx);
01925         hy. take_homology (hom_cy);
01926         hmap -> take_homology (cmap, hom_cx, hom_cy);
01927         hmap -> show (sout, "\tf", "x", "y");
01928 
01929         // show the map induced in homology by the inclusion map
01930         sout << "The map induced in homology by the inclusion:\n";
01931         hincl. take_homology (imap, hom_cx, hom_cy);
01932         hincl. show (sout, "\ti", "x", "y");
01933 
01934         sout << "The inverse of the map induced by the inclusion:\n";
01935         bool invertible = true;
01936         try
01937         {
01938                 hincl. invert ();
01939         }
01940         catch (...)
01941         {
01942                 sout << "Oh, my goodness! This map is apparently "
01943                         "not invertible.\n";
01944                 invertible = false;
01945         }
01946 
01947         if (invertible)
01948         {
01949                 hincl. show (sout, "\tI", "y", "x");
01950 
01951                 sout << "The composition of F and the inverse "
01952                         "of the map induced by the inclusion:\n";
01953                 hcomp -> compose (hincl, *hmap);
01954                 hcomp -> show (sout, "\tF", "x", "x");
01955         }
01956 
01957         // set the appropriate map
01958         if (invertible)
01959         {
01960                 hom_f = hcomp;
01961                 delete hmap;
01962         }
01963         else
01964         {
01965                 hom_f = hmap;
01966                 delete hcomp;
01967         }
01968 
01969         // throw an exception if the map is not invertible
01970         if (!invertible)
01971                 throw "Unable to invert the inclusion map.";
01972 
01973         maxlevel = (maxlevel_cx < maxlevel_cy) ? maxlevel_cx : maxlevel_cy;
01974         return maxlevel;
01975 } /* Homology2l */
01976 
01978 template <class euclidom, class cubetype>
01979 int Homology2l (mvmap<cubetype,cubetype> &Fcubmap,
01980         hashedset<cubetype> &Xcubes, hashedset<cubetype> &Acubes,
01981         chain<euclidom> *&hom, int &maxlevel,
01982         chainmap<euclidom> *&hom_f, int careful = 0x01,
01983         chain<euclidom> ***gfgen = 0,
01984         gcomplex<tCell2l<typename cubetype::CellType>,euclidom>
01985         **gfcompl = 0, chain<euclidom> ***gygen = 0,
01986         gcomplex<tCell2l<typename cubetype::CellType>,euclidom>
01987         **gycompl = 0)
01988 {
01989         return Homology2l (Fcubmap, "F", Xcubes, "X", Acubes, "A", hom,
01990                 maxlevel, hom_f, careful, gfgen, gfcompl, gygen, gycompl);
01991 } /* Homology2l */
01992 
01993 
01994 // --------------------------------------------------
01995 // ------------ ACYCLICITY VERIFICATION -------------
01996 // --------------------------------------------------
01997 
02000 inline bool acyclic (const cube &q, const cubes &X)
02001 {
02002         int dim = q. dim ();
02003         BitField b;
02004         int_t maxneighbors = getmaxneighbors (dim);
02005         b. allocate (maxneighbors);
02006         bool result = acyclic (q, dim, X, &b, maxneighbors);
02007         b. free ();
02008         return result;
02009 } /* acyclic */
02010 
02011 
02012 // --------------------------------------------------
02013 // ------------- BINARY CUBE FUNCTIONS --------------
02014 // --------------------------------------------------
02015 
02020 template <int dim, int twoPower>
02021 void ComputeBettiNumbers (bincube<dim,twoPower> &b, int *result)
02022 {
02023         using namespace chomp::homology;
02024         typedef typename bincube<dim,twoPower>::iterator cubetype;
02025         typedef typename bincube<dim,twoPower>::neighborhood_iterator
02026                 neighbortype;
02027 
02028         // perform the reduction of full cubes in the binary cube first
02029         sout << "Reducing the binary cube";
02030         int prev = b. count ();
02031         reduceFullCubes (b);
02032         sout << (prev - b. count ()) << " cubes removed, " <<
02033                 b. count () << " left.\n";
02034 
02035         // create an extra binary cube to store connected components
02036         bincube<dim,twoPower> c;
02037 
02038         // set the correct wrapping for the new binary cube and the space
02039         coordinate wrap [dim];
02040         bool setwrapping = false;
02041         for (int i = 0; i < dim; ++ i)
02042         {
02043                 if (b. wrapped (i))
02044                 {
02045                         wrap [i] = 1 << twoPower;
02046                         setwrapping = true;
02047                         c. wrap (i);
02048                 }
02049                 else
02050                         wrap [i] = 0;
02051         }
02052         if (setwrapping)
02053                 tPointBase<coordinate>::setwrapping (wrap);
02054 
02055         // reset the table to store Betti numbers
02056         for (int i = 0; i <= dim; ++ i)
02057                 result [i] = 0;
02058 
02059         // gather Betti numbers for each connected component separately
02060         bool first_run = true;
02061         while (!b. empty ())
02062         {
02063                 // increase the 0th Betti number which counts conn. comp.
02064                 ++ *result;
02065 
02066                 // extract a connected component
02067                 if (first_run)
02068                         first_run = false;
02069                 else
02070                         c. clear ();
02071                 hashIntQueue s;
02072                 s. push (static_cast<int> (b. begin ()));
02073                 while (!s. empty ())
02074                 {
02075                         int n = s. front ();
02076                         s. pop ();
02077                         neighbortype cur = b. neighborhood_begin (n);
02078                         neighbortype end = b. neighborhood_end (n);
02079                         while (cur != end)
02080                         {
02081                                 s. push (static_cast<int> (cur));
02082                                 ++ cur;
02083                         }
02084                         c. add (n);
02085                         b. remove (n);
02086                 }
02087 
02088                 // if the component has just one cube, the answer is obvious
02089                 if (c. count () == 1)
02090                         continue;
02091 
02092                 // transform the binary cube into the usual set of cubes
02093                 // (in the future this step will be postponed)
02094                 SetOfCubes X;
02095                 cubetype cur (c. begin ()), end (c. end ());
02096                 while (cur != end)
02097                 {
02098                         X. add (cube_cast<Cube> (cur));
02099                         ++ cur;
02100                 }
02101 
02102                 // say which connected component is processed
02103                 sout << "Connected component no. " << *result <<
02104                         " (" << X. size () << " cubes):\n";
02105 
02106                 // prepare a pair of sets for relative homology computation
02107                 SetOfCubes A;
02108                 int_t number = X. size () - 1;
02109                 A. add (X [number]);
02110                 X. removenum (number);
02111                 
02112                 // compute the relative homology
02113                 Chain *chn = 0;
02114                 int maxlevel = Homology (X, "X", A, "A", chn);
02115 
02116                 // display the result
02117                 ShowHomology (chn, maxlevel);
02118 
02119                 // update the Betti number count
02120                 for (int i = 1; i <= maxlevel; ++ i)
02121                         result [i] += BettiNumber (chn [i]);
02122 
02123                 // release the memory assigned to the table of chains
02124                 if (chn)
02125                         delete [] chn;
02126         }
02127         
02128         sout << "Computed Betti numbers:";
02129         for (int i = 0; i <= dim; ++ i)
02130                 sout << " " << result [i];
02131         sout << ".\n";
02132 
02133         return;
02134 } /* ComputeBettiNumbers */
02135 
02144 template <int dim, int twoPower, class coordtype>
02145 void ComputeBettiNumbers (char *binary_buffer, int *result,
02146         const coordtype *space_wrapping = 0)
02147 {
02148         using namespace chomp::homology;
02149 
02150         // create a binary cube based on the binary buffer
02151         bincube<dim,twoPower> b (binary_buffer);
02152         
02153         // set the space wrapping if requested to
02154         if (space_wrapping)
02155         {
02156                 for (int i = 0; i < dim; ++ i)
02157                 {
02158                         if (!space_wrapping [i])
02159                                 continue;
02160                         int w = space_wrapping [i];
02161                         if (w != (1 << twoPower))
02162                                 sout << "WARNING: Wrapping [" << i <<
02163                                         "] set to " << (1 << twoPower) <<
02164                                         ".\n";
02165                         b. wrap (i);
02166                 }
02167         }
02168 
02169         ComputeBettiNumbers (b, result);
02170         return;
02171 } /* ComputeBettiNumbers */
02172 
02173 
02174 // --------------------------------------------------
02175 // -------------- SIMPLIFIED INTERFACE --------------
02176 // --------------------------------------------------
02177 
02186 template <class coordtype>
02187 void ComputeBettiNumbers (coordtype *coord, int n, int dim, int *result)
02188 {
02189         using namespace chomp::homology;
02190 
02191         // create a corresponding set of cubes
02192         SetOfCubes X;
02193         coordinate c [Cube::MaxDim];
02194         coordtype const *coordpointer = coord;
02195         for (int i = 0; i < n; ++ i)
02196         {
02197                 for (int j = 0; j < dim; ++ j)
02198                         c [j] = static_cast<coordtype> (*(coordpointer ++));
02199                 X. add (Cube (c, dim));
02200         }
02201 
02202         // turn off screen output
02203         bool soutput = sout. show;
02204         sout. show = false;
02205         bool coutput = scon. show;
02206         scon. show = false;
02207         
02208         // compute the homology of the constructed cubical set
02209         Chain *hom;
02210         int maxlevel = Homology (X, "X", hom);
02211 
02212         // fill out the resulting table of Betti numbers
02213         for (int j = 0; j <= dim; ++ j)
02214                 result [j] = (j <= maxlevel) ? BettiNumber (hom [j]) : 0;
02215 
02216         // free unused memory and finish
02217         if (hom)
02218                 delete [] hom;
02219         sout. show = soutput;
02220         scon. show = coutput;
02221         return;
02222 } /* ComputeBettiNumbers */
02223 
02229 template <class coordtype>
02230 inline void SetSpaceWrapping (int dim, const coordtype *wrap)
02231 {
02232         if ((dim < 0) || (dim >= Cube::MaxDim))
02233                 return;
02234 
02235         // set space wrapping if requested to
02236         coordinate wrapcoord [Cube::MaxDim];
02237         for (int j = 0; j < dim; ++ j)
02238                 wrapcoord [j] = static_cast <coordtype>
02239                         ((wrap [j] >= 0) ? wrap [j] : -wrap [j]);
02240         tPointBase<coordinate>::setwrapping (wrapcoord, dim, dim + 1);
02241         return;
02242 } /* SetSpaceWrapping */
02243 
02244 
02245 } // namespace homology
02246 } // namespace chomp
02247 
02248 #endif // _CHOMP_HOMOLOGY_HOMOLOGY_H_
02249 
02251