gcomplex.h

Go to the documentation of this file.
00001 
00002 
00003 
00016 
00017 // Copyright (C) 1997-2010 by Pawel Pilarczyk.
00018 //
00019 // This file is part of the Homology Library.  This library is free software;
00020 // you can redistribute it and/or modify it under the terms of the GNU
00021 // General Public License as published by the Free Software Foundation;
00022 // either version 2 of the License, or (at your option) any later version.
00023 //
00024 // This library is distributed in the hope that it will be useful,
00025 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00026 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00027 // GNU General Public License for more details.
00028 //
00029 // You should have received a copy of the GNU General Public License along
00030 // with this software; see the file "license.txt".  If not, write to the
00031 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00032 // MA 02111-1307, USA.
00033 
00034 // Started in January 2002. Last revision: January 23, 2010.
00035 
00036 
00037 #ifndef _CHOMP_HOMOLOGY_GCOMPLEX_H_
00038 #define _CHOMP_HOMOLOGY_GCOMPLEX_H_
00039 
00040 #include "chomp/system/config.h"
00041 #include "chomp/system/textfile.h"
00042 #include "chomp/struct/integer.h"
00043 #include "chomp/struct/hashsets.h"
00044 #include "chomp/homology/chains.h"
00045 #include "chomp/homology/gcomplex.h"
00046 
00047 #include <iostream>
00048 #include <fstream>
00049 #include <iomanip>
00050 #include <cstdlib>
00051 
00052 namespace chomp {
00053 namespace homology {
00054 
00055 
00056 // class templates defined within this header file (in this order):
00057 template <class cell, class euclidom>
00058 class gcomplex;
00059 template <class cell, class euclidom, class element>
00060 class mvcellmap;
00061 
00062 
00063 // --------------------------------------------------
00064 // --------------- geometric complex ----------------
00065 // --------------------------------------------------
00066 
00067 template <class cell>
00068 int boundarycoef (const cell &, int i);
00069 
00070 template <class cell>
00071 int boundarylength (const cell &);
00072 
00073 template <class cell>
00074 cell boundarycell (const cell &, int i);
00075 
00084 template <class cell, class euclidom>
00085 class gcomplex
00086 {
00087 public:
00089         gcomplex ();
00090 
00092         gcomplex (const gcomplex<cell,euclidom> &c);
00093 
00095         ~gcomplex ();
00096 
00098         gcomplex &operator = (const gcomplex<cell,euclidom> &c);
00099 
00102         int dim () const;
00103 
00105         int_t size () const;
00106 
00108         bool empty () const;
00109 
00111         const hashedset<cell> &operator [] (int d) const;
00112 
00114         const hashedset<cell> &getcob (const cell &c) const;
00115 
00118         const hashedset<cell> &getcob (const cell &c, int d) const;
00119 
00121         gcomplex<cell,euclidom> &add (const cell &c);
00122 
00125         gcomplex<cell,euclidom> &add (const hashedset<cell> &c, int d);
00126 
00128         gcomplex<cell,euclidom> &add (const hashedset<cell> &c);
00129 
00131         gcomplex<cell,euclidom> &add (const gcomplex<cell,euclidom> &c);
00132 
00134         gcomplex<cell,euclidom> &remove (const cell &c);
00135 
00138         gcomplex<cell,euclidom> &remove (const hashedset<cell> &c, int d);
00139 
00141         gcomplex<cell,euclidom> &remove (const hashedset<cell> &c);
00142 
00144         gcomplex<cell,euclidom> &remove (const gcomplex<cell,euclidom> &c);
00145 
00147         gcomplex<cell,euclidom> &removeall (int d);
00148 
00151         bool check (const cell &c) const;
00152 
00156         int_t addboundaries (int d, bool addcob = false);
00157 
00161         int_t addboundaries (bool addcob = false);
00162 
00169         int_t addboundaries (int d, gcomplex<cell,euclidom> &notthese,
00170                 bool keepused = false);
00171 
00178         int_t addboundaries (gcomplex<cell,euclidom> &notthese,
00179                 bool keepused = false);
00180 
00182         int_t addboundaries (int d, chaincomplex<euclidom> &c);
00183 
00185         int_t addboundaries (chaincomplex<euclidom> &c);
00186 
00188         int_t addboundaries (int d, chaincomplex<euclidom> &c,
00189                 gcomplex<cell,euclidom> &notthese,
00190                 bool keepused = false);
00191 
00193         int_t addboundaries (chaincomplex<euclidom> &c,
00194                 gcomplex<cell,euclidom> &notthese,
00195                 bool keepused = false);
00196 
00199         int_t addboundaries (int d, chaincomplex<euclidom> *c,
00200                 gcomplex<cell,euclidom> *notthese,
00201                 bool dontadd, bool keepused, bool addcob);
00202 
00205         int_t addboundaries (chaincomplex<euclidom> *c,
00206                 gcomplex<cell,euclidom> *notthese,
00207                 bool dontadd, bool keepused, bool addcob);
00208 
00214         int_t collapse (int d,
00215                 gcomplex<cell,euclidom> &other,
00216                 const gcomplex<cell,euclidom> &keep,
00217                 bool addbd, bool addcob, bool disjoint,
00218                 bool quiet = false);
00219 
00227         int_t collapse (gcomplex<cell,euclidom> &other,
00228                 gcomplex<cell,euclidom> &keep,
00229                 bool addbd, bool addcob, bool disjoint,
00230                 const int *level = NULL, bool quiet = false);
00231 
00232 private:
00234         hashedset<cell> **tab;
00235 
00237         mvmap<cell,cell> **cob;
00238 
00240         int n;
00241 
00243         void increasedimension (int d);
00244 
00246         void decreasedimension ();
00247 
00248 }; /* class gcomplex */
00249 
00250 // --------------------------------------------------
00251 
00252 template <class cell, class euclidom>
00253 inline gcomplex<cell,euclidom>::gcomplex (): tab (NULL), cob (NULL), n (0)
00254 {
00255         return;
00256 } /* gcomplex<cell,euclidom>::gcomplex */
00257 
00258 template <class cell, class euclidom>
00259 gcomplex<cell,euclidom>::gcomplex (const gcomplex<cell,euclidom> &c)
00260 {
00261         n = c. n;
00262         if (n > 0)
00263         {
00264                 tab = new hashedset<cell> *[n];
00265                 cob = new mvmap<cell,cell> *[n];
00266                 if (!tab || !cob)
00267                         throw "Cannot copy a geometric complex.";
00268         }
00269         else
00270         {
00271                 tab = NULL;
00272                 cob = NULL;
00273         }
00274         for (int i = 0; i < n; ++ i)
00275         {
00276                 tab [i] = new hashedset<cell> (*(c. tab [i]));
00277                 cob [i] = new mvmap<cell,cell> (*(c. cob [i]));
00278                 if (!tab [i] || !cob [i])
00279                         throw "Cannot copy part of a geometric complex.";
00280         }
00281         return;
00282 } /* gcomplex<cell,euclidom>::gcomplex */
00283 
00284 template <class cell, class euclidom>
00285 gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::operator =
00286         (const gcomplex<cell,euclidom> &c)
00287 {
00288         // if the sizes of the tables are not the same, re-allocate the table
00289         // and use the copying constructor to create an identical table
00290         if (n != c. n)
00291         {
00292                 if (tab)
00293                 {
00294                         for (int i = 0; i < n; ++ i)
00295                                 delete tab [i];
00296                         delete [] tab;
00297                 }
00298                 if (cob)
00299                 {
00300                         for (int i = 0; i < n; ++ i)
00301                                 delete cob [i];
00302                         delete [] cob;
00303                 }
00304                 n = c. n;
00305                 if (n > 0)
00306                 {
00307                         tab = new hashedset<cell> *[n];
00308                         cob = new mvmap<cell,cell> *[n];
00309                         if (!tab || !cob)
00310                                 throw "Cannot copy a geometric complex.";
00311                 }
00312                 else
00313                 {
00314                         tab = NULL;
00315                         cob = NULL;
00316                 }
00317                 for (int i = 0; i < n; ++ i)
00318                 {
00319                         tab [i] = new hashedset<cell> (*(c. tab [i]));
00320                         cob [i] = new mvmap<cell,cell> (*(c. cob [i]));
00321                         if (!tab [i] || !cob [i])
00322                                 throw "Cannot copy part of a geom. complex.";
00323                 }
00324         }
00325         // otherwise copy the source table to this complex
00326         else
00327         {
00328                 for (int i = 0; i < n; ++ i)
00329                 {
00330                         *(tab [i]) = *(c. tab [i]);
00331                         *(cob [i]) = *(c. cob [i]);
00332                 }
00333         }
00334         return *this;
00335 } /* gcomplex<cell,euclidom>::operator = */
00336 
00337 template <class cell, class euclidom>
00338 gcomplex<cell,euclidom>::~gcomplex ()
00339 {
00340         for (int i = 0; i < n; ++ i)
00341         {
00342                 if (tab [i])
00343                         delete tab [i];
00344                 if (cob [i])
00345                         delete cob [i];
00346         }
00347         if (tab)
00348                 delete [] tab;
00349         if (cob)
00350                 delete [] cob;
00351         return;
00352 } /* gcomplex<cell,euclidom>::~gcomplex */
00353 
00354 template <class cell, class euclidom>
00355 inline int gcomplex<cell,euclidom>::dim () const
00356 {
00357         return n - 1;
00358 } /* gcomplex<cell,euclidom>::dim */
00359 
00360 template <class cell, class euclidom>
00361 int_t gcomplex<cell,euclidom>::size () const
00362 {
00363         int_t count = 0;
00364         for (int i = 0; i < n; ++ i)
00365                 count += tab [i] -> size ();
00366         return count;
00367 } /* gcomplex<cell,euclidom>::size */
00368 
00369 template <class cell, class euclidom>
00370 bool gcomplex<cell,euclidom>::empty () const
00371 {
00372         if (!n)
00373                 return true;
00374         for (int i = 0; i < n; ++ i)
00375                 if (!(*(tab [i])). empty ())
00376                         return false;
00377         return true;
00378 } /* gcomplex<cell,euclidom>::empty */
00379 
00380 template <class cell, class euclidom>
00381 inline const hashedset<cell> &gcomplex<cell,euclidom>::operator [] (int d)
00382         const
00383 {
00384         if ((d < 0) || (d >= n))
00385                 throw "Dimension out of range for retrieving cells.";
00386         return *(tab [d]);
00387 } /* gcomplex<cell,euclidom>::operator [] */
00388 
00389 template <class cell, class euclidom>
00390 inline const hashedset<cell> &gcomplex<cell,euclidom>::getcob (const cell &c)
00391         const
00392 {
00393         return getcob (c, c. dim ());
00394 } /* gcomplex<cell,euclidom>::getcob */
00395 
00396 template <class cell, class euclidom>
00397 inline const hashedset<cell> &gcomplex<cell,euclidom>::getcob (const cell &c,
00398         int d) const
00399 {
00400         if ((d < 0) || (d >= n))
00401                 throw "Dimension out of range for coboundary.";
00402         return (*(cob [d])) (c);
00403 } /* gcomplex<cell,euclidom>::getcob */
00404 
00405 template <class cell, class euclidom>
00406 inline gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::add (const cell &c)
00407 {
00408         // get the dimension of the cell
00409         int d = c. dim ();
00410         if (d < 0)
00411                 throw "Negative dimension of a cell to be added.";
00412 
00413         // if the dimension of the cell is beyond the allocated table,
00414         // then increase the table
00415         if (n <= d)
00416                 increasedimension (d);
00417 
00418         // add the cell to the suitable set of cells
00419         tab [d] -> add (c);
00420 
00421         return *this;
00422 } /* gcomplex<cell,euclidom>::add */
00423 
00424 template <class cell, class euclidom>
00425 inline gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::add
00426         (const hashedset<cell> &c, int d)
00427 {
00428         // increase the dimension of the complex if necessary
00429         if (d > n)
00430                 increasedimension (d);
00431 
00432         // add the set of cells to the suitable set
00433         tab [d] -> add (c);
00434 
00435         return *this;
00436 } /* gcomplex<cell,euclidom>::add */
00437 
00438 template <class cell, class euclidom>
00439 gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::add
00440         (const hashedset<cell> &c)
00441 {
00442         int_t size = c. size ();
00443         for (int_t i = 0; i < size; ++ i)
00444                 add (c [i]);
00445 
00446         return *this;
00447 } /* gcomplex<cell,euclidom>::add */
00448 
00449 template <class cell, class euclidom>
00450 gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::add
00451         (const gcomplex<cell,euclidom> &c)
00452 {
00453         // increase the dimension of the complex if necessary
00454         if (c. n > n)
00455                 increasedimension (c. dim ());
00456 
00457         // add the sets of cells
00458         for (int i = 0; i < c. n; ++ i)
00459         {
00460                 tab [i] -> add (*(c. tab [i]));
00461         /*      const hashedset<cell> &cset = *(c. tab [i]);
00462                 for (int j = 0; j < cset. size (); ++ j)
00463                 {
00464                         const cell &thecell = cset [j];
00465                         tab [i] -> add (thecell);
00466                         if (cob && c. cob)
00467                                 (*(cob [i])) [thecell] =
00468                                         ((*(c. cob [i])) (thecell));
00469                 }
00470         */
00471         }
00472 
00473         return *this;
00474 } /* gcomplex<cell,euclidom>::add */
00475 
00476 template <class cell, class euclidom>
00477 inline gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::remove
00478         (const cell &c)
00479 {
00480         // get the dimension of the cell
00481         int d = c. dim ();
00482         if (d < 0)
00483                 throw "Negative dimension of a cell to be removed.";
00484 
00485         // if the dimension of the cell is beyond the allocated table,
00486         // then ignore it
00487         if (n <= d)
00488                 return *this;
00489 
00490         // remove the cell from the suitable set of cells
00491         tab [d] -> remove (c);
00492 
00493         // decrease the dimension of the complex if no cells remain
00494         if ((d == n - 1) && tab [d] -> empty ())
00495                 decreasedimension ();
00496 
00497         return *this;
00498 } /* gcomplex<cell,euclidom>::remove */
00499 
00500 template <class cell, class euclidom>
00501 gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::remove
00502         (const gcomplex<cell,euclidom> &c)
00503 {
00504         // figure out the number of tables to work on
00505         int m = c. n;
00506         if (m > n)
00507                 m = n;
00508 
00509         // remove the sets of cells
00510         for (int i = 0; i < m; ++ i)
00511                 tab [i] -> remove (*(c. tab [i]));
00512 
00513         // decrease the dimension of the complex if no highdim cells remain
00514         decreasedimension ();
00515 
00516         return *this;
00517 } /* gcomplex<cell,euclidom>::remove */
00518 
00519 template <class cell, class euclidom>
00520 inline gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::remove
00521         (const hashedset<cell> &c, int d)
00522 {
00523         // remove the set of cells to the suitable set
00524         tab [d] -> remove (c);
00525 
00526         // decrease the dimension of the complex if no highdim cells remain
00527         decreasedimension ();
00528 
00529         return *this;
00530 } /* gcomplex<cell,euclidom>::remove */
00531 
00532 template <class cell, class euclidom>
00533 gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::remove
00534         (const hashedset<cell> &c)
00535 {
00536         int_t size = c. size ();
00537         for (int_t i = 0; i < size; ++ i)
00538                 remove (c [i]);
00539 
00540         return *this;
00541 } /* gcomplex<cell,euclidom>::remove */
00542 
00543 template <class cell, class euclidom>
00544 gcomplex<cell,euclidom> &gcomplex<cell,euclidom>::removeall (int d)
00545 {
00546         if (d == n - 1)
00547         {
00548                 -- n;
00549                 delete tab [n];
00550                 delete cob [n];
00551                 decreasedimension ();
00552         }
00553         else if ((d >= 0) && (d < n))
00554         {
00555                 delete tab [d];
00556                 tab [d] = new hashedset<cell>;
00557         }
00558 
00559         return *this;
00560 } /* gcomplex<cell,euclidom>::removeall */
00561 
00562 template <class cell, class euclidom>
00563 bool gcomplex<cell,euclidom>::check (const cell &c) const
00564 {
00565         // get the dimension of the cell
00566         int d = c. dim ();
00567         if (d < 0)
00568                 throw "Negative dimension of a cell to be checked.";
00569 
00570         // if the dimension of the cell is beyond the allocated table,
00571         // then it is not there
00572         if (n <= d)
00573                 return false;
00574 
00575         // check for the existence of the cell in the suitable set of cells
00576         return tab [d] -> check (c);
00577 } /* gcomplex<cell,euclidom>::check */
00578 
00579 template <class cell, class euclidom>
00580 int_t gcomplex<cell,euclidom>::addboundaries (int d,
00581         chaincomplex<euclidom> *c, gcomplex<cell,euclidom> *notthese,
00582         bool dontadd, bool keepused, bool addcob)
00583 {
00584         // if the dimension is inappropriate, do nothing
00585         if ((d <= 0) || (d >= n))
00586                 return 0;
00587 
00588         // first add boundaries to the other cell complex
00589         if (notthese && !dontadd)
00590                 notthese -> addboundaries (d);
00591 
00592         int_t prevsize = tab [d - 1] -> size ();
00593         hashedset<cell> &cset = *(tab [d]);
00594         for (int_t i = 0; i < cset. size (); ++ i)
00595         {
00596                 const cell &thecell = cset [i];
00597                 int len = boundarylength (thecell);
00598                 for (int j = 0; j < len; ++ j)
00599                 {
00600                         // take the j-th boundary cell
00601                         cell bcell = boundarycell (thecell, j);
00602 
00603                         // add it to the cell complex unless it is unwanted
00604                         if (!notthese || !notthese -> check (bcell))
00605                         {
00606                                 tab [d - 1] -> add (bcell);
00607                                 if (c)
00608                                 {
00609                                         int icoef = boundarycoef (thecell, j);
00610                                         euclidom coef;
00611                                         if (icoef < 0)
00612                                         {
00613                                                 coef = -icoef;
00614                                                 coef = -coef;
00615                                         }
00616                                         else
00617                                                 coef = icoef;
00618                                         c -> add (d, tab [d - 1] ->
00619                                                 getnumber (bcell), i, coef);
00620                                 }
00621                                 if (addcob)
00622                                         (*(cob [d - 1])) [bcell].
00623                                                 add (thecell);
00624                         }
00625                 }
00626         }
00627 
00628         // clean the used level in 'notthese'
00629         if (notthese && !keepused)
00630                 notthese -> removeall (d);
00631 
00632         return tab [d - 1] -> size () - prevsize;
00633 } /* gcomplex<cell,euclidom>::addboundaries */
00634 
00635 template <class cell, class euclidom>
00636 int_t gcomplex<cell,euclidom>::addboundaries (chaincomplex<euclidom> *c,
00637         gcomplex<cell,euclidom> *notthese, bool dontadd, bool keepused,
00638         bool addcob)
00639 {
00640         int_t countadded = 0;
00641         for (int d = n - 1; d > 0; -- d)
00642                 countadded += addboundaries (d, c, notthese,
00643                         dontadd, keepused, addcob);
00644         return countadded;
00645 } /* gcomplex<cell,euclidom>::addboundaries */
00646 
00647 template <class cell, class euclidom>
00648 inline int_t gcomplex<cell,euclidom>::addboundaries (int d, bool addcob)
00649 {
00650         return addboundaries (d, NULL, NULL, false, false, addcob);
00651 } /* gcomplex<cell,euclidom>::addboundaries */
00652 
00653 template <class cell, class euclidom>
00654 inline int_t gcomplex<cell,euclidom>::addboundaries (bool addcob)
00655 {
00656         return addboundaries (NULL, NULL, false, false, addcob);
00657 } /* gcomplex<cell,euclidom>::addboundaries */
00658 
00659 template <class cell, class euclidom>
00660 inline int_t gcomplex<cell,euclidom>::addboundaries (int d,
00661         gcomplex<cell,euclidom> &notthese, bool keepused)
00662 {
00663         return addboundaries (d, NULL, &notthese, false, keepused, false);
00664 } /* gcomplex<cell,euclidom>::addboundaries */
00665 
00666 template <class cell, class euclidom>
00667 int_t gcomplex<cell,euclidom>::addboundaries
00668         (gcomplex<cell,euclidom> &notthese, bool keepused)
00669 {
00670         return addboundaries (NULL, &notthese, false, keepused, false);
00671 } /* gcomplex<cell,euclidom>::addboundaries */
00672 
00673 template <class cell, class euclidom>
00674 inline int_t gcomplex<cell,euclidom>::addboundaries (int d,
00675         chaincomplex<euclidom> &c)
00676 {
00677         return addboundaries (d, &c, NULL, false, false, false);
00678 } /* gcomplex<cell,euclidom>::addboundaries */
00679 
00680 template <class cell, class euclidom>
00681 inline int_t gcomplex<cell,euclidom>::addboundaries (chaincomplex<euclidom> &c)
00682 {
00683         return addboundaries (&c, NULL, false, false, false);
00684 } /* gcomplex<cell,euclidom>::addboundaries */
00685 
00686 template <class cell, class euclidom>
00687 inline int_t gcomplex<cell,euclidom>::addboundaries (int d,
00688         chaincomplex<euclidom> &c, gcomplex<cell,euclidom> &notthese,
00689         bool keepused)
00690 {
00691         return addboundaries (d, &c, &notthese, false, keepused, false);
00692 } /* gcomplex<cell,euclidom>::addboundaries */
00693 
00694 template <class cell, class euclidom>
00695 inline int_t gcomplex<cell,euclidom>::addboundaries (chaincomplex<euclidom> &c,
00696         gcomplex<cell,euclidom> &notthese, bool keepused)
00697 {
00698         return addboundaries (&c, &notthese, false, keepused, false);
00699 } /* gcomplex<cell,euclidom>::addboundaries */
00700 
00701 // --------------------------------------------------
00702 
00705 template <class element>
00706 int_t findelem (const multitable<element> &tab, const element &e, int_t len)
00707 {
00708         if (len <= 0)
00709                 return -1;
00710 
00711         // prepare a random search starting point and step increase
00712         int_t i = static_cast<int_t> (std::rand ()) % len;
00713         if (i < 0)
00714                 i = static_cast<int_t> (1) - i;
00715         int_t step = static_cast<int_t> (std::rand () + 17) % len;
00716         if (step < 0)
00717                 step = static_cast<int_t> (1) - step;
00718         if (step < 17)
00719                 step = 17;
00720         if (step > len)
00721                 step = len >> 1;
00722         if (step < 1)
00723                 step = 1;
00724 
00725         // jump randomly in the table to find some element if possible
00726         int_t jumping = len >> 1;
00727         while (jumping --)
00728         {
00729         //      if ((i < 0) || (i >= len))
00730         //              throw "Wrong random number.";
00731                 if (tab (i) == e)
00732                         return i;
00733         //      if ((i + 1 < len) && (tab (i + 1) == e))
00734         //              return i + 1;
00735                 if (jumping)
00736                 {
00737                         i += step;
00738                         if (i >= len)
00739                                 i -= len;
00740                 }
00741         }
00742 
00743         // if not found, try finding the element thoroughly
00744         for (int_t i = 0; i < len; ++ i)
00745         {
00746                 if (tab (i) == e)
00747                         return i;
00748         }
00749         return -1;
00750 } /* findelem */
00751 
00752 template <class cell, class euclidom>
00753 int_t gcomplex<cell,euclidom>::collapse (int d,
00754         gcomplex<cell,euclidom> &other, const gcomplex<cell,euclidom> &keep,
00755         bool addbd, bool addcob, bool disjoint, bool quiet)
00756 {
00757         if ((d <= 0) || (d > dim ()))
00758                 return 0;
00759 
00760         // prepare references to the sets of cells of interest
00761         hashedset<cell> &cset = *(tab [d]);
00762         hashedset<cell> &bset = *(tab [d - 1]);
00763         hashedset<cell> empty;
00764         hashedset<cell> &cother = (other. dim () >= d) ?
00765                 *(other. tab [d]) : empty;
00766         hashedset<cell> &bother = (other. dim () >= d - 1) ?
00767                 *(other. tab [d - 1]) : empty;
00768         const hashedset<cell> &ckeep = (keep. dim () >= d) ?
00769                 *(keep. tab [d]) : empty;
00770         const hashedset<cell> &bkeep = (keep. dim () >= d - 1) ?
00771                 *(keep. tab [d - 1]) : empty;
00772 
00773         // show the currently processed dimension
00774         if (!quiet)
00775         {
00776                 if (d > 9)
00777                         scon << "#\b";
00778                 else
00779                         scon << d << '\b';
00780         }
00781 
00782         // go through all the cells from A and generate their boundaries
00783         if (addbd)
00784         {
00785                 if (!quiet)
00786                 {
00787                         sseq << "\"Adding boundaries of cells in A...\"\n";
00788                         sseq << "D 0\n";
00789                 }
00790                 for (int_t i = 0; i < cother. size (); ++ i)
00791                 {
00792                         // select the given cell in 'cother'
00793                         const cell &thecell = cother [i];
00794 
00795                         // detect the length of the boundary of this cell
00796                         int blen = boundarylength (thecell);
00797 
00798                         // add to 'bother' all the cells in this boundary
00799                         for (int j = 0; j < blen; ++ j)
00800                                 bother. add (boundarycell (thecell, j));
00801 
00802                         // write the boundary cells to the sequential file
00803                         if (!quiet && (sseq. show || sseq. log))
00804                         {
00805                                 for (int j = 0; j < blen; ++ j)
00806                                         sseq << '2' << boundarycell
00807                                                 (thecell, j) << '\n';
00808                         }
00809                 }
00810         }
00811         if (!quiet)
00812                 sseq << "D 100\n";
00813 
00814         // if the complexes should be disjoint, remove 'bother' from 'bset'
00815         if (disjoint)
00816                 bset. remove (bother);
00817 
00818         // prepare tables for coboundaries of cells in X and their lengths
00819         multitable<int> coblen;
00820         multitable<hashedset <cell> > coboundary;
00821         if (!bset. empty ())
00822                 coblen. fill (0, bset. size ());
00823 
00824         // go through the list of all the cells of dimension 'd' in the set,
00825         // add their boundaries to 'bset' and create the coboundary links;
00826         // note: these cells may appear in the 'other' complex
00827         if (!quiet)
00828                 sseq << "\"Adding boundaries of cells of dimension " <<
00829                         d << "\"\nD 0\n";
00830         bool maximal = (d == dim ());
00831         for (int_t i = 0; i < cset. size (); ++ i)
00832         {
00833                 // select the i-th d-dimensional cell
00834                 const cell &thecell = cset [i];
00835 
00836                 // check if this cell belongs to 'cother'
00837                 bool cbelongs = cother. check (thecell);
00838 
00839                 // if this cell should be removed, do it
00840                 if (cbelongs && (disjoint || maximal))
00841                 {
00842                 //      if (!quiet && (sseq. show || sseq. log))
00843                 //              sseq << '0' << thecell << '\n';
00844                         cother. remove (thecell);
00845                         cset. removenum (i --);
00846                         continue;
00847                 }
00848 
00849                 // detect the length of the boundary of this cell
00850                 int blen = boundarylength (thecell);
00851 
00852                 // should this cell be kept secure from the collapses?
00853                 bool keepit = ckeep. check (thecell);
00854 
00855                 // go through all the cells in this boundary
00856                 for (int j = 0; j < blen; ++ j)
00857                 {
00858                         // take the j-th boundary cell
00859                         cell bcell = boundarycell (thecell, j);
00860 
00861                         // check if this cell belongs to the other complex
00862                         bool bbelongs = bother. check (bcell);
00863 
00864                         // if it is in 'bother', then skip it if disjoint
00865                         if (bbelongs && disjoint)
00866                                 continue;
00867 
00868                         // add this cell to 'bset' or get its number
00869                         int_t prev = bset. size ();
00870                         int_t number = addbd ? bset. add (bcell) :
00871                                 bset. getnumber (bcell);
00872 
00873                         // if the cell is not there, skip it
00874                         if (number < 0)
00875                                 continue;
00876 
00877                         // if this is the first occurrence of the cell
00878                         if ((prev < bset. size ()) || (coblen [number] == 0))
00879                         {
00880                                 // write it to the sequence if necessary
00881                                 if (!quiet && !bbelongs)
00882                                         sseq << '1' << bcell << '\n';
00883 
00884                                 // if this cell should be kept, mark it
00885                                 if (keepit || bkeep. check (bset [number]) ||
00886                                         bother. check (bset [number]))
00887                                         coblen [number] = 13;
00888                                 else
00889                                         coblen [number] = 1;
00890                                 coboundary [number]. add (thecell);
00891                         }
00892 
00893                         // otherwise add the corresponding coboundary link
00894                         else
00895                         {
00896                                 ++ (coblen [number]);
00897                                 coboundary [number]. add (thecell);
00898                         }
00899                 }
00900         }
00901         if (!quiet)
00902                 sseq << "D 100\n";
00903 
00904         // show a dot
00905         if (!quiet)
00906                 scon << "*\b";
00907 
00908         // prepare tables for cells to be removed
00909         hashedset<cell> cremove, bremove;
00910         int_t nremove = 0;
00911 
00912         // go through all the free faces
00913         if (!quiet)
00914                 sseq << "\"Collapsing free faces...\"\n";
00915         while (1)
00916         {
00917                 // find a free face
00918                 int_t ncell = findelem (coblen, 1, bset. size ());
00919 
00920                 // if not found then finish
00921                 if (ncell < 0)
00922                         break;
00923 
00924                 // collapse this cell with its parent cell
00925                 const cell &parent = coboundary [ncell] [0];
00926                 int blen = boundarylength (parent);
00927                 coblen [ncell] = 0;
00928 
00929                 // remove the parent cell from coboundaries
00930                 for (int j = 0; j < blen; ++ j)
00931                 {
00932                         cell thecell = boundarycell (parent, j);
00933                         int_t number = bset. getnumber (thecell);
00934                         if ((number >= 0) && (coblen [number] > 0))
00935                         {
00936                                 coboundary [number]. remove (parent);
00937                                 -- (coblen [number]);
00938                         }
00939                 }
00940 
00941                 // write these cells to the sequence file
00942                 if (!quiet)
00943                 {
00944                         sseq << '0' << bset [ncell] << '\n';
00945                         sseq << '0' << parent << '\n';
00946                 }
00947 
00948                 // mark these cells for removal
00949                 cremove. add (parent);
00950                 bremove. add (bset [ncell]);
00951                 ++ nremove;
00952 
00953                 // clear the coboundary, because it is no longer used
00954                 coboundary [ncell] = empty;
00955         }
00956 
00957         // add the computed coboundaries if required
00958         if (addcob)
00959         {
00960                 for (int_t i = 0; i < bset. size (); ++ i)
00961                         if (!bremove. check (bset [i]))
00962                         {
00963                                 coboundary [i]. remove (cremove);
00964                                 (*(cob [d - 1])) [bset [i]]. add
00965                                         (coboundary [i]);
00966                         }
00967         }
00968 
00969         // remove cells that are scheduled for removal from 'cset'
00970         if (nremove == cset. size ())
00971         {
00972                 removeall (d);
00973                 other. removeall (d);
00974         }
00975         else
00976         {
00977                 for (int_t i = 0; i < nremove; ++ i)
00978                         cset. remove (cremove [i]);
00979         }
00980 
00981         // remove from the set of boundary cells these scheduled for removal
00982         for (int_t i = 0; i < nremove; ++ i)
00983                 bset. remove (bremove [i]);
00984 
00985         // update the dimension of the cell complex - is this necessary?
00986         decreasedimension ();
00987 
00988         // show a dot
00989         if (!quiet)
00990                 scon << '.';
00991 
00992         return nremove;
00993 } /* gcomplex<cell,euclidom>::collapse */
00994 
00995 template <class cell, class euclidom>
00996 int_t gcomplex<cell,euclidom>::collapse (gcomplex<cell,euclidom> &other,
00997         gcomplex<cell,euclidom> &keep, bool addbd, bool addcob,
00998         bool disjoint, const int *level, bool quiet)
00999 {
01000         // determine the lower bound for the adding boundaries levels
01001         int dmin = 0;
01002         if (level)
01003         {
01004                 while ((dmin < dim ()) && (!level [dmin]))
01005                         ++ dmin;
01006                 if (dmin && level [dmin])
01007                         -- dmin;
01008         }
01009 
01010         // add boundaries to high-dimensional cells in 'keep'
01011         while (keep. dim () > dim ())
01012         {
01013                 keep. addboundaries (keep. dim ());
01014                 keep. removeall (keep. dim ());
01015         }
01016 
01017         // add boundaries to high-dimensional cells in 'other'
01018         if (other. dim () > dim ())
01019         {
01020                 other. addboundaries (other. dim ());
01021                 other. removeall (other. dim ());
01022         }
01023 
01024         // add boundaries and collapse in all the dimensions of interest
01025         int_t counter = 0;
01026         for (int d = dim (); d > dmin; -- d)
01027         {
01028                 // add boundaries to the other cell complexes
01029                 keep. addboundaries (d);
01030 
01031                 // add boundaries and collapse this level
01032                 counter += collapse (d, other, keep, addbd, addcob, disjoint,
01033                         quiet);
01034 
01035                 // remove unnecessary cells from 'other'
01036                 if (disjoint)
01037                         other. removeall (d);
01038 
01039                 // remove unnecessary cells from 'keep'
01040                 keep. removeall (d);
01041         }
01042 
01043         // forget all the other cells of minimal dimension which are not used
01044         if (!disjoint && (dim () >= dmin) && (other. dim () >= dmin))
01045         {
01046                 hashedset<cell> &cset = *(tab [dmin]);
01047                 hashedset<cell> &cother = *(other. tab [dmin]);
01048                 for (int_t i = 0; i < cother. size (); ++ i)
01049                 {
01050                         if (!(cset. check (cother [i])))
01051                                 cother. removenum (i --);
01052                 }
01053         }
01054 
01055         // remove unused cells which were supposed to be kept
01056         if (!keep. empty ())
01057         {
01058                 gcomplex<cell,euclidom> empty;
01059                 keep = empty;
01060         }
01061 
01062         if (!quiet)
01063                 scon << ' ';
01064 
01065         return counter;
01066 } /* gcomplex<cell,euclidom>::collapse */
01067 
01068 template <class cell, class euclidom>
01069 void gcomplex<cell,euclidom>::increasedimension (int d)
01070 {
01071         // create a new table for sets of cells
01072         hashedset<cell> **newtab = new hashedset<cell> *[d + 1];
01073         mvmap<cell,cell> **newcob = new mvmap<cell,cell> *[d + 1];
01074 
01075         // copy anything that was in the old table
01076         for (int i = 0; i < n; ++ i)
01077         {
01078                 newtab [i] = tab [i];
01079                 newcob [i] = cob [i];
01080         }
01081 
01082         // delete the old table if it was allocated
01083         if (tab)
01084                 delete [] tab;
01085         if (cob)
01086                 delete [] cob;
01087 
01088         // initialize the remaining portion of the new table
01089         tab = newtab;
01090         cob = newcob;
01091         for (int i = n; i < d + 1; ++ i)
01092         {
01093                 tab [i] = new hashedset<cell>;
01094                 cob [i] = new mvmap<cell,cell>;
01095         }
01096 
01097         // set the new dimension
01098         n = d + 1;
01099 
01100         return;
01101 } /* gcomplex<cell,euclidom>::increasedimension */
01102 
01103 template <class cell, class euclidom>
01104 void gcomplex<cell,euclidom>::decreasedimension ()
01105 {
01106         while (n && tab [n - 1] -> empty ())
01107         {
01108                 -- n;
01109                 delete tab [n];
01110                 delete cob [n];
01111         }
01112         if (!n)
01113         {
01114                 delete [] tab;
01115                 tab = NULL;
01116                 delete [] cob;
01117                 cob = NULL;
01118         }
01119         return;
01120 } /* gcomplex<cell,euclidom>::decreasedimension */
01121 
01122 // --------------------------------------------------
01123 
01128 template <class cell, class euclidom>
01129 chaincomplex<euclidom> &createchaincomplex (chaincomplex<euclidom> &c,
01130         const gcomplex<cell,euclidom> &g, bool quiet = false)
01131 {
01132         if (g. dim () < 0)
01133                 return c;
01134         c. def_gen (0, g [0]. size ());
01135         for (int d = 1; d <= g. dim (); ++ d)
01136         {
01137                 c. def_gen (d, g [d]. size ());
01138                 for (int_t i = 0; i < g [d]. size (); ++ i)
01139                 {
01140                         int len = boundarylength (g [d] [i]);
01141                         for (int j = 0; j < len; ++ j)
01142                         {
01143                                 // take the j-th boundary cell
01144                                 cell thecell = boundarycell (g [d] [i], j);
01145         
01146                                 // add it to the chain complex
01147                                 if (g. check (thecell))
01148                                 {
01149                                         int icoef = boundarycoef
01150                                                 (g [d] [i], j);
01151                                         euclidom coef;
01152                                         if (icoef < 0)
01153                                         {
01154                                                 coef = -icoef;
01155                                                 coef = -coef;
01156                                         }
01157                                         else
01158                                                 coef = icoef;
01159                                         c. add (d, g [d - 1]. getnumber
01160                                                 (thecell), i, coef);
01161                                 }
01162                         }
01163                 }
01164                 if (!quiet)
01165                 {
01166                         if (d < g. dim ())
01167                                 scon << '.';
01168                         else
01169                                 scon << ". ";
01170                 }
01171         }
01172         return c;
01173 } /* createchaincomplex */
01174 
01180 template <class cell, class euclidom>
01181 std::ostream &writechaincomplex (std::ostream &out,
01182         const gcomplex<cell,euclidom> &g, bool symbolicnames = false,
01183         bool quiet = false)
01184 {
01185         if (g. dim () < 0)
01186                 return out;
01187         out << "chaincomplex\n\n";
01188         out << "maxdimension " << g. dim () << "\n\n";
01189         out << "dimension 0: " << g [0]. size () << "\n\n";
01190         for (int d = 1; d <= g. dim (); ++ d)
01191         {
01192                 out << "dimension " << d << ": " << g [d]. size () << "\n";
01193                 for (int_t i = 0; i < g [d]. size (); ++ i)
01194                 {
01195                         bool cellwritten = false;
01196                         int len = boundarylength (g [d] [i]);
01197                         for (int j = 0; j < len; ++ j)
01198                         {
01199                                 // take the j-th boundary cell
01200                                 cell thecell = boundarycell (g [d] [i], j);
01201 
01202                                 // add it to the chain complex
01203                                 if (g. check (thecell))
01204                                 {
01205                                         int icoef = boundarycoef
01206                                                 (g [d] [i], j);
01207                                         euclidom coef;
01208                                         if (icoef < 0)
01209                                         {
01210                                                 coef = -icoef;
01211                                                 coef = -coef;
01212                                         }
01213                                         else
01214                                                 coef = icoef;
01215                                         if (!cellwritten)
01216                                         {
01217                                                 out << "\t# ";
01218                                                 if (symbolicnames)
01219                                                         out << g [d] [i];
01220                                                 else
01221                                                         out << (i + 1);
01222                                                 out << " = ";
01223                                                 if (-coef == 1)
01224                                                         out << "- ";
01225                                         }
01226                                         else if (coef == 1)
01227                                                 out << " + ";
01228                                         else if (-coef == 1)
01229                                                 out << " - ";
01230                                         else
01231                                                 out << " + " << coef <<
01232                                                         " * ";
01233                                         if (symbolicnames)
01234                                                 out << thecell;
01235                                         else
01236                                                 out << (1 + g [d - 1].
01237                                                         getnumber (thecell));
01238                                         cellwritten = true;
01239                                 }
01240                         }
01241                         if (cellwritten)
01242                                 out << '\n';
01243                 }
01244                 if (!quiet)
01245                 {
01246                         if (d < g. dim ())
01247                                 scon << '.';
01248                         else
01249                                 scon << ". ";
01250                 }
01251                 out << '\n';
01252         }
01253         return out;
01254 } /* writechaincomplex */
01255 
01260 template <class cell, class euclidom>
01261 chaincomplex<euclidom> &createchaincomplex (chaincomplex<euclidom> &c,
01262         const gcomplex<cell,euclidom> &g, const gcomplex<cell,euclidom> &rel,
01263         bool quiet = false)
01264 {
01265         // if the geometric complex is empty, don't modify the chain complex
01266         if (g. dim () < 0)
01267                 return c;
01268 
01269         // prepare a table of numbers of ignored cells in the geom. complex
01270         multitable<int_t> *numbers0 = new multitable<int_t>;
01271         int_t count0 = g [0]. size ();
01272         if (rel. dim () >= 0)
01273         {
01274                 count0 -= rel [0]. size ();
01275                 int_t j = 0;
01276                 for (int_t i = 0; i < rel [0]. size (); ++ i)
01277                 {
01278                         (*numbers0) [j] = g [0]. getnumber (rel [0] [i]);
01279                         if ((*numbers0) [j] < 0)
01280                                 ++ count0;
01281                         else
01282                                 ++ j;
01283                 }
01284         }
01285 
01286         // set the number of generators of the given dimension
01287         c. def_gen (0, count0);
01288 
01289         // create boundary matrices
01290         for (int d = 1; d <= g. dim (); ++ d)
01291         {
01292                 // prepare a table of numbers to be ignored
01293                 multitable<int_t> *numbers1 = new multitable<int_t>;
01294                 int_t count1 = g [d]. size ();
01295                 if (rel. dim () >= d)
01296                 {
01297                         count1 -= rel [d]. size ();
01298                         int_t j = 0;
01299                         for (int_t i = 0; i < rel [d]. size (); ++ i)
01300                         {
01301                                 (*numbers1) [j] =
01302                                         g [d]. getnumber (rel [d] [i]);
01303                                 if ((*numbers1) [j] < 0)
01304                                         ++ count1;
01305                                 else
01306                                         ++ j;
01307                         }
01308                 }
01309 
01310                 // set the number of generators of this dimension
01311                 c. def_gen (d, count1);
01312 
01313                 // create the boundary connections with coefficients
01314                 for (int_t i = 0; i < g [d]. size (); ++ i)
01315                 {
01316                         // if this cell is in the other complex, ignore it
01317                         if ((rel. dim () >= d) &&
01318                                 (rel [d]. check (g [d] [i])))
01319                                 continue;
01320 
01321                         // determine the number of this cell
01322                         int_t n1 = i;
01323                         if (n1 >= count1)
01324                                 n1 = (*numbers1) [n1 - count1];
01325 
01326                         // get the length of the cell
01327                         int len = boundarylength (g [d] [i]);
01328 
01329                         // retrieve boundary cells and make boundary formula
01330                         for (int j = 0; j < len; ++ j)
01331                         {
01332                                 // take the j-th boundary cell
01333                                 cell thecell = boundarycell (g [d] [i], j);
01334 
01335                                 // add it to the chain complex if relevant
01336                                 if (g [d - 1]. check (thecell) &&
01337                                         ((rel. dim () < d - 1) ||
01338                                         (!rel [d - 1]. check (thecell))))
01339                                 {
01340                                         // determine the number of the cell
01341                                         int_t n0 = g [d - 1].
01342                                                 getnumber (thecell);
01343 
01344                                         // if out of range, translate it
01345                                         if (n0 >= count0)
01346                                                 n0 = (*numbers0)
01347                                                         [n0 - count0];
01348 
01349                                         // determine the right coefficient
01350                                         int icoef = boundarycoef
01351                                                 (g [d] [i], j);
01352                                         euclidom coef;
01353                                         if (icoef < 0)
01354                                         {
01355                                                 coef = -icoef;
01356                                                 coef = -coef;
01357                                         }
01358                                         else
01359                                                 coef = icoef;
01360 
01361                                         // add this link to the boundary
01362                                         c. add (d, n0, n1, coef);
01363                                 }
01364                         }
01365                 }
01366 
01367                 // forget unnecessary tables and prepare for the next loop
01368                 delete numbers0;
01369                 numbers0 = numbers1;
01370                 count0 = count1;
01371 
01372                 // show progress indicator
01373                 if (!quiet)
01374                 {
01375                         if (d < g. dim ())
01376                                 scon << '.';
01377                         else
01378                                 scon << ". ";
01379                 }
01380         }
01381 
01382         // release used memory
01383         delete numbers0;
01384 
01385         // finish
01386         return c;
01387 } /* createchaincomplex */
01388 
01390 template <class cell, class euclidom>
01391 std::ostream &writegenerators (std::ostream &out, const chain<euclidom> *hom,
01392         const chaincomplex<euclidom> &c,
01393         const gcomplex<cell,euclidom> &g, const int *level = NULL)
01394 {
01395         bool firstlist = true;
01396         for (int d = 0; d <= c. dim (); ++ d)
01397         {
01398                 if ((!level || level [d]) && !hom [d]. empty ())
01399                 {
01400                         if (firstlist)
01401                                 firstlist = false;
01402                         else
01403                                 out << '\n';
01404                         if (hom [d]. size () == 1)
01405                                 out << "The generator of H_" << d <<
01406                                         " follows:" << '\n';
01407                         else
01408                                 out << "The " << hom [d]. size () <<
01409                                         " generators of H_" << d <<
01410                                         " follow:" << '\n';
01411                         const hashedset<cell> &cset = g [d];
01412                         for (int_t i = 0; i < hom [d]. size (); ++ i)
01413                         {
01414                                 if (hom [d]. size () > 1)
01415                                         out << "generator " << (i + 1) <<
01416                                                 '\n';
01417                                 const chain<euclidom> &lst =
01418                                         c. gethomgen (d, hom [d]. num (i));
01419                                 for (int_t j = 0; j < lst. size (); ++ j)
01420                                         out << lst. coef (j) << " * " <<
01421                                                 cset [lst. num (j)] << '\n';
01422                         }
01423                 }
01424         }
01425         return out;
01426 } /* writegenerators */
01427 
01429 template <class cell, class euclidom>
01430 gcomplex<cell,euclidom> &creategraph (const mvmap<cell,cell> &m,
01431         gcomplex<cell,euclidom> &graph)
01432 {
01433         for (int_t i = 0; i < m. size (); ++ i)
01434         {
01435                 const cell &e = m. get (i);
01436                 const hashedset<cell> &f = m (i);
01437                 for (int_t j = 0; j < f. size (); ++ j)
01438                         graph. add (e * f [j]);
01439         }
01440         return graph;
01441 } /* creategraph */
01442 
01447 template <class cell, class euclidom>
01448 bool acyclic (gcomplex<cell,euclidom> &c)
01449 {
01450         // collapse the geometric complex and check if you can get one elem.
01451         gcomplex<cell,euclidom> empty;
01452         c. collapse (empty, empty, true, false, false, NULL, true);
01453         if (c. size () == 1)
01454                 return true;
01455 
01456         // create the corresponding chain complex and compute its homology
01457         chaincomplex<euclidom> cx (c. dim ());
01458         createchaincomplex (cx, c, true);
01459         chain<euclidom> *hom;
01460         cx. simple_form (static_cast<int *> (0), true);
01461         cx. simple_homology (hom, 0);
01462 
01463         // if there is anything above the zero level, the set is not acyclic
01464         for (int i = 1; i <= cx. dim (); ++ i)
01465         {
01466                 if (!hom [i]. empty ())
01467                 {
01468                         delete [] hom;
01469                         return false;
01470                 }
01471         }
01472 
01473         // if there is more than one connected component, it is not acyclic
01474         if (hom [0]. size () != 1)
01475         {
01476                 delete [] hom;
01477                 return false;
01478         }
01479 
01480         // if the coefficient is not 1, the set is not acyclic
01481         if (hom [0]. getcoefficient (0) == 1)
01482         {
01483                 delete [] hom;
01484                 return true;
01485         }
01486         else
01487         {
01488                 delete [] hom;
01489                 return false;
01490         }
01491 } /* acyclic */
01492 
01493 // --------------------------------------------------
01494 
01496 template <class cell, class euclidom>
01497 std::ostream &operator << (std::ostream &out,
01498         const gcomplex<cell,euclidom> &c)
01499 {
01500         out << "; Geometric complex of dimension " << c. dim () <<
01501                 " (" << c. size () << " cells total)." << '\n';
01502         for (int i = 0; i <= c. dim (); ++ i)
01503                 out << "; Cells of dimension " << i << ':' << '\n' << c [i];
01504         return out;
01505 } /* operator << */
01506 
01508 template <class cell, class euclidom>
01509 std::istream &operator >> (std::istream &in, gcomplex<cell,euclidom> &c)
01510 {
01511         ignorecomments (in);
01512         while (closingparenthesis (in. peek ()) != EOF)
01513         {
01514                 cell x;
01515                 in >> x;
01516                 c. add (x);
01517                 ignorecomments (in);
01518         }
01519         return in;
01520 } /* operator >> */
01521 
01522 
01523 // --------------------------------------------------
01524 // ------------------ mv cell map -------------------
01525 // --------------------------------------------------
01526 
01529 template <class cell, class euclidom, class element>
01530 class mvcellmap
01531 {
01532 public:
01536         mvcellmap (gcomplex<cell,euclidom> *_g = 0);
01537 
01541         mvcellmap (gcomplex<cell,euclidom> &_g);
01542 
01544         mvcellmap (const mvcellmap<cell,euclidom,element> &m);
01545 
01547         mvcellmap &operator = (const mvcellmap<cell,euclidom,element> &m);
01548 
01550         ~mvcellmap ();
01551 
01553         int dim () const;
01554 
01556         const hashedset<cell> &get (int d) const;
01557 
01559         const gcomplex<cell,euclidom> &getdomain () const;
01560 
01562         const hashedset<element> &operator () (const cell &c) const;
01563 
01566         void add (int d, const cell &c,
01567                 const hashedset<element> &set);
01568 
01570         void add (const cell &c, const hashedset<element> &set);
01571 
01574         void add (int d, int_t n, const hashedset<element> &set);
01575 
01578         void add (int d, const cell &c, const element &e);
01579 
01581         void add (const cell &c, const element &e);
01582 
01585         void add (int d, int_t n, const element &e);
01586 
01587 private:
01589         gcomplex<cell,euclidom> *g;
01590 
01592         multitable <hashedset<element> > *images;
01593 
01595         int dimension;
01596         
01597 }; /* class mvcellmap */
01598 
01599 // --------------------------------------------------
01600 
01601 template <class cell, class euclidom, class element>
01602 inline mvcellmap<cell,euclidom,element>::mvcellmap
01603         (gcomplex<cell,euclidom> *_g)
01604 {
01605         g = _g;
01606         if (!g || (g -> dim () < 0))
01607         {
01608                 images = NULL;
01609                 dimension = -1;
01610                 return;
01611         }
01612         dimension = g -> dim ();
01613         images = new multitable <hashedset<element> > [dimension + 1];
01614         if (!images)
01615                 throw "Cannot create a multivalued cellular map.";
01616         return;
01617 } /* mvcellmap<cell,euclidom,element>::mvcellmap */
01618 
01619 template <class cell, class euclidom, class element>
01620 inline mvcellmap<cell,euclidom,element>::mvcellmap
01621         (gcomplex<cell,euclidom> &_g)
01622 {
01623         g = &_g;
01624         if (!g || (g -> dim () < 0))
01625         {
01626                 images = NULL;
01627                 dimension = -1;
01628                 return;
01629         }
01630         dimension = g -> dim ();
01631         images = new multitable <hashedset<element> > [dimension + 1];
01632         if (!images)
01633                 throw "Cannot create a multivalued cellular map.";
01634         return;
01635 } /* mvcellmap<cell,euclidom,element>::mvcellmap */
01636 
01637 template <class cell, class euclidom, class element>
01638 mvcellmap<cell,euclidom,element>::mvcellmap
01639         (const mvcellmap<cell,euclidom,element> &m)
01640 {
01641         g = m. g;
01642         if (!g || (g -> dim () < 0))
01643         {
01644                 images = NULL;
01645                 dimension = -1;
01646                 return;
01647         }
01648         dimension = g -> dim ();
01649         images = new multitable <hashedset<element> > [dimension + 1];
01650         if (!images)
01651                 throw "Unable to construct a copy of a multivalued "
01652                         "cellular map.";
01653         for (int i = 0; i < dimension + 1; ++ i)
01654                 images [i] = m. images [i];
01655         return;
01656 } /* mvcellmap<cell,euclidom,element>::mvcellmap */
01657 
01658 template <class cell, class euclidom, class element>
01659 mvcellmap<cell,euclidom,element> &mvcellmap<cell,euclidom,element>::operator =
01660         (const mvcellmap<cell,euclidom,element> &m)
01661 {
01662         if (images)
01663                 delete [] images;
01664         g = m. g;
01665         dimension = m. dimension;
01666         if (!g || (dimension < 0))
01667         {
01668                 images = NULL;
01669                 return *this;
01670         }
01671         images = new multitable <hashedset<element> > [dimension + 1];
01672         if (!images)
01673                 throw "Cannot copy a multivalued cellular map.";
01674         for (int i = 0; i < dimension + 1; ++ i)
01675                 images [i] = m. images [i];
01676         return *this;
01677 } /* mvcellmap<cell,euclidom,element>::operator = */
01678 
01679 template <class cell, class euclidom, class element>
01680 inline mvcellmap<cell,euclidom,element>::~mvcellmap ()
01681 {
01682         if (images)
01683                 delete [] images;
01684         return;
01685 } /* mvcellmap<cell,euclidom,element>::~mvcellmap */
01686 
01687 template <class cell, class euclidom, class element>
01688 int mvcellmap<cell,euclidom,element>::dim () const
01689 {
01690         return dimension;
01691 } /* mvcellmap<cell,euclidom,element>::dim */
01692 
01693 template <class cell, class euclidom, class element>
01694 const hashedset<cell> &mvcellmap<cell,euclidom,element>::get (int d) const
01695 {
01696         if ((d < 0) || (d > dimension))
01697                 throw "Wrong dimension to retrieve from mvcellmap.";
01698         return (*g) [d];
01699 } /* mvcellmap<cell,euclidom,element>::get */
01700 
01701 template <class cell, class euclidom, class element>
01702 const gcomplex<cell,euclidom> &mvcellmap<cell,euclidom,element>::getdomain ()
01703         const
01704 {
01705         return *g;
01706 } /* mvcellmap<cell,euclidom,element>::getdomain */
01707 
01708 template <class cell, class euclidom, class element>
01709 const hashedset<element> &mvcellmap<cell,euclidom,element>::operator ()
01710         (const cell &c) const
01711 {
01712         int d = c. dim ();
01713         if (d > dimension)
01714                 throw "Trying to get the image of a cell of dim too high.";
01715         int_t n = (*g) [d]. getnumber (c);
01716         if (n < 0)
01717                 throw "Trying to get the image of a cell not in the domain.";
01718         return images [d] [n];
01719 } /* mvcellmap<cell,euclidom,element>::operator () */
01720 
01721 template <class cell, class euclidom, class element>
01722 inline void mvcellmap<cell,euclidom,element>::add (int d, const cell &c,
01723         const hashedset<element> &set)
01724 {
01725         if ((d < 0) || (d > dimension))
01726                 throw "Wrong dimension for adding a cell to a map.";
01727         if (!g -> check (c))
01728         //      throw "The cell does not belong to the domain of the map.";
01729                 g -> add (c);
01730         images [d] [(*g) [d]. getnumber (c)]. add (set);
01731         return;
01732 } /* mvcellmap<cell,euclidom,element>::add */
01733 
01734 template <class cell, class euclidom, class element>
01735 inline void mvcellmap<cell,euclidom,element>::add (const cell &c,
01736         const hashedset<element> &set)
01737 {
01738         add (c. dim (), c, set);
01739         return;
01740 } /* mvcellmap<cell,euclidom,element>::add */
01741 
01742 template <class cell, class euclidom, class element>
01743 inline void mvcellmap<cell,euclidom,element>::add (int d, int_t n,
01744         const hashedset<element> &set)
01745 {
01746         if ((d < 0) || (d > dimension))
01747                 throw "Wrong dimension for adding an element to the image.";
01748         images [d] [n]. add (set);
01749         return;
01750 } /* mvcellmap<cell,euclidom,element>::add */
01751 
01752 template <class cell, class euclidom, class element>
01753 inline void mvcellmap<cell,euclidom,element>::add (int d, const cell &c,
01754         const element &e)
01755 {
01756         if ((d < 0) || (d > dimension))
01757                 throw "Wrong dimension for adding a cell to a map.";
01758         if (!g -> check (c))
01759         //      throw "The cell does not belong to the domain of the map.";
01760                 g -> add (c);
01761         images [d] [(*g) [d]. getnumber (c)]. add (e);
01762         return;
01763 } /* mvcellmap<cell,euclidom,element>::add */
01764 
01765 template <class cell, class euclidom, class element>
01766 inline void mvcellmap<cell,euclidom,element>::add (const cell &c,
01767         const element &e)
01768 {
01769         add (c. dim (), c, e);
01770         return;
01771 } /* mvcellmap<cell,euclidom,element>::add */
01772 
01773 template <class cell, class euclidom, class element>
01774 inline void mvcellmap<cell,euclidom,element>::add (int d, int_t n,
01775         const element &set)
01776 {
01777         if ((d < 0) || (d > dimension))
01778                 throw "Wrong dimension for adding an element to the image.";
01779         images [d] [n]. add (set);
01780         return;
01781 } /* mvcellmap<cell,euclidom,element>::add */
01782 
01783 // --------------------------------------------------
01784 
01788 template <class cell, class euclidom, class element>
01789 void creategraph (const mvcellmap<cell,euclidom,element> &m,
01790         gcomplex<cell,euclidom> &c, bool addbd)
01791 {
01792         // go through all the dimensions of the domain cell complex
01793         for (int d1 = 0; d1 <= m. dim (); ++ d1)
01794         {
01795                 // go through all the cells of this dimension
01796                 const hashedset<cell> &cset = m. get (d1);
01797                 for (int_t i = 0; i < cset. size (); ++ i)
01798                 {
01799                         // create a cell complex of the image of this cell
01800                         const cell &thecell = cset [i];
01801                         const hashedset<element> &set = m (thecell);
01802                         gcomplex<cell,euclidom> img;
01803                         for (int_t j = 0; j < set. size (); ++ j)
01804                                 img. add (cell (set [j]));
01805                         if (addbd)
01806                                 img. addboundaries ();
01807 
01808                         // go through all the dimensions of this cell complex
01809                         for (int d2 = 0; d2 <= img. dim (); ++ d2)
01810                         {
01811                                 // add all the products to the graph
01812                                 const hashedset<cell> &cs = img [d2];
01813                                 for (int_t j = 0; j < cs. size (); ++ j)
01814                                         c. add (thecell * cs [j]);
01815                         }
01816                 }
01817                 if (d1 < m. dim ())
01818                         scon << '.';
01819                 else
01820                         scon << ' ';
01821         }
01822         return;
01823 } /* creategraph */
01824 
01828 template <class cell, class euclidom, class element>
01829 void creategraph (const mvcellmap<cell,euclidom,element> &m,
01830         const gcomplex<cell,euclidom> &rel,
01831         gcomplex<cell,euclidom> &c, bool addbd)
01832 {
01833         // go through all the dimensions of the domain cell complex
01834         for (int d1 = 0; d1 <= m. dim (); ++ d1)
01835         {
01836                 // go through all the cells of this dimension
01837                 const hashedset<cell> &cset = m. get (d1);
01838                 for (int_t i = 0; i < cset. size (); ++ i)
01839                 {
01840                         // create a cell complex of the image of this cell
01841                         const cell &thecell = cset [i];
01842                         const hashedset<element> &set = m (thecell);
01843                         gcomplex<cell,euclidom> img;
01844                         for (int_t j = 0; j < set. size (); ++ j)
01845                                 img. add (cell (set [j]));
01846                         if (addbd)
01847                                 img. addboundaries ();
01848 
01849                         // go through all the dimensions of this cell complex
01850                         for (int d2 = 0; d2 <= img. dim (); ++ d2)
01851                         {
01852                                 // add all the products to the graph
01853                                 const hashedset<cell> &cs = img [d2];
01854                                 for (int_t j = 0; j < cs. size (); ++ j)
01855                                 {
01856                                         cell bigcell = thecell * cs [j];
01857                                         if (!rel. check (bigcell))
01858                                                 c. add (bigcell);
01859                                 }
01860                         }
01861                 }
01862                 if (d1 < m. dim ())
01863                         scon << '.';
01864                 else
01865                         scon << ' ';
01866         }
01867         return;
01868 } /* creategraph */
01869 
01874 template <class cell, class euclidom, class element>
01875 void createcellmap (const mvcellmap<cell,euclidom,element> &m,
01876         mvcellmap<cell,euclidom,cell> &cm)
01877 {
01878         // go through all the dimensions of the domain cell complex
01879         int spacedim = -1;
01880         const gcomplex<cell,euclidom> &dom = m. getdomain ();
01881         for (int d = m. dim (); d >= 0; -- d)
01882         {
01883                 // go through all the cells of this dimension
01884                 const hashedset<cell> &cset = m. get (d);
01885                 for (int_t i = 0; i < cset. size (); ++ i)
01886                 {
01887                         // extract the cell of interest and its image
01888                         const cell &thecell = cset [i];
01889                         const hashedset<element> &set = m (thecell);
01890 
01891                         // the image must not be empty!
01892                         if (set. empty ())
01893                                 throw "An empty image of a cell found.";
01894 
01895                         // correct the dimension of the space if necessary
01896                         if (spacedim < 0)
01897                                 spacedim = set [0]. dim ();
01898 
01899                         // if this is maximal dimension, extract one point
01900                         if (d == spacedim)
01901                         {
01902                         //      cm. add (d, thecell, cell (set [0]. coord (),
01903                         //              set [0]. coord (), spacedim));
01904                                 cm. add (d, thecell, cell (set [0], 0));
01905                                 continue;
01906                         }
01907 
01908                         // create a cell complex of the image of this cell
01909                         gcomplex<cell,euclidom> img;
01910                         for (int_t j = 0; j < set. size (); ++ j)
01911                                 img. add (cell (set [j]));
01912 
01913                         // create a cell complex to keep while collapsing
01914                         gcomplex<cell,euclidom> keep;
01915                         const hashedset<cell> &cob =
01916                                 dom. getcob (thecell, d);
01917                         for (int_t j = 0; j < cob. size (); ++ j)
01918                                 keep. add (cm (cob [j]));
01919 
01920                         // reduce 'img' towards 'keep'
01921                         gcomplex<cell,euclidom> empty;
01922                         img. collapse (empty, keep, 1, 0, 0, NULL, 1);
01923 
01924                         // set this to be the image of this cell
01925                         // *** THIS MUST BE IMPROVED ***
01926                         for (int j = 0; j <= img. dim (); ++ j)
01927                                 cm. add (d, thecell, img [j]);
01928 
01929                         // show progress indicator
01930                         if (i && !(i % 373))
01931                                 scon << std::setw (12) << i <<
01932                                         "\b\b\b\b\b\b\b\b\b\b\b\b";
01933                 }
01934                 if (cset. size () > 373)
01935                         scon << "            \b\b\b\b\b\b\b\b\b\b\b\b";
01936                 scon << '.';
01937         }
01938         scon << ' ';
01939         return;
01940 } /* createcellmap */
01941 
01948 template <class cell, class euclidom, class element>
01949 bool createcellmap (const mvcellmap<cell,euclidom,element> &m,
01950         const mvcellmap<cell,euclidom,element> &rel,
01951         mvcellmap<cell,euclidom,cell> &cm, bool verifyacyclicity)
01952 {
01953         // prepare the default result
01954         bool result = true;
01955 
01956         // go through all the dimensions of the domain cell complex
01957         const gcomplex<cell,euclidom> &dom = m. getdomain ();
01958         const gcomplex<cell,euclidom> &reldom = rel. getdomain ();
01959 
01960         int maxdim = m. dim ();
01961         for (int d = maxdim; d >= 0; -- d)
01962         {
01963                 // go through all the cells of this dimension
01964                 const hashedset<cell> &cset = m. get (d);
01965                 for (int_t i = 0; i < cset. size (); ++ i)
01966                 {
01967                         // extract the cell of interest and its image
01968                         const cell &thecell = cset [i];
01969                         const hashedset<element> &set = m (thecell);
01970 
01971                         // the image must not be empty!
01972                         if (set. empty ())
01973                                 throw "An empty image of a cell found.";
01974 
01975                         // if this is maximal dimension, extract one point
01976                         if (d == maxdim)
01977                         {
01978                                 if (reldom. check (thecell))
01979                                         continue;
01980                                 //      throw "This cell shouldn't be here.";
01981                         //      cm. add (d, thecell, cell (set [0]. coord (),
01982                         //              set [0]. coord (), set [0]. dim ()));
01983                                 cm. add (d, thecell, cell (set [0], 0));
01984                                 continue;
01985                         }
01986 
01987                         // create a cell complex of the image of this cell
01988                         gcomplex<cell,euclidom> img;
01989                         for (int_t j = 0; j < set. size (); ++ j)
01990                                 img. add (cell (set [j]));
01991 
01992                         // create a cell complex to keep while collapsing
01993                         gcomplex<cell,euclidom> keep;
01994                         const hashedset<cell> &cob =
01995                                 dom. getcob (thecell, d);
01996 
01997                         for (int_t j = 0; j < cob. size (); ++ j)
01998                                 keep. add (cm (cob [j]));
01999 
02000                         // create a cell complex from 'rel'
02001                         gcomplex<cell,euclidom> other;
02002                         if (reldom. check (thecell))
02003                         {
02004                                 const hashedset<element> &relset =
02005                                         rel (thecell);
02006                                 for (int_t j = 0; j < relset. size (); ++ j)
02007                                 {
02008                                         cell c = cell (relset [j]);
02009                                         keep. add (c);
02010                                         other. add (c);
02011                                 //      img. remove (c);
02012                                 }
02013                         }
02014 
02015                         // reduce 'img' towards 'keep'
02016                         gcomplex<cell,euclidom> empty;
02017                         img. collapse (empty, keep, 1, 0, 0, NULL, 1);
02018 
02019                         // verify the acyclicity of this image if requested
02020                         if (verifyacyclicity)
02021                         {
02022                                 gcomplex<cell,euclidom> imgdupl (img);
02023                                 if (!acyclic (imgdupl))
02024                                 {
02025                                         result = false;
02026                                         verifyacyclicity = false;
02027                                 }
02028                         }
02029 
02030                         // remove the other cells and their faces from img
02031                         other. addboundaries ();
02032                         img. remove (other);
02033 
02034                         // verify the acyclicity of the other complex
02035                         if (verifyacyclicity && other. size ())
02036                         {
02037                                 // note: acycl. check destroys 'other'
02038                                 if (!acyclic (other))
02039                                 {
02040                                         result = false;
02041                                         verifyacyclicity = false;
02042                                 }
02043                         }
02044 
02045                         // set this to be the image of this cell
02046                         // *** THIS MUST BE IMPROVED ***
02047                         for (int j = 0; j <= img. dim (); ++ j)
02048                                 cm. add (d, thecell, img [j]);
02049 
02050                         // show progress indicator
02051                         if (i && !(i % 373))
02052                                 scon << std::setw (12) << i <<
02053                                         "\b\b\b\b\b\b\b\b\b\b\b\b";
02054                 }
02055                 if (cset. size () > 373)
02056                         scon << "            \b\b\b\b\b\b\b\b\b\b\b\b";
02057                 scon << '.';
02058         }
02059         scon << ' ';
02060         return result;
02061 } /* createcellmap */
02062 
02063 // --------------------------------------------------
02064 
02066 template <class cell, class euclidom, class element>
02067 std::ostream &operator << (std::ostream &out,
02068         const mvcellmap<cell,euclidom,element> &m)
02069 {
02070         for (int d = 0; d <= m. dim (); ++ d)
02071         {
02072                 out << "; Dimension " << d << ':' << '\n';
02073                 const hashedset<cell> &cset = m. get (d);
02074                 for (int_t i = 0; i < cset. size (); ++ i)
02075                 {
02076                         out << cset [i] << " -> ";
02077                         write (out, m (cset [i]), SMALL_SIZE) << '\n';
02078                 }
02079         }
02080         return out;
02081 } /* operator << */
02082 
02083 
02084 } // namespace homology
02085 } // namespace chomp
02086 
02087 #endif // _CHOMP_HOMOLOGY_GCOMPLEX_H_
02088 
02090