chains.h

Go to the documentation of this file.
00001 
00002 
00003 
00023 
00024 // Copyright (C) 1997-2010 by Pawel Pilarczyk.
00025 //
00026 // This file is part of the Homology Library.  This library is free software;
00027 // you can redistribute it and/or modify it under the terms of the GNU
00028 // General Public License as published by the Free Software Foundation;
00029 // either version 2 of the License, or (at your option) any later version.
00030 //
00031 // This library is distributed in the hope that it will be useful,
00032 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00033 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00034 // GNU General Public License for more details.
00035 //
00036 // You should have received a copy of the GNU General Public License along
00037 // with this software; see the file "license.txt".  If not, write to the
00038 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00039 // MA 02111-1307, USA.
00040 
00041 // Started in 1997. Last revision: June 25, 2007.
00042 
00043 
00044 #ifndef _CHOMP_HOMOLOGY_CHAINS_H_
00045 #define _CHOMP_HOMOLOGY_CHAINS_H_
00046 
00047 #include "chomp/system/config.h"
00048 #include "chomp/system/textfile.h"
00049 
00050 #include <iostream>
00051 #include <fstream>
00052 #include <cstdlib>
00053 #include <iomanip>
00054 
00055 namespace chomp {
00056 namespace homology {
00057 
00058 
00059 // templates defined within this file (in this order):
00060 
00061 // a chain, that is, a linear combination of generators
00062 template <class euclidom>
00063 class chain;
00064 // a set of matrices
00065 template <class euclidom>
00066 class matrices;
00067 // a sparse matrix whose entries are the given coefficients
00068 template <class euclidom>
00069 class mmatrix;
00070 // a chain complex over a given Euclidean domain
00071 template <class euclidom>
00072 class chaincomplex;
00073 // a chain homomorphism between two chain complexes
00074 template <class euclidom>
00075 class chainmap;
00076 
00077 // templates of functions which display the homology to the output streams
00078 template <class euclidom>
00079 outputstream &show_homology (outputstream &out, const chain<euclidom> &c);
00080 template <class euclidom>
00081 std::ostream &show_homology (std::ostream &out, const chain<euclidom> &c);
00082 
00083 
00084 // --------------------------------------------------
00085 // --------------------- chains ---------------------
00086 // --------------------------------------------------
00087 
00088 // define the number of chain elements that are kept in the chain itself;
00089 // use 1 for better memory usage (?), use more for less memory allocation;
00090 // set to 0 to switch the 'smart' pointer space usage off
00091 #define CHAINFIXED 0
00092 
00093 #ifndef CHAINFIXED
00094 #define CHAINFIXED 1
00095 #endif
00096 
00100 template <class euclidom>
00101 class chain
00102 {
00103 public:
00105         chain ();
00106 
00108         chain (const chain<euclidom> &c);
00109 
00111         chain<euclidom> &operator = (const chain<euclidom> &c);
00112 
00114         ~chain ();
00115 
00118         int size () const;
00119 
00121         bool empty () const;
00122 
00126         euclidom getcoefficient (int n = -1) const;
00127 
00130         int findnumber (int n) const;
00131 
00134         euclidom coef (int i) const;
00135 
00137         int num (int i) const;
00138 
00141         bool contains_non_invertible () const;
00142 
00149         int findbest (chain<euclidom> *table = NULL) const;
00150 
00152         chain<euclidom> &add (int n, euclidom e);
00153 
00155         chain<euclidom> &remove (int n);
00156 
00161         chain<euclidom> &add (const chain<euclidom> &other,
00162                 euclidom e, int number = -1,
00163                 chain<euclidom> *table = NULL);
00164 
00169         chain<euclidom> &swap (chain<euclidom> &other,
00170                 int number = -1, int othernumber = -1,
00171                 chain<euclidom> *table = NULL);
00172 
00174         chain<euclidom> &take (chain<euclidom> &c);
00175 
00178         chain<euclidom> &multiply (euclidom e, int number = -1);
00179 
00182         outputstream &show (outputstream &out,
00183                 const char *label = NULL) const;
00184 
00187         std::ostream &show (std::ostream &out, const char *label = NULL) const;
00188 
00189 private:
00191         int len;
00192 
00197         union
00198         {
00199                 struct
00200                 {
00201                         int *n;
00202                         euclidom *e;
00203                 } t;
00204                 struct
00205                 {
00206                         #if CHAINFIXED
00207                         int n [CHAINFIXED];
00208                         euclidom e [CHAINFIXED];
00209                         #else
00210                         int *n;
00211                         euclidom *e;
00212                         #endif
00213                 } x;
00214         };
00215 
00217         chain<euclidom> &insertpair (int i, int n, euclidom e);
00218 
00220         chain<euclidom> &removepair (int i);
00221 
00223         chain<euclidom> &swapnumbers (int number1, int number2);
00224 
00228         bool allocated () const;
00229 
00230 }; /* class chain */
00231 
00232 // --------------------------------------------------
00233 
00234 template <class euclidom>
00235 inline bool chain<euclidom>::allocated () const
00236 {
00237         if (len <= static_cast<int> (CHAINFIXED))
00238                 return false;
00239 //      return (sizeof (int *) < ((sizeof (int) < sizeof (euclidom)) ?
00240 //              sizeof (euclidom) : sizeof (int)) * len);
00241         else
00242                 return true;
00243 } /* chain<euclidom>::allocated */
00244 
00245 template <class euclidom>
00246 inline chain<euclidom>::chain ()
00247 {
00248         len = 0;
00249         return;
00250 } /* chain<euclidom>::chain */
00251 
00252 template <class euclidom>
00253 inline chain<euclidom>::chain (const chain<euclidom> &c)
00254 {
00255         // copy the length of the chain
00256         len = c. len;
00257 
00258         // allocate new tables if necessary and copy the data
00259         if (allocated ())
00260         {
00261                 t. n = new int [len];
00262                 t. e = new euclidom [len];
00263                 if (!t. n || !t. e)
00264                         throw "Not enough memory to create a chain copy.";
00265                 for (int i = 0; i < len; ++ i)
00266                 {
00267                         t. n [i] = c. t. n [i];
00268                         t. e [i] = c. t. e [i];
00269                 }
00270         }
00271         else
00272         {
00273                 for (int i = 0; i < len; ++ i)
00274                 {
00275                         x. n [i] = c. x. n [i];
00276                         x. e [i] = c. x. e [i];
00277                 }
00278         }
00279         return;
00280 } /* chain<euclidom>::chain */
00281 
00282 template <class euclidom>
00283 inline chain<euclidom> &chain<euclidom>::operator =
00284         (const chain<euclidom> &c)
00285 {
00286         // first release allocated tables if any
00287         if (allocated ())
00288         {
00289                 delete [] t. n;
00290                 delete [] t. e;
00291         }
00292 
00293         // copy the length of the chain
00294         len = c. len;
00295 
00296         // allocate new tables if necessary and copy the data
00297         if (allocated ())
00298         {
00299                 t. n = new int [len];
00300                 t. e = new euclidom [len];
00301                 if (!t. n || !t. e)
00302                         throw "Not enough memory to create a chain copy =.";
00303                 for (int i = 0; i < len; ++ i)
00304                 {
00305                         t. n [i] = c. t. n [i];
00306                         t. e [i] = c. t. e [i];
00307                 }
00308         }
00309         else
00310         {
00311                 for (int i = 0; i < len; ++ i)
00312                 {
00313                         x. n [i] = c. x. n [i];
00314                         x. e [i] = c. x. e [i];
00315                 }
00316         }
00317         return *this;
00318 } /* chain<euclidom>::operator = */
00319 
00320 template <class euclidom>
00321 inline chain<euclidom>::~chain ()
00322 {
00323         if (allocated ())
00324         {
00325                 delete [] t. n;
00326                 delete [] t. e;
00327         }
00328         return;
00329 } /* chain<euclidom>::~chain */
00330 
00331 template <class euclidom>
00332 inline int chain<euclidom>::size () const
00333 {
00334         return len;
00335 } /* chain<euclidom>::size */
00336 
00337 template <class euclidom>
00338 inline bool chain<euclidom>::empty () const
00339 {
00340         return !len;
00341 } /* chain<euclidom>::empty */
00342 
00343 template <class euclidom>
00344 /*inline*/ euclidom chain<euclidom>::getcoefficient (int n) const
00345 {
00346         bool a = allocated ();
00347         const euclidom *tetab = a ? t. e : x. e;
00348         if (n < 0)
00349         {
00350                 if (len > 0)
00351                         return tetab [0];
00352                 else
00353                 {
00354                         euclidom zero;
00355                         zero = 0;
00356                         return zero;
00357                 }
00358         }
00359 
00360         const int *tntab = a ? t. n : x. n;
00361         int i = 0;
00362         while ((i < len) && (tntab [i] < n))
00363                 ++ i;
00364         if ((i >= len) || (tntab [i] != n))
00365         {
00366                 euclidom zero;
00367                 zero = 0;
00368                 return zero;
00369         }
00370         return tetab [i];
00371 } /* chain<euclidom>::getcoefficient */
00372 
00373 template <class euclidom>
00374 inline int chain<euclidom>::findnumber (int n) const
00375 {
00376         bool a = allocated ();
00377         const int *tntab = a ? t. n : x. n;
00378         for (int i = 0; i < len; ++ i)
00379         {
00380                 if (tntab [i] == n)
00381                         return i;
00382                 else if (tntab [i] > n)
00383                         return -1;
00384         }
00385         return -1;
00386 } /* chain<euclidom>::findnumber */
00387 
00388 template <class euclidom>
00389 inline euclidom chain<euclidom>::coef (int i) const
00390 {
00391         if (i >= len)
00392                 throw "Wrong coefficient requested from a chain.";
00393         return (allocated () ? t. e : x. e) [i];
00394 } /* chain<euclidom>::coef */
00395 
00396 template <class euclidom>
00397 inline int chain<euclidom>::num (int i) const
00398 {
00399         if (i >= len)
00400                 throw "Wrong number requested from a chain.";
00401         return (allocated () ? t. n : x. n) [i];
00402 } /* chain<euclidom>::num */
00403 
00404 template <class euclidom>
00405 inline bool chain<euclidom>::contains_non_invertible () const
00406 {
00407         if (allocated ())
00408         {
00409                 for (int i = 0; i < len; ++ i)
00410                 {
00411                         if (t. e [i]. delta () > 1)
00412                                 return true;
00413                 }
00414         }
00415         else
00416         {
00417                 for (int i = 0; i < len; ++ i)
00418                 {
00419                         if (x. e [i]. delta () > 1)
00420                                 return true;
00421                 }
00422         }
00423         return false;
00424 } /* chain<euclidom>::contains_non_invertible */
00425 
00426 template <class euclidom>
00427 inline int chain<euclidom>::findbest (chain<euclidom> *table) const
00428 {
00429         // if the chain is so short that the answer is obvious, return it
00430         if (len <= 1)
00431                 return (len - 1);
00432 
00433         // find the number which has the smallest delta function value
00434         int this_delta, best_delta = -1;
00435         int best_i = 0;
00436 
00437         // go through the whole table
00438         bool a = allocated ();
00439         const int *tntab = a ? t. n : x. n;
00440         const euclidom *tetab = a ? t. e : x. e;
00441         int i;
00442         for (i = 0; i < len; ++ i)
00443         {
00444                 // compute the value of the function delta
00445                 this_delta = tetab [i]. delta ();
00446 
00447                 // if the value is the smallest possible
00448                 // and no further analysis was required, finish here
00449                 if (!table && (this_delta == 1))
00450                         return i;
00451 
00452                 // if this delta is better, remember it
00453                 if (!i || (this_delta < best_delta))
00454                 {
00455                         best_delta = this_delta;
00456                         best_i = i;
00457                 }
00458         }
00459 
00460         // if no further analysis is required, return the result just now
00461         if (!table)
00462                 return best_i;
00463 
00464         // analyse which element has the shortest corresponding chain
00465         int this_length, best_length =
00466                 table [tntab [best_i]]. size ();
00467         for (i = best_i + 1; i < len; ++ i)
00468         {
00469                 if (tetab [i]. delta () == best_delta)
00470                 {
00471                         this_length =
00472                                 table [tntab [i]]. size ();
00473                         if (best_length > this_length)
00474                         {
00475                                 best_length = this_length;
00476                                 best_i = i;
00477                         }
00478                 }
00479         }
00480 
00481         return best_i;
00482 } /* chain<euclidom>::findbest */
00483 
00484 // --------------------------------------------------
00485 
00486 template <class euclidom>
00487 inline chain<euclidom> &chain<euclidom>::insertpair
00488         (int i, int n, euclidom e)
00489 {
00490         // remember if the table was previously allocated or not
00491         bool a = allocated ();
00492 
00493         // increase the length
00494         ++ len;
00495 
00496         // determine if the new table should be allocated or not
00497         bool na = allocated ();
00498 
00499         // if a new table has to be allocated, do it
00500         if (na)
00501         {
00502                 // allocate a new table
00503                 int *newntab = new int [len];
00504                 euclidom *newetab = new euclidom [len];
00505                 if (!newntab || !newetab)
00506                         throw "Cannot add an element to a chain.";
00507 
00508                 // determine the addresses of the old tables
00509                 int *oldntab = a ? t. n : x. n;
00510                 euclidom *oldetab = a ? t. e : x. e;
00511 
00512                 // copy the old data and insert the new pair
00513                 int j;
00514                 for (j = 0; j < i; ++ j)
00515                 {
00516                         newntab [j] = oldntab [j];
00517                         newetab [j] = oldetab [j];
00518                 }
00519                 newntab [i] = n;
00520                 newetab [i] = e;
00521                 for (j = i + 1; j < len; ++ j)
00522                 {
00523                         newntab [j] = oldntab [j - 1];
00524                         newetab [j] = oldetab [j - 1];
00525                 }
00526 
00527                 // release the previous tables if they were allocated
00528                 if (a)
00529                 {
00530                         delete [] t. n;
00531                         delete [] t. e;
00532                 }
00533 
00534                 // take the new tables to the data structure
00535                 t. n = newntab;
00536                 t. e = newetab;
00537         }
00538 
00539         // otherwise just insert the new element at the appropriate position
00540         else // if (!na && !a)
00541         {
00542                 for (int j = len - 1; j > i; -- j)
00543                 {
00544                         x. n [j] = x. n [j - 1];
00545                         x. e [j] = x. e [j - 1];
00546                 }
00547                 x. n [i] = n;
00548                 x. e [i] = e;
00549         }
00550 
00551         return *this;
00552 } /* chain<euclidom>::insertpair */
00553 
00554 template <class euclidom>
00555 inline chain<euclidom> &chain<euclidom>::removepair (int i)
00556 {
00557         // remember if the table was previously allocated or not
00558         bool a = allocated ();
00559 
00560         // decrease the length
00561         if (len)
00562                 -- len;
00563 
00564         // determine if the new table should be allocated or not
00565         bool na = allocated ();
00566 
00567         // allocate the new tables if necessary
00568         if (na)
00569         {
00570                 int *newntab = new int [len];
00571                 euclidom *newetab = new euclidom [len];
00572                 if (!newntab || !newetab)
00573                         throw "Cannot remove a pair from a chain.";
00574 
00575                 // copy the data form the previous tables
00576                 int j;
00577                 for (j = 0; j < i; ++ j)
00578                 {
00579                         newntab [j] = t. n [j];
00580                         newetab [j] = t. e [j];
00581                 }
00582                 for (j = i; j < len; ++ j)
00583                 {
00584                         newntab [j] = t. n [j + 1];
00585                         newetab [j] = t. e [j + 1];
00586                 }
00587                 delete [] t. n;
00588                 delete [] t. e;
00589                 t. n = newntab;
00590                 t. e = newetab;
00591         }
00592 
00593         // otherwise, copy the data from the previous tables
00594         else
00595         {
00596                 int *oldntab = a ? t. n : x. n;
00597                 euclidom *oldetab = a ? t. e : x. e;
00598 
00599                 // copy the data form the previous tables
00600                 int j;
00601                 for (j = 0; a && (j < i); ++ j)
00602                 {
00603                         x. n [j] = oldntab [j];
00604                         x. e [j] = oldetab [j];
00605                 }
00606                 for (j = i; j < len; ++ j)
00607                 {
00608                         x. n [j] = oldntab [j + 1];
00609                         x. e [j] = oldetab [j + 1];
00610                 }
00611 
00612                 // release the old tables if necessary
00613                 if (a)
00614                 {
00615                         delete [] oldntab;
00616                         delete [] oldetab;
00617                 }
00618         }
00619 
00620         return *this;
00621 } /* chain<euclidom>::removepair */
00622 
00623 template <class euclidom>
00624 inline chain<euclidom> &chain<euclidom>::swapnumbers (int number1,
00625         int number2)
00626 {
00627         // if the numbers are the same, do nothing
00628         if (number1 == number2)
00629                 return *this;
00630 
00631         // force the first number be less than the second number
00632         if (number1 > number2)
00633         {
00634                 int tempnumber = number1;
00635                 number1 = number2;
00636                 number2 = tempnumber;
00637         }
00638 
00639         // determine the true tables to be processed
00640         bool a = allocated ();
00641         int *tntab = a ? t. n : x. n;
00642         euclidom *tetab = a ? t. e : x. e;
00643 
00644         // find both numbers or the positions they should be at
00645         int i1 = 0, i2 = 0;
00646         while ((i1 < len) && (tntab [i1] < number1))
00647                 ++ i1;
00648         while ((i2 < len) && (tntab [i2] < number2))
00649                 ++ i2;
00650 
00651         // if the first number was found...
00652         if ((i1 < len) && (tntab [i1] == number1))
00653         {
00654                 // if both numbers were found, exchange their coefficients
00655                 if ((i2 < len) && (tntab [i2] == number2))
00656                         swapelements (tetab [i1], tetab [i2]);
00657                 // if only the first was found, move it to the new position
00658                 else
00659                 {
00660                         euclidom temp = tetab [i1];
00661                         for (int i = i1 + 1; i < i2; ++ i)
00662                         {
00663                                 tntab [i - 1] = tntab [i];
00664                                 tetab [i - 1] = tetab [i];
00665                         }
00666                         tntab [i2 - 1] = number2;
00667                         tetab [i2 - 1] = temp;
00668                 }
00669         }
00670 
00671         // otherwise if the second number only was found, move it to its pos.
00672         else if ((i2 < len) && (tntab [i2] == number2))
00673         {
00674                 euclidom temp = tetab [i2];
00675                 for (int i = i2; i > i1; -- i)
00676                 {
00677                         tntab [i] = tntab [i - 1];
00678                         tetab [i] = tetab [i - 1];
00679                 }
00680                 tntab [i1] = number1;
00681                 tetab [i1] = temp;
00682         }
00683 
00684         return *this;
00685 } /* chain<euclidom>::swapnumbers */
00686 
00687 // --------------------------------------------------
00688 
00689 template <class euclidom>
00690 inline chain<euclidom> &chain<euclidom>::add (int n, euclidom e)
00691 {
00692         // if the coefficient is zero, ignore the pair
00693         if (e == 0)
00694                 return *this;
00695         bool a = allocated ();
00696         int *tntab = a ? t. n : x. n;
00697         euclidom *tetab = a ? t. e : x. e;
00698 
00699         // find the position in the table for adding this pair
00700         int i = 0;
00701         while ((i < len) && (tntab [i] < n))
00702                 ++ i;
00703 
00704         // if an element with this identifier was found, add the coefficients
00705         if ((i < len) && (tntab [i] == n))
00706         {
00707                 // add the coefficient
00708                 tetab [i] += e;
00709 
00710                 // if the coefficient became zero, remove this pair
00711                 if (tetab [i] == 0)
00712                         return removepair (i);
00713 
00714                 // otherwise we are done
00715                 else
00716                         return *this;
00717         }
00718 
00719         // otherwise insert this pair into the chain
00720         return insertpair (i, n, e);
00721 
00722 } /* chain<euclidom>::add */
00723 
00724 template <class euclidom>
00725 chain<euclidom> &chain<euclidom>::remove (int n)
00726 {
00727         bool a = allocated ();
00728         int *tntab = a ? t. n : x. n;
00729 
00730         // find the element of the chain to be removed
00731         int i = 0;
00732         while ((i < len) && (tntab [i] < n))
00733                 ++ i;
00734 
00735         // if found, then remove it
00736         if ((i < len) && (tntab [i] == n))
00737                 return removepair (i);
00738 
00739         return *this;
00740 } /* chain<euclidom>::remove */
00741 
00742 template <class euclidom>
00743 inline chain<euclidom> &chain<euclidom>::add (const chain<euclidom> &other,
00744         euclidom e, int number, chain<euclidom> *table)
00745 {
00746         // if the coefficient is zero or the other chain is zero,
00747         // then there is nothing to do
00748         if ((e == 0) || !other. len)
00749                 return *this;
00750 
00751         // prepare big tables for the new chain
00752         int tablen = len + other. len;
00753         int *bigntab = new int [tablen];
00754         euclidom *bigetab = new euclidom [tablen];
00755         if (!bigntab || !bigetab)
00756                 throw "Not enough memory to add chains.";
00757 
00758         // prepare the counters of elements of the two input chains
00759         // and of the output chain
00760         int i = 0, j = 0, k = 0;
00761 
00762         // determine the actual tables to be processed
00763         bool a = allocated ();
00764         bool oa = other. allocated ();
00765         const int *tntab = a ? t. n : x. n;
00766         const euclidom *tetab = a ? t. e : x. e;
00767         const int *ontab = oa ? other. t. n : other. x. n;
00768         const euclidom *oetab = oa ? other. t. e : other. x. e;
00769 
00770         // go through both input chains and compute the output chain
00771         while ((i < len) || (j < other. len))
00772         {
00773                 if (i >= len)
00774                 {
00775                         bigntab [k] = ontab [j];
00776                         bigetab [k] = e * oetab [j ++];
00777                         if (table)
00778                         {
00779                                 table [bigntab [k]]. add (number,
00780                                         bigetab [k]);
00781                         }
00782                         ++ k;
00783                 }
00784                 else if ((j >= other. len) || (tntab [i] < ontab [j]))
00785                 {
00786                         bigntab [k] = tntab [i];
00787                         bigetab [k ++] = tetab [i ++];
00788                 }
00789                 else if (tntab [i] > ontab [j])
00790                 {
00791                         bigntab [k] = ontab [j];
00792                         bigetab [k] = e * oetab [j ++];
00793                         if (table)
00794                         {
00795                                 table [bigntab [k]]. add (number,
00796                                         bigetab [k]);
00797                         }
00798                         ++ k;
00799                 }
00800                 else // if (tntab [i] == ontab [j])
00801                 {
00802                         bigntab [k] = tntab [i];
00803                         euclidom addelem = e * oetab [j ++];
00804                         bigetab [k] = tetab [i ++] + addelem;
00805                         euclidom zero;
00806                         zero = 0;
00807                         if (bigetab [k] != zero)
00808                         {
00809                                 if (table)
00810                                 {
00811                                         table [bigntab [k]]. add (number,
00812                                                 addelem);
00813                                 }
00814                                 ++ k;
00815                         }
00816                         else if (table)
00817                         {
00818                                 table [bigntab [k]]. remove (number);
00819                         }
00820                 }
00821         }
00822 
00823         // release the old tables if they are useless now
00824         if (a && ((k != len) || (k == tablen)))
00825         {
00826                 delete [] t. n;
00827                 delete [] t. e;
00828         }
00829 
00830         // use the previous tables and release the big table if beneficial
00831         if (a && (k == len) && (k != tablen))
00832         {
00833                 for (int i = 0; i < len; ++ i)
00834                 {
00835                         t. n [i] = bigntab [i];
00836                         t. e [i] = bigetab [i];
00837                 }
00838                 delete [] bigntab;
00839                 delete [] bigetab;
00840                 return *this;
00841         }
00842 
00843         len = k;
00844 
00845         // if the new tables don't have to be allocated, only copy the data
00846         if (!allocated ())
00847         {
00848                 for (int i = 0; i < len; ++ i)
00849                 {
00850                         x. n [i] = bigntab [i];
00851                         x. e [i] = bigetab [i];
00852                 }
00853                 delete [] bigntab;
00854                 delete [] bigetab;
00855                 return *this;
00856         }
00857 
00858         // if the big tables cannot be used, allocate new tables
00859         if (len != tablen)
00860         {
00861                 t. n = new int [len];
00862                 t. e = new euclidom [len];
00863                 if (!t. n || !t. e)
00864                         throw "Cannot shorten a sum of chains.";
00865                 for (int i = 0; i < len; ++ i)
00866                 {
00867                         t. n [i] = bigntab [i];
00868                         t. e [i] = bigetab [i];
00869                 }
00870                 delete [] bigntab;
00871                 delete [] bigetab;
00872         }
00873 
00874         // otherwise, simply use the big tables
00875         else
00876         {
00877                 t. n = bigntab;
00878                 t. e = bigetab;
00879         }
00880 
00881         return *this;
00882 } /* chain<euclidom>::add */
00883 
00884 template <class euclidom>
00885 inline chain<euclidom> &chain<euclidom>::swap (chain<euclidom> &other,
00886         int number, int othernumber, chain<euclidom> *table)
00887 {
00888         // check which chains where allocated
00889         bool a = allocated ();
00890         bool oa = other. allocated ();
00891 
00892         // swap the data of the chains
00893         if (a && oa)
00894         {
00895                 swapelements (t. n, other. t. n);
00896                 swapelements (t. e, other. t. e);
00897         }
00898         else if (!a && !oa)
00899         {
00900                 // common variable for interations (required by MSVC++)
00901                 int i;
00902 
00903                 // swap the data in the common area of both chains
00904                 for (i = 0; (i < len) && (i < other. len); ++ i)
00905                 {
00906                         swapelements (x. n [i], other. x. n [i]);
00907                         swapelements (x. e [i], other. x. e [i]);
00908                 }
00909 
00910                 // copy the remaining portion of the data
00911                 for (i = len; i < other. len; ++ i)
00912                 {
00913                         x. n [i] = other. x. n [i];
00914                         x. e [i] = other. x. e [i];
00915                 }
00916                 for (i = other. len; i < len; ++ i)
00917                 {
00918                         other. x. n [i] = x. n [i];
00919                         other. x. e [i] = x. e [i];
00920                 }
00921         }
00922         else if (a) // && !oa
00923         {
00924                 int *tempn = t. n;
00925                 euclidom *tempe = t. e;
00926                 for (int i = 0; i < other. len; ++ i)
00927                 {
00928                         x. n [i] = other. x. n [i];
00929                         x. e [i] = other. x. e [i];
00930                 }
00931                 other. t. n = tempn;
00932                 other. t. e = tempe;
00933         }
00934         else // if (oa) // && !a
00935         {
00936                 int *tempn = other. t. n;
00937                 euclidom *tempe = other. t. e;
00938                 for (int i = 0; i < len; ++ i)
00939                 {
00940                         other. x. n [i] = x. n [i];
00941                         other. x. e [i] = x. e [i];
00942                 }
00943                 t. n = tempn;
00944                 t. e = tempe;
00945         }
00946 
00947         // swap the lengths of the chains (do not swap 'a' with 'oa')
00948         swapelements (len, other. len);
00949 
00950         if (!table)
00951                 return *this;
00952 
00953         // change the numbers in every relevant entry of the table
00954         int *tntab = oa ? t. n : x. n;
00955         int *ontab = a ? other. t. n : other. x. n;
00956         int i = 0, j = 0;
00957         while ((i < len) || (j < other. len))
00958         {
00959                 // determine which table entry should be modified
00960                 int n;
00961                 if (i >= len)
00962                         n = ontab [j ++];
00963                 else if (j >= other. len)
00964                         n = tntab [i ++];
00965                 else if (tntab [i] < ontab [j])
00966                         n = tntab [i ++];
00967                 else if (ontab [j] < tntab [i])
00968                         n = ontab [j ++];
00969                 else
00970                 {
00971                         n = tntab [i ++];
00972                         ++ j;
00973                 //      ++ i;
00974                 //      ++ j;
00975                 //      continue;
00976                 }
00977 
00978                 // swap numbers in that table entry
00979                 table [n]. swapnumbers (othernumber, number);
00980         }
00981 
00982         return *this;
00983 } /* chain<euclidom>::swap */
00984 
00985 template <class euclidom>
00986 inline chain<euclidom> &chain<euclidom>::take (chain<euclidom> &c)
00987 {
00988         // release the current tables if they were allocated
00989         if (allocated ())
00990         {
00991                 delete [] t. n;
00992                 delete [] t. e;
00993         }
00994 
00995         // if the other tables were allocated, take them
00996         if (c. allocated ())
00997         {
00998                 t. n = c. t. n;
00999                 t. e = c. t. e;
01000         }
01001 
01002         // otherwise copy the data from the internal other tables
01003         else
01004         {
01005                 for (int i = 0; i < c. len; ++ i)
01006                 {
01007                         x. n [i] = c. x. n [i];
01008                         x. e [i] = c. x. e [i];
01009                 }
01010         }
01011 
01012         // copy the length and reset the other length
01013         len = c. len;
01014         c. len = 0;
01015 
01016         return *this;
01017 } /* chain<euclidom>::take */
01018 
01019 template <class euclidom>
01020 inline chain<euclidom> &chain<euclidom>::multiply (euclidom e, int number)
01021 {
01022         // check if the tables have been allocated or not
01023         bool a = allocated ();
01024         int *tntab = a ? t. n : x. n;
01025         euclidom *tetab = a ? t. e : x. e;
01026 
01027         // if there is only one element to be multiplied, find it and do it
01028         if (number >= 0)
01029         {
01030                 for (int i = 0; i < len; ++ i)
01031                 {
01032                         if (tntab [i] == number)
01033                         {
01034                                 if (e == 0)
01035                                         removepair (i);
01036                                 else
01037                                 {
01038                                         tetab [i] *= e;
01039                                 //      if (tetab [i] == 0)
01040                                 //              removepair (i);
01041                                 }
01042                                 return *this;
01043                         }
01044                 }
01045         }
01046 
01047         // if the entire chain has to be multiplied by a non-zero number...
01048         else if (e != 0)
01049         {
01050                 for (int i = 0; i < len; ++ i)
01051                 {
01052                         tetab [i] *= e;
01053                         if (tetab [i] == 0)
01054                                 removepair (i);
01055                 }
01056         }
01057 
01058         // otherwise, if the chain has to be made zero, clean it
01059         else
01060         {
01061                 if (a)
01062                 {
01063                         delete [] t. n;
01064                         delete [] t. e;
01065                 }
01066                 len = 0;
01067         }
01068 
01069         return *this;
01070 } /* chain<euclidom>::multiply */
01071 
01072 template <class euclidom>
01073 inline outputstream &chain<euclidom>::show (outputstream &out,
01074         const char *label) const
01075 {
01076         if (len <= 0)
01077                 out << "0";
01078         bool a = allocated ();
01079         const int *tntab = a ? t. n : x. n;
01080         const euclidom *tetab = a ? t. e : x. e;
01081         for (int i = 0; i < len; ++ i)
01082         {
01083                 euclidom e = tetab [i];
01084                 int n = tntab [i] + 1;
01085 
01086                 if (e == 1)
01087                         out << (i ? " + " : "") <<
01088                                 (label ? label : "") << n;
01089                 else if (-e == 1)
01090                         out << (i ? " - " : "-") <<
01091                                 (label ? label : "") << n;
01092                 else
01093                         out << (i ? " + " : "") << e << " * " <<
01094                                 (label ? label : "") << n;
01095         }
01096         return out;
01097 } /* chain<euclidom>::show */
01098 
01099 template <class euclidom>
01100 inline std::ostream &chain<euclidom>::show (std::ostream &out, const char *label) const
01101 {
01102         outputstream tout (out);
01103         show (tout, label);
01104         return out;
01105 } /* chain<euclidom>::show */
01106 
01107 // --------------------------------------------------
01108 
01111 template <class euclidom>
01112 inline std::ostream &operator << (std::ostream &out, const chain<euclidom> &c)
01113 {
01114         c. show (out);
01115         return out;
01116 } /* operator << */
01117 
01120 template <class euclidom>
01121 inline std::istream &operator >> (std::istream &in, chain<euclidom> &c)
01122 {
01123         ignorecomments (in);
01124         int closing = readparenthesis (in);
01125 
01126         ignorecomments (in);
01127         while (in. peek () != closing)
01128         {
01129                 // read the coefficient
01130                 euclidom e (1);
01131                 in >> e;
01132 
01133                 // read the multiplication symbol
01134                 ignorecomments (in);
01135                 if (in. peek () != '*')
01136                         throw "The multiplication sign '*' while reading a chain.";
01137                 in. get ();
01138 
01139                 // read the identifier
01140                 ignorecomments (in);
01141                 int n;
01142                 in >> n;
01143                 -- n;
01144 
01145                 // if the coefficient is zero, then this is wrong
01146                 if (e == 0)
01147                         throw "A zero coefficient in a chain detected.";
01148 
01149                 // add this element to the chain
01150                 c. add (e, n);
01151 
01152                 // prepare for the next pair to read
01153                 ignorecomments (in);
01154 
01155                 // read a comma or a plus between two elements of the chain
01156                 if ((in. peek () == ',') || (in. peek () == '+'))
01157                 {
01158                         in. get ();
01159                         ignorecomments (in);
01160                 }
01161         }
01162 
01163         if (closing != EOF)
01164                 in. get ();
01165 
01166         return in;
01167 } /* operator >> */
01168 
01169 
01170 // --------------------------------------------------
01171 // ------------------- simplelist -------------------
01172 // --------------------------------------------------
01173 
01176 template <class element>
01177 class simplelist
01178 {
01179 public:
01181         simplelist ();
01182 
01184         ~simplelist ();
01185 
01187         void add (element &m);
01188 
01190         void remove (element &m);
01191 
01197         element *take ();
01198 
01199 private:
01201         simplelist (const simplelist<element> &s)
01202         {
01203                 throw "Copying constructor not implemented "
01204                         "for a simple list.";
01205                 return;
01206         }
01207 
01209         simplelist<element> &operator = (const simplelist<element> &s)
01210         {
01211                 throw "Operator = not implemented "
01212                         "for a simple list.";
01213                 return *this;
01214         }
01215 
01217         int num;
01218 
01220         int cur;
01221 
01223         element **elem;
01224 
01225 }; /* class simplelist */
01226 
01227 // --------------------------------------------------
01228 
01229 template <class element>
01230 inline simplelist<element>::simplelist (): num (0), cur (0), elem (NULL)
01231 {
01232         return;
01233 } /* simplelist::simplelist */
01234 
01235 template <class element>
01236 inline simplelist<element>::~simplelist ()
01237 {
01238         if (elem)
01239                 delete [] elem;
01240         return;
01241 } /* simplelist::~simplelist */
01242 
01243 template <class element>
01244 inline void simplelist<element>::add (element &m)
01245 {
01246         element **newelem = new element * [num + 1];
01247         for (int i = 0; i < num; ++ i)
01248                 newelem [i] = elem [i];
01249         newelem [num ++] = &m;
01250         delete [] elem;
01251         elem = newelem;
01252         return;
01253 } /* simplelist::add */
01254 
01255 template <class element>
01256 inline void simplelist<element>::remove (element &m)
01257 {
01258         int pos = 0;
01259         while ((pos < num) && (elem [pos] != &m))
01260                 ++ pos;
01261         -- num;
01262         while (pos < num)
01263         {
01264                 elem [pos] = elem [pos + 1];
01265                 ++ pos;
01266         }
01267         return;
01268 } /* simplelist::remove */
01269 
01270 template <class element>
01271 inline element *simplelist<element>::take ()
01272 {
01273         if (cur >= num)
01274         {
01275                 cur = 0;
01276                 return NULL;
01277         }
01278         else
01279         {
01280                 return elem [cur ++];
01281         }
01282 } /* simplelist::take */
01283 
01284 
01285 // --------------------------------------------------
01286 // -------------------- mmatrix ---------------------
01287 // --------------------------------------------------
01288 
01292 template <class euclidom>
01293 class mmatrix
01294 {
01295 public:
01297         mmatrix ();
01298 
01301         mmatrix (const mmatrix<euclidom> &m);
01302 
01305         mmatrix<euclidom> &operator = (const mmatrix<euclidom> &s);
01306 
01308         ~mmatrix ();
01309 
01312         void define (int numrows, int numcols);
01313 
01315         void identity (int size);
01316 
01318         void add (int row, int col, const euclidom &e);
01319 
01323         euclidom get (int row, int col) const;
01324 
01326         const chain<euclidom> &getrow (int n) const;
01327 
01329         const chain<euclidom> &getcol (int n) const;
01330 
01332         int getnrows () const;
01333 
01335         int getncols () const;
01336 
01339         void addrow (int dest, int source, const euclidom &e);
01340 
01343         void addcol (int dest, int source, const euclidom &e);
01344 
01346         void swaprows (int i, int j);
01347 
01349         void swapcols (int i, int j);
01350 
01352         void multiplyrow (int n, const euclidom &e);
01353 
01355         void multiplycol (int n, const euclidom &e);
01356 
01362         int findrow (int req_elements = 1, int start = -1) const;
01363 
01369         int findcol (int req_elements = 1, int start = -1) const;
01370 
01375         int reducerow (int n, int preferred);
01376 
01381         int reducecol (int n, int preferred);
01382 
01386         void simple_reductions (bool quiet = false);
01387 
01389         void simple_form (bool quiet = false);
01390 
01392         void invert (void);
01393 
01396         void multiply (const mmatrix<euclidom> &m1,
01397                 const mmatrix<euclidom> &m2);
01398 
01405         simplelist<mmatrix<euclidom> > dom_dom, dom_img, img_dom,
01406                 img_img;
01407 
01411         void submatrix (const mmatrix<euclidom> &matr,
01412                 const chain<euclidom> &domain,
01413                 const chain<euclidom> &range);
01414 
01417         outputstream &show_hom_col (outputstream &out, int col,
01418                 const chain<euclidom> &range,
01419                 const char *txt = NULL) const;
01420 
01423         std::ostream &show_hom_col (std::ostream &out, int col,
01424                 const chain<euclidom> &range,
01425                 const char *txt = NULL) const;
01426 
01428         outputstream &showrowscols (outputstream &out,
01429                 chain<euclidom> *table, int tablen,
01430                 int first = 0, int howmany = 0,
01431                 const char *label = NULL) const;
01432 
01434         outputstream &showrows (outputstream &out, int first = 0,
01435                 int howmany = 0, const char *label = "Row ") const;
01436 
01438         std::ostream &showrows (std::ostream &out, int first = 0,
01439                 int howmany = 0, const char *label = "Row ") const;
01440                 
01442         outputstream &showcols (outputstream &out, int first = 0,
01443                 int howmany = 0, const char *label = "Col ") const;
01444 
01446         std::ostream &showcols (std::ostream &out, int first = 0,
01447                 int howmany = 0, const char *label = "Col ") const;
01448 
01450         outputstream &showmap (outputstream &out,
01451                 const char *maplabel = NULL,
01452                 const char *xlabel = NULL, const char *ylabel = NULL)
01453                 const;
01454 
01456         std::ostream &showmap (std::ostream &out, const char *maplabel = NULL,
01457                 const char *xlabel = NULL, const char *ylabel = NULL)
01458                 const;
01459 
01460 private:
01462         int nrows;
01463 
01465         int ncols;
01466 
01468         int allrows;
01469 
01471         int allcols;
01472 
01474         chain<euclidom> *rows;
01475 
01477         chain<euclidom> *cols;
01478 
01480         int findrowcol (int req_elements, int start, int which) const;
01481 
01484         void increase (int numrows, int numcols);
01485 
01487         void increaserows (int numrows);
01488 
01491         void increasecols (int numcols);
01492 
01493 }; /* class mmatrix */
01494 
01495 // --------------------------------------------------
01496 
01497 template <class euclidom>
01498 inline mmatrix<euclidom>::mmatrix (): nrows (0), ncols (0),
01499         allrows (0), allcols (0), rows (NULL), cols (NULL)
01500 {
01501         return;
01502 } /* mmatrix<euclidom>::mmatrix */
01503 
01504 template <class euclidom>
01505 inline mmatrix<euclidom>::~mmatrix ()
01506 {
01507         if (rows)
01508                 delete [] rows;
01509         if (cols)
01510                 delete [] cols;
01511         return;
01512 } /* mmatrix<euclidom>::~mmatrix */
01513 
01514 template <class euclidom>
01515 inline void mmatrix<euclidom>::define (int numrows, int numcols)
01516 {
01517         // verify that no nonzero entry will be thrown away
01518         if ((nrows > numrows) || (ncols > numcols))
01519                 throw "Trying to define a matrix smaller than it really is";
01520 
01521         // increase the size of the matrix to fit the defined one
01522         increase (numrows, numcols);
01523 
01524         // set the number of rows and the number of columns as requested
01525         nrows = numrows;
01526         ncols = numcols;
01527 
01528         return;
01529 } /* mmatrix<euclidom>::define */
01530 
01531 template <class euclidom>
01532 inline mmatrix<euclidom>::mmatrix (const mmatrix<euclidom> &m)
01533 {
01534         nrows = m.nrows; 
01535         ncols = m.ncols;
01536         allrows = m.allrows;
01537         allcols = m.allcols;
01538 
01539         rows = NULL;
01540         cols = NULL;
01541         if (m. allrows > 0)
01542         {
01543                 chain<euclidom> *newrows = new chain<euclidom> [m. allrows];
01544                 if (!newrows)
01545                         throw "Not enough memory for matrix rows.";
01546                 for (int i = 0; i < m. allrows; ++ i)
01547                         newrows [i] = m. rows [i];
01548                 rows = newrows;
01549         }
01550 
01551         if (m. allcols > 0)
01552         {
01553                 chain<euclidom> *newcols = new chain<euclidom> [m. allcols];
01554                 if (!newcols)
01555                         throw "Not enough memory for matrix columns.";
01556                 for (int i = 0; i < m.allcols; ++ i)
01557                         newcols [i] = m. cols [i];
01558                 cols = newcols;
01559         }
01560 } /* mmatrix<euclidom>::mmatrix */
01561 
01562 template <class euclidom>
01563 inline mmatrix<euclidom> &mmatrix<euclidom>::operator =
01564         (const mmatrix<euclidom> &m)
01565 {
01566         // first release allocated tables if any
01567         if (rows)
01568                 delete [] rows;
01569         if (cols)
01570                 delete [] cols;
01571 
01572         nrows = m. nrows; 
01573         ncols = m. ncols;
01574         allrows = m. allrows;
01575         allcols = m. allcols;
01576 
01577         rows = NULL;
01578         cols = NULL;
01579         if (m. allrows > 0)
01580         {
01581                 chain<euclidom> *newrows = new chain<euclidom> [m. allrows];
01582                 if (!newrows)
01583                         throw "Not enough memory for matrix rows.";
01584                 for (int i = 0; i < m. allrows; ++ i)
01585                         newrows [i] = m. rows [i];
01586                 rows = newrows;
01587         }
01588 
01589         if (m. allcols > 0)
01590         {
01591                 chain<euclidom> *newcols = new chain<euclidom> [m. allcols];
01592                 if (!newcols)
01593                         throw "Not enough memory for matrix columns.";
01594                 for (int i = 0; i < m.allcols; ++ i)
01595                         newcols [i] = m. cols [i];
01596                 cols = newcols;
01597         }
01598 
01599         return *this;
01600 } /* mmatrix<euclidom>::operator = */
01601 
01602 template <class euclidom>
01603 inline void mmatrix<euclidom>::identity (int size)
01604 {
01605         if (!nrows && !ncols)
01606                 increase (size, size);
01607         else if ((size > nrows) || (size > ncols))
01608                 size = (nrows < ncols) ? nrows : ncols;
01609         for (int i = 0; i < size; ++ i)
01610         {
01611                 euclidom one;
01612                 one = 1;
01613                 add (i, i, one);
01614         }
01615         return;
01616 } /* mmatrix<euclidom>::identity */
01617 
01618 template <class euclidom>
01619 inline void mmatrix<euclidom>::add (int row, int col, const euclidom &e)
01620 // A [r] [c] += e;
01621 {
01622         if (row < 0)
01623                 throw "Incorrect row number.";
01624         if (col < 0)
01625                 throw "Incorrect column number.";
01626         if (row >= nrows)
01627         {
01628                 if (row >= allrows)
01629                         increaserows (row + row / 2 + 1);
01630                 nrows = row + 1;
01631         }
01632         if (col >= ncols)
01633         {
01634                 if (col >= allcols)
01635                         increasecols (col + col / 2 + 1);
01636                 ncols = col + 1;
01637         }
01638         if (e == 0)
01639                 return;
01640         cols [col]. add (row, e);
01641         rows [row]. add (col, e);
01642         return;
01643 } /* mmatrix<euclidom>::add */
01644 
01645 template <class euclidom>
01646 inline euclidom mmatrix<euclidom>::get (int row, int col) const
01647 // return (A [r] [c]);
01648 {
01649         if ((row >= nrows) || (col >= ncols))
01650         {
01651                 euclidom zero;
01652                 zero = 0;
01653                 return zero;
01654         }
01655         if (row >= 0)
01656                 return rows [row]. getcoefficient (col);
01657         else if (col >= 0)
01658                 return cols [col]. getcoefficient (row);
01659         else
01660         {
01661                 euclidom zero;
01662                 zero = 0;
01663                 return zero;
01664         }
01665 } /* mmatrix<euclidom>::get */
01666 
01667 template <class euclidom>
01668 inline const chain<euclidom> &mmatrix<euclidom>::getrow (int n) const
01669 {
01670         if ((n < 0) || (n >= nrows))
01671                 throw "Incorrect row number.";
01672         return rows [n];
01673 } /* mmatrix<euclidom>::getrow */
01674 
01675 template <class euclidom>
01676 inline const chain<euclidom> &mmatrix<euclidom>::getcol (int n) const
01677 {
01678         if ((n < 0) || (n >= ncols))
01679                 throw "Incorrect column number.";
01680         return cols [n];
01681 } /* mmatrix<euclidom>::getcol */
01682 
01683 template <class euclidom>
01684 inline int mmatrix<euclidom>::getnrows () const
01685 {
01686         return nrows;
01687 } /* mmatrix<euclidom>::getnrows */
01688 
01689 template <class euclidom>
01690 inline int mmatrix<euclidom>::getncols () const
01691 {
01692         return ncols;
01693 } /* mmatrix<euclidom>::getncols */
01694 
01695 template <class euclidom>
01696 inline void mmatrix<euclidom>::addrow (int dest, int source,
01697         const euclidom &e)
01698 {
01699         // check if the parameters are not out of range
01700         if ((dest < 0) || (dest >= nrows) || (source < 0) ||
01701                 (source >= nrows))
01702                 throw "Trying to add rows out of range.";
01703 
01704         // add this row
01705         rows [dest]. add (rows [source], e, dest, cols);
01706 
01707         // update the other matrices
01708         mmatrix<euclidom> *m;
01709         while ((m = img_img. take ()) != NULL)
01710                 if (m -> rows)
01711                         m -> rows [dest]. add (m -> rows [source], e,
01712                                 dest, m -> cols);
01713 
01714         while ((m = img_dom. take ()) != NULL)
01715                 if (m -> cols)
01716                         m -> cols [source]. add (m -> cols [dest], -e,
01717                                 source, m -> rows);
01718 
01719         return;
01720 } /* mmatrix<euclidom>::addrow */
01721 
01722 template <class euclidom>
01723 inline void mmatrix<euclidom>::addcol (int dest, int source,
01724         const euclidom &e)
01725 {
01726         // check if the parameters are not out of range
01727         if ((dest < 0) || (dest >= ncols) || (source < 0) ||
01728                 (source >= ncols))
01729                 throw "Trying to add columns out of range.";
01730 
01731         // add this column
01732         cols [dest]. add (cols [source], e, dest, rows);
01733 
01734         // update the other matrices
01735         mmatrix<euclidom> *m;
01736         while ((m = dom_dom. take ()) != NULL)
01737                 if (m -> cols)
01738                         m -> cols [dest]. add (m -> cols [source], e,
01739                                 dest, m -> rows);
01740 
01741         while ((m = dom_img. take ()) != NULL)
01742                 if (m -> rows)
01743                         m -> rows [source]. add (m -> rows [dest], -e,
01744                                 source, m -> cols);
01745 
01746         return;
01747 } /* mmatrix<euclidom>::addcol */
01748 
01749 template <class euclidom>
01750 inline void mmatrix<euclidom>::swaprows (int i, int j)
01751 {
01752         // in the trivial case nothing needs to be done
01753         if (i == j)
01754                 return;
01755 
01756         // check if the parameters are not out of range
01757         if ((i < 0) || (i >= nrows) || (j < 0) || (j >= nrows))
01758                 throw "Trying to swap rows out of range.";
01759 
01760         // swap the rows
01761         rows [i]. swap (rows [j], i, j, cols);
01762 
01763         // update the other matrices
01764         mmatrix<euclidom> *m;
01765         while ((m = img_img. take ()) != NULL)
01766                 if ((m -> rows) && (m -> nrows))
01767                         m -> rows [i]. swap (m -> rows [j], i, j, m -> cols);
01768 
01769         while ((m = img_dom. take ()) != NULL)
01770                 if ((m -> cols) && (m -> ncols))
01771                         m -> cols [i]. swap (m -> cols [j], i, j, m -> rows);
01772 
01773         return;
01774 } /* mmatrix<euclidom>::swaprows */
01775 
01776 template <class euclidom>
01777 inline void mmatrix<euclidom>::swapcols (int i, int j)
01778 {
01779         // in the trivial case nothing needs to be done
01780         if (i == j)
01781                 return;
01782 
01783         // check if the parameters are not out of range
01784         if ((i < 0) || (i >= ncols) || (j < 0) || (j >= ncols))
01785                 throw "Trying to swap cols out of range.";
01786 
01787         // swap the columns
01788         cols [i]. swap (cols [j], i, j, rows);
01789 
01790         // update the other matrices
01791         mmatrix<euclidom> *m;
01792         while ((m = dom_dom. take ()) != NULL)
01793                 if ((m -> cols) && (m -> ncols))
01794                         m -> cols [i]. swap (m -> cols [j], i, j, m -> rows);
01795 
01796         while ((m = dom_img. take ()) != NULL)
01797                 if ((m -> rows) && (m -> nrows))
01798                         m -> rows [i]. swap (m -> rows [j], i, j, m -> cols);
01799 
01800         return;
01801 } /* mmatrix<euclidom>::swapcols */
01802 
01803 template <class euclidom>
01804 inline void mmatrix<euclidom>::multiplyrow (int n, const euclidom &e)
01805 {
01806         // retrieve the row
01807         chain<euclidom> &therow = rows [n];
01808 
01809         // multiply the row
01810         therow. multiply (e);
01811 
01812         // multiply the corresponding entries in all the columns
01813         for (int i = 0; i < therow. size (); ++ i)
01814                 cols [therow. num (i)]. multiply (e, n);
01815 
01816         return;
01817 } /* mmatrix<euclidom>::multiplyrow */
01818 
01819 template <class euclidom>
01820 inline void mmatrix<euclidom>::multiplycol (int n, const euclidom &e)
01821 {
01822         // retrieve the row
01823         chain<euclidom> &thecol = cols [n];
01824 
01825         // multiply the row
01826         thecol. multiply (e);
01827 
01828         // multiply the corresponding entries in all the rows
01829         for (int i = 0; i < thecol. size (); ++ i)
01830                 rows [thecol. num (i)]. multiply (e, n);
01831 
01832         return;
01833 } /* mmatrix<euclidom>::multiplycol */
01834 
01835 template <class euclidom>
01836 inline int mmatrix<euclidom>::findrowcol (int req_elements, int start,
01837         int which) const
01838 // which: row = 1, col = 0
01839 {
01840         // start at the starting point
01841         int i = start;
01842         int random_i = -1;
01843 
01844         // set loop to none
01845         int loopcounter = 0;
01846 
01847         // if a random start is requested, initialize it and set loop to 1
01848         if (start < 0)
01849         {
01850                 i = random_i = std::rand () % (which ? nrows : ncols);
01851                 loopcounter = 1;
01852         }
01853 
01854         // select some candidates
01855         int candidate = -1;
01856         int candidates_left = 3;
01857 
01858         // if the table has one of its dimensions trivial, return the result
01859         if (which ? !ncols : !nrows)
01860                 return (((req_elements > 0) ||
01861                         (i >= (which ? nrows : ncols))) ? -1 : i);
01862 
01863         // while the current position has not gone beyond the table
01864         while (i < (which ? nrows : ncols))
01865         {
01866                 // if there is an appropriate row/column, return its number
01867                 int l = (which ? rows : cols) [i]. size ();
01868                 if ((req_elements >= 0) && (l >= req_elements))
01869                         return i;
01870                 else if ((req_elements < 0) && !l)
01871                 {
01872                         if (!candidates_left || !(which ? rows : cols) [i].
01873                                 contains_non_invertible ())
01874                                 return i;
01875                         else
01876                         {
01877                                 candidate = i;
01878                                 -- candidates_left;
01879                                 if (start < 0)
01880                                 {
01881                                         random_i = std::rand () %
01882                                                 (which ? nrows : ncols);
01883                                         i = random_i - 1;
01884                                         loopcounter = 1;
01885                                 }
01886                         }
01887                 }
01888 
01889                 // otherwise increase the counter and rewind to 0 if needed
01890                 if (++ i >= (which ? nrows : ncols))
01891                         if (loopcounter --)
01892                                 i = 0;
01893 
01894                 // if the searching was started at a random position,
01895                 // finish earlier
01896                 if ((random_i >= 0) && !loopcounter && (i >= random_i))
01897                         break;
01898         }
01899 
01900         // if not found, return the recent candidate (or -1 if none)
01901         return candidate;
01902 } /* mmatrix<euclidom>::findrowcol */
01903 
01904 template <class euclidom>
01905 inline int mmatrix<euclidom>::findrow (int req_elements, int start) const
01906 {
01907         return findrowcol (req_elements, start, 1);
01908 } /* mmatrix<euclidom>::findrow */
01909 
01910 template <class euclidom>
01911 inline int mmatrix<euclidom>::findcol (int req_elements, int start) const
01912 {
01913         return findrowcol (req_elements, start, 0);
01914 } /* mmatrix<euclidom>::findcol */
01915 
01916 template <class euclidom>
01917 inline int mmatrix<euclidom>::reducerow (int n, int preferred)
01918 {
01919         if (n >= nrows)
01920                 throw "Trying to reduce a row out of range.";
01921 
01922         int the_other = -1;
01923 
01924         // repeat until the row contains at most one nonzero entry
01925         int len;
01926         while ((len = rows [n]. size ()) > 1)
01927         {
01928                 // copy the row to a local structure
01929                 chain<euclidom> local (rows [n]);
01930 
01931                 // find the best element in this row
01932                 int best_i = local. findbest (cols);
01933 
01934                 // find the number of the preferred element in the row
01935                 int preferred_i = (preferred < 0) ? -1 :
01936                         local. findnumber (preferred);
01937 
01938                 // check if the element in the preferred column
01939                 // is equally good as the one already chosen
01940                 if ((preferred_i >= 0) &&
01941                         (local. coef (preferred_i). delta () ==
01942                         local. coef (best_i). delta ()))
01943                         best_i = preferred_i;
01944 
01945                 // remember the column number containing this element
01946                 the_other = local. num (best_i);
01947 
01948                 // for each column
01949                 for (int i = 0; i < len; ++ i)
01950                 {
01951                         // if this column is the chosen one, do nothing
01952                         if (i == best_i)
01953                                 continue;
01954 
01955                         // compute the quotient of two elements
01956                         euclidom quotient = local. coef (i) /
01957                                 local. coef (best_i);
01958 
01959                         // subtract the chosen column from the other one
01960                         addcol (local. num (i), local. num (best_i),
01961                                 -quotient);
01962                 }
01963         }
01964 
01965         return the_other;
01966 } /* mmatrix<euclidom>::reducerow */
01967 
01968 template <class euclidom>
01969 inline int mmatrix<euclidom>::reducecol (int n, int preferred)
01970 {
01971         if (n >= ncols)
01972                 throw "Trying to reduce a column out of range.";
01973 
01974         int the_other = -1;
01975 
01976         // repeat until the column contains at most one nonzero entry
01977         int len;
01978         while ((len = cols [n]. size ()) > 1)
01979         {
01980                 // copy the column to a local structure
01981                 chain<euclidom> local (cols [n]);
01982 
01983                 // find the best element in this column
01984                 int best_i = local. findbest (rows);
01985 
01986                 // find the number of the preferred element in the row
01987                 int preferred_i = (preferred < 0) ? -1 :
01988                         local. findnumber (preferred);
01989 
01990                 // check if the element in the preferred column
01991                 // is equally good as the one already chosen
01992                 if ((preferred_i >= 0) &&
01993                         (local. coef (preferred_i). delta () ==
01994                         local. coef (best_i). delta ()))
01995                         best_i = preferred_i;
01996 
01997                 // remember the row number containing this element
01998                 the_other = local. num (best_i);
01999 
02000                 // for each row
02001                 for (int i = 0; i < len; ++ i)
02002                 {
02003                         // if this row is the chosen one, do nothing
02004                         if (i == best_i)
02005                                 continue;
02006 
02007                         // compute the quotient of two elements
02008                         euclidom quotient = local. coef (i) /
02009                                 local. coef (best_i);
02010 
02011                         // subtract the chosen row from the other one
02012                         addrow (local. num (i), local. num (best_i),
02013                                 -quotient);
02014                 }
02015         }
02016 
02017         return the_other;
02018 } /* mmatrix<euclidom>::reducecol */
02019 
02020 template <class euclidom>
02021 inline outputstream &mmatrix<euclidom>::showrowscols (outputstream &out,
02022         chain<euclidom> *table, int tablen, int first, int howmany,
02023         const char *label) const
02024 {
02025         if ((first < 0) || (first >= tablen))
02026                 first = 0;
02027         if ((howmany <= 0) || (first + howmany > tablen))
02028                 howmany = tablen - first;
02029         for (int i = 0; i < howmany; ++ i)
02030                 out << (label ? label : "") << (first + i + 1) << ": " <<
02031                         table [first + i] << '\n';
02032         out << '\n';
02033         return out;
02034 } /* matrix<euclidom>::showrowscols */
02035 
02036 template <class euclidom>
02037 inline outputstream &mmatrix<euclidom>::showrows (outputstream &out,
02038         int first, int howmany, const char *label) const
02039 {
02040         return showrowscols (out, rows, nrows, first, howmany, label);
02041 } /* mmatrix<euclidom>::showrows */
02042 
02043 template <class euclidom>
02044 inline std::ostream &mmatrix<euclidom>::showrows (std::ostream &out,
02045         int first, int howmany, const char *label) const
02046 {
02047         outputstream tout (out);
02048         showrows (tout, first, howmany, label);
02049         return out;
02050 } /* mmatrix<euclidom>::showrows */
02051 
02052 template <class euclidom>
02053 inline outputstream &mmatrix<euclidom>::showcols (outputstream &out,
02054         int first, int howmany, const char *label) const
02055 {
02056         return showrowscols (out, cols, ncols, first, howmany, label);
02057 } /* mmatrix<euclidom>::showcols */
02058 
02059 template <class euclidom>
02060 inline std::ostream &mmatrix<euclidom>::showcols (std::ostream &out,
02061         int first, int howmany, const char *label) const
02062 {
02063         outputstream tout (out);
02064         showcols (tout, first, howmany, label);
02065         return out;
02066 } /* mmatrix<euclidom>::showcols */
02067 
02068 template <class euclidom>
02069 inline outputstream &mmatrix<euclidom>::showmap (outputstream &out,
02070         const char *maplabel, const char *xlabel, const char *ylabel) const
02071 {
02072         if (ncols <= 0)
02073         {
02074                 if (maplabel && (maplabel [0] == '\t'))
02075                         out << "\t0\n";
02076                 else
02077                         out << "0\n";
02078         }
02079         for (int i = 0; i < ncols; ++ i)
02080         {
02081                 out << (maplabel ? maplabel : "f") << " (" <<
02082                         (xlabel ? xlabel : "") << (i + 1) << ") = ";
02083                 cols [i]. show (out, ylabel) << '\n';
02084         }
02085         return out;
02086 } /* mmatrix<euclidom>::showmap */
02087 
02088 template <class euclidom>
02089 inline std::ostream &mmatrix<euclidom>::showmap (std::ostream &out,
02090         const char *maplabel, const char *xlabel, const char *ylabel) const
02091 {
02092         outputstream tout (out);
02093         showmap (tout, maplabel, xlabel, ylabel);
02094         return out;
02095 } /* mmatrix<euclidom>::showmap */
02096 
02097 template <class euclidom>
02098 inline void mmatrix<euclidom>::simple_reductions (bool quiet)
02099 {
02100         // if the matrix has no rows or no columns,
02101         // simple reductions make no sense
02102         if (!nrows || !ncols)
02103                 return;
02104 
02105         // prepare counters
02106         long countreduced = 0;
02107         long count = 4 * ((nrows > ncols) ? ncols : nrows);
02108 
02109         // prepare quazi-random numbers
02110         int nr = std::rand () % nrows;
02111         int nr_count = 0;
02112         int nr_add = 0;
02113 
02114         // try quazi-random reductions
02115         while (count --)
02116         {
02117                 // try a simple reduction
02118                 if ((rows [nr]. size () == 1) &&
02119                         (rows [nr]. coef (0). delta () == 1) &&
02120                         (cols [rows [nr]. num (0)]. size () > 1))
02121                 {
02122                         ++ countreduced;
02123                         reducecol (rows [nr]. num (0), -1);
02124                 }
02125 
02126                 // try a new semi-random position
02127                 if (nr_count)
02128                         -- nr_count;
02129                 else
02130                 {
02131                         nr_add = ((std::rand () >> 2) + 171) % nrows;
02132                         if (nr_add < 1)
02133                                 nr_add = 1;
02134                         nr_count = 100;
02135                 }
02136                 nr += nr_add;
02137                 if (nr >= nrows)
02138                         nr -= nrows;
02139 
02140                 // display a counter
02141                 if (!quiet && !(count % 373))
02142                         scon << std::setw (12) << count <<
02143                                 "\b\b\b\b\b\b\b\b\b\b\b\b";
02144         }
02145 
02146         if (!quiet)
02147                 sout << countreduced << " +";
02148 
02149         return;
02150 } /* mmatrix<euclidom>::simple_reductions */
02151 
02152 template <class euclidom>
02153 inline void mmatrix<euclidom>::simple_form (bool quiet)
02154 {
02155         // if the matrix has no rows or columns, it is already in simple form
02156         if (!nrows || !ncols)
02157                 return;
02158 
02159         // make some random simple reductions before proceeding
02160         simple_reductions (quiet);
02161 
02162         // prepare a counter
02163         long count = 0;
02164 
02165         // prepare variables for chosen row and column numbers
02166         int row, col, prev_row, prev_col;
02167 
02168         // find a row or a column with at least two nonzero entries
02169         row = -1;
02170         col = findcol (2);
02171         prev_row = -1, prev_col = -1;
02172         if (col < 0)
02173                 row = findrow (2);
02174 
02175         // repeat while such a row or a column can be found
02176         while ((row >= 0) || (col >= 0))
02177         {
02178                 // reduce rows and columns until a single entry remains
02179                 while ((row >= 0) || (col >= 0))
02180                         if (row >= 0)
02181                         {
02182                                 col = reducerow (row, prev_col);
02183                                 prev_row = row;
02184                                 row = -1;
02185                         }
02186                         else if (col >= 0)
02187                         {
02188                                 row = reducecol (col, prev_row);
02189                                 prev_col = col;
02190                                 col = -1;
02191                         }
02192 
02193                 // update the counter and display it if requested to
02194                 ++ count;
02195                 if (!quiet && !(count % 373))
02196                         scon << std::setw (12) << count <<
02197                                 "\b\b\b\b\b\b\b\b\b\b\b\b";
02198 
02199                 // find another row or column with at least 2 nonzero entries
02200                 col = findcol (2);
02201                 if (col < 0)
02202                         row = findrow (2);
02203         }
02204 
02205         if (!quiet)
02206                 sout << " " << count << " reductions made. ";
02207 
02208         return;
02209 } /* mmatrix<euclidom>::simple_form */
02210 
02211 template <class euclidom>
02212 inline void mmatrix<euclidom>::invert (void)
02213 {
02214         // check if the matrix is square
02215         if (nrows != ncols)
02216                 throw "Trying to invert a non-square matrix.";
02217 
02218         // if the matrix is trivial, nothing needs to be done
02219         if (!nrows)
02220                 return;
02221 
02222         // create the identity matrix of the appropriate size
02223         mmatrix<euclidom> m;
02224         m. identity (ncols);
02225         
02226         // transform the matrix to the identity
02227         // by row operations (swapping and adding)
02228         // and apply the same operations to the matrix 'm'
02229         for (int col = 0; col < ncols; ++ col)
02230         {
02231                 // find an invertible element in the column
02232                 int len = cols [col]. size ();
02233                 if (len <= 0)
02234                 {
02235                         throw "Matrix inverting: Zero column found.";
02236                 }
02237                 int chosen = 0;
02238                 while ((chosen < len) &&
02239                         ((cols [col]. num (chosen) < col) ||
02240                         (cols [col]. coef (chosen). delta () != 1)))
02241                 {
02242                         ++ chosen;
02243                 }
02244                 if (chosen >= len)
02245                 {
02246                         throw "Matrix inverting: "
02247                                 "No invertible element in a column.";
02248                 }
02249 
02250                 // make the leading entry equal 1 in the chosen row
02251                 euclidom invcoef;
02252                 invcoef = 1;
02253                 invcoef = invcoef / cols [col]. coef (chosen);
02254                 m. multiplyrow (cols [col]. num (chosen), invcoef);
02255                 multiplyrow (cols [col]. num (chosen), invcoef);
02256 
02257                 // move the chosen row to the diagonal position
02258                 m. swaprows (col, cols [col]. num (chosen));
02259                 swaprows (col, cols [col]. num (chosen));
02260 
02261                 // zero the column below and above the chosen entry
02262                 invcoef = -1;
02263                 for (int i = 0; i < len; ++ i)
02264                 {
02265                         if (cols [col]. num (i) == col)
02266                                 continue;
02267                         euclidom coef = invcoef * cols [col]. coef (i);
02268                         m. addrow (cols [col]. num (i), col, coef);
02269                         addrow (cols [col]. num (i), col, coef);
02270                         -- i;
02271                         -- len;
02272                 }
02273         }
02274 
02275         // take the matrix 'm' as the result
02276         for (int i = 0; i < ncols; ++ i)
02277         {
02278                 cols [i]. take (m. cols [i]);
02279                 rows [i]. take (m. rows [i]);
02280         }
02281 
02282         return;
02283 } /* mmatrix<euclidom>::invert */
02284 
02285 template <class euclidom>
02286 inline void mmatrix<euclidom>::multiply (const mmatrix<euclidom> &m1,
02287         const mmatrix<euclidom> &m2)
02288 {
02289         if (m1. ncols != m2. nrows)
02290                 throw "Trying to multiply matrices of wrong sizes.";
02291         int K = m1. ncols;
02292         define (m1. nrows, m2. ncols);
02293         for (int i = 0; i < nrows; ++ i)
02294         {
02295                 for (int j = 0; j < ncols; ++ j)
02296                 {
02297                         euclidom e;
02298                         e = 0;
02299                         for (int k = 0; k < K; ++ k)
02300                                 e += m1. get (i, k) * m2. get (k, j);
02301                         add (i, j, e);
02302                 }
02303         }
02304         return;
02305 } /* mmatrix<euclidom>::multiply */
02306 
02307 template <class euclidom>
02308 inline void mmatrix<euclidom>::submatrix (const mmatrix<euclidom> &matr,
02309         const chain<euclidom> &domain, const chain<euclidom> &range)
02310 {
02311         for (int i = 0; i < domain. size (); ++ i)
02312         {
02313                 for (int j = 0; j < range. size (); ++ j)
02314                 {
02315                         euclidom e = matr. get (domain. num (i),
02316                                 range. num (j));
02317                         if (!(e == 0))
02318                                 add (i, j, e);
02319                 }
02320         }
02321 
02322         return;
02323 } /* mmatrix<euclidom>::submatrix */
02324 
02325 template <class euclidom>
02326 inline outputstream &mmatrix<euclidom>::show_hom_col (outputstream &out,
02327         int col, const chain<euclidom> &range, const char *txt) const
02328 {
02329         // keep current position in 'range'
02330         int j = 0;
02331 
02332         // remember if this is the first displayed element
02333         int first = 1;
02334 
02335         // go through the column of the matrix
02336         for (int i = 0; i < cols [col]. size (); ++ i)
02337         {
02338                 // find the current element in the range
02339                 while ((j < range. size ()) &&
02340                         (range. num (j) < cols [col]. num (i)))
02341                 {
02342                         ++ j;
02343                 }
02344 
02345                 // if this element was found in the range, display it
02346                 if ((j < range. size ()) &&
02347                         (range. num (j) == cols [col]. num (i)))
02348                 {
02349                         if (first)
02350                                 first = 0;
02351                         else
02352                                 out << " + ";
02353                         if (-cols [col]. coef (i) == 1)
02354                                 out << "-";
02355                         else if (cols [col]. coef (i) != 1)
02356                                 out << cols [col]. coef (i) << " * ";
02357                         if (txt)
02358                                 out << txt;
02359                         out << (j + 1);
02360                 }
02361         }
02362 
02363         // if nothing was shown, display 0
02364         if (first)
02365                 out << 0;
02366 
02367         return out;
02368 } /* mmatrix<euclidom>::show_hom_col */
02369 
02370 template <class euclidom>
02371 inline std::ostream &mmatrix<euclidom>::show_hom_col (std::ostream &out, int col,
02372         const chain<euclidom> &range, const char *txt) const
02373 {
02374         outputstream tout (out);
02375         show_hom_col (tout, col, range, txt);
02376         return out;
02377 } /* mmatrix<euclidom>::show_hom_col */
02378 
02379 // --------------------------------------------------
02380 
02381 template <class euclidom>
02382 inline void mmatrix<euclidom>::increase (int numrows, int numcols)
02383 {
02384         increaserows (numrows);
02385         increasecols (numcols);
02386         return;
02387 } /* mmatrix<euclidom>::increase */
02388 
02389 template <class euclidom>
02390 inline void mmatrix<euclidom>::increaserows (int numrows)
02391 {
02392         if (allrows >= numrows)
02393                 return;
02394         chain<euclidom> *newrows = new chain<euclidom> [numrows];
02395         if (!newrows)
02396                 throw "Not enough memory for matrix rows.";
02397         for (int i = 0; i < nrows; ++ i)
02398                 newrows [i]. take (rows [i]);
02399         if (rows)
02400                 delete [] rows;
02401         rows = newrows;
02402         allrows = numrows;
02403         return;
02404 } /* mmatrix<euclidom>::increaserows */
02405 
02406 template <class euclidom>
02407 inline void mmatrix<euclidom>::increasecols (int numcols)
02408 {
02409         if (allcols >= numcols)
02410                 return;
02411         chain<euclidom> *newcols = new chain<euclidom> [numcols];
02412         if (!newcols)
02413                 throw "Not enough memory for matrix columns.";
02414         for (int i = 0; i < ncols; ++ i)
02415                 newcols [i]. take (cols [i]);
02416         if (cols)
02417                 delete [] cols;
02418         cols = newcols;
02419         allcols = numcols;
02420 
02421         return;
02422 } /* mmatrix<euclidom>::increasecols */
02423 
02424 // --------------------------------------------------
02425 
02428 template <class euclidom>
02429 inline std::ostream &operator << (std::ostream &out,
02430         const mmatrix<euclidom> &m)
02431 {
02432         return m. showcols (out);
02433 } /* operator << */
02434 
02435 
02436 // --------------------------------------------------
02437 // ------------------ chaincomplex ------------------
02438 // --------------------------------------------------
02439 
02444 template <class euclidom>
02445 class chaincomplex
02446 {
02447 public:
02451         chaincomplex (int d, int trace_generators = 0);
02452 
02454         ~chaincomplex ();
02455 
02460         void def_gen (int q, int n);
02461 
02464         void add (int q, int m, int n, const euclidom &e);
02465 
02468         euclidom get (int q, int row, int col) const;
02469 
02471         const mmatrix<euclidom> &getboundary (int i) const;
02472 
02474         int getnumgen (int i) const;
02475 
02477         int dim () const;
02478 
02481         const chain<euclidom> &gethomgen (int q, int i) const;
02482 
02485         void simple_form (int which, bool quiet);
02486 
02491         void simple_form (const int *level, bool quiet);
02492 
02498         int simple_homology (chain<euclidom> &result, int which) const;
02499 
02508         int simple_homology (chain<euclidom> *&result,
02509                 const int *level = NULL) const;
02510 
02514         void take_homology (const chain<euclidom> *hom_chain);
02515 
02519         outputstream &show_homology (outputstream &out,
02520                 const chain<euclidom> *hom,
02521                 const int *level = NULL) const;
02522 
02526         std::ostream &show_homology (std::ostream &out,
02527                 const chain<euclidom> *hom,
02528                 const int *level = NULL) const;
02529 
02533         outputstream &show_generators (outputstream &out,
02534                 const chain<euclidom> &list, int q) const;
02535 
02539         std::ostream &show_generators (std::ostream &out,
02540                 const chain<euclidom> &list, int q) const;
02541 
02543         outputstream &compute_and_show_homology (outputstream &out,
02544                 chain<euclidom> *&hom, const int *level = NULL);
02545 
02547         std::ostream &compute_and_show_homology (std::ostream &out,
02548                 chain<euclidom> *&hom, const int *level = NULL);
02549 
02552         friend class chainmap<euclidom>;
02553 
02554 private:
02556         chaincomplex (const chaincomplex<euclidom> &m)
02557                 {throw "Copying constructor not implemented "
02558                 "for a chain complex.";}
02559 
02561         chaincomplex<euclidom> &operator =
02562                 (const chaincomplex<euclidom> &s)
02563                 {throw "Operator = not implemented "
02564                 "for a chain complex."; return *this;}
02565 
02567         int len;
02568 
02571         mmatrix<euclidom> *boundary;
02572 
02575         mmatrix<euclidom> *generators;
02576 
02579         int *generators_initialized;
02580 
02583         int *numgen;
02584 
02585 }; /* class chaincomplex */
02586 
02587 // --------------------------------------------------
02588 
02589 template <class euclidom>
02590 inline chaincomplex<euclidom>::chaincomplex (int d, int trace_generators)
02591 {
02592         // set the number of tables to be sufficient for 0 to d inclusive
02593         len = (d >= 0) ? (d + 1) : 0;
02594 
02595         // create a table of empty matrices
02596         boundary = len ? new mmatrix<euclidom> [len] : NULL;
02597 
02598         // create a table of matrices for tracing generators of homology
02599         generators = (trace_generators && len) ?
02600                 new mmatrix<euclidom> [len] : NULL;
02601         if (generators)
02602                 generators_initialized = new int [len];
02603         else
02604                 generators_initialized = NULL;
02605 
02606         // create a table of generator numbers
02607         numgen = len ? new int [len] : NULL;
02608 
02609         // link the boundary matrices to each other and to the generators
02610         for (int i = 0; i < len; ++ i)
02611         {
02612                 numgen [i] = -1;
02613                 if (i < len - 1)
02614                         boundary [i]. dom_img. add (boundary [i + 1]);
02615                 if (i > 0)
02616                         boundary [i]. img_dom. add (boundary [i - 1]);
02617                 if (generators)
02618                 {
02619                         boundary [i]. dom_dom. add (generators [i]);
02620                         if (i > 0)
02621                                 boundary [i]. img_dom. add
02622                                         (generators [i - 1]);
02623                         generators_initialized [i] = 0;
02624                 }
02625         }
02626 
02627         return;
02628 } /* chaincomplex<euclidom>::chaincomplex */
02629 
02630 template <class euclidom>
02631 inline chaincomplex<euclidom>::~chaincomplex ()
02632 {
02633         if (boundary)
02634                 delete [] boundary;
02635         if (generators)
02636                 delete [] generators;
02637         if (numgen)
02638                 delete [] numgen;
02639         if (generators_initialized)
02640                 delete [] generators_initialized;
02641         return;
02642 } /* chaincomplex<euclidom>::~chaincomplex */
02643 
02644 template <class euclidom>
02645 inline void chaincomplex<euclidom>::def_gen (int q, int n)
02646 {
02647         if ((q < 0) || (q >= len))
02648                 return;
02649 
02650         if (numgen [q] < n)
02651                 numgen [q] = n;
02652 
02653         if (q == 0)
02654                 boundary [0]. define (0, numgen [q]);
02655         if ((q > 0) && (numgen [q - 1] >= 0))
02656                 boundary [q]. define (numgen [q - 1], numgen [q]);
02657         if ((q < dim ()) && (numgen [q + 1] >= 0))
02658                 boundary [q + 1]. define (numgen [q], numgen [q + 1]);
02659 
02660         return;
02661 } /* chaincomplex<euclidom>::def_gen */
02662 
02663 template <class euclidom>
02664 inline void chaincomplex<euclidom>::add (int q, int m, int n,
02665         const euclidom &e)
02666 {
02667         if ((q <= 0) || (q >= len))
02668                 throw "Trying to add a boundary for dimension out of range";
02669 
02670         if (numgen [q] <= n)
02671                 numgen [q] = n + 1;
02672         if (numgen [q - 1] <= m)
02673                 numgen [q - 1] = m + 1;
02674 
02675         boundary [q]. add (m, n, e);
02676         return;
02677 } /* chaincomplex<euclidom>::add */
02678 
02679 template <class euclidom>
02680 inline euclidom chaincomplex<euclidom>::get (int q, int row, int col) const
02681 {
02682         if ((q <= 0) || (q >= len))
02683                 throw "Boundary coefficient out of range from chain cplx.";
02684 
02685         return boundary [q]. get (row, col);
02686 } /* chaincomplex<euclidom>::get */
02687 
02688 template <class euclidom>
02689 inline const mmatrix<euclidom> &chaincomplex<euclidom>::getboundary (int i)
02690         const
02691 {
02692         if ((i <= 0) || (i >= len))
02693                 throw "Boundary matrix out of range from chain complex.";
02694 
02695         return boundary [i];
02696 } /* chaincomplex<euclidom>::getboundary */
02697 
02698 template <class euclidom>
02699 inline int chaincomplex<euclidom>::getnumgen (int i) const
02700 {
02701         if ((i < 0) || (i >= len))
02702         //      throw "Level for the number of generators out of range.";
02703                 return 0;
02704 
02705         if (numgen [i] < 0)
02706                 return 0;
02707         else
02708                 return numgen [i];
02709 } /* chaincomplex<euclidom>::getnumgen */
02710 
02711 template <class euclidom>
02712 inline int chaincomplex<euclidom>::dim () const
02713 {
02714         return len - 1;
02715 } /* chaincomplex<euclidom>::dim */
02716 
02717 template <class euclidom>
02718 inline const chain<euclidom> &chaincomplex<euclidom>::gethomgen (int q,
02719         int i) const
02720 {
02721         if ((q < 0) || (q >= len))
02722                 throw "Level for homology generators out of range.";
02723         if (!generators_initialized [q])
02724                 throw "Trying to get non-existent homology generators.";
02725         return generators [q]. getcol (i);
02726 } /* chaincomplex<euclidom>::getgen */
02727 
02728 template <class euclidom>
02729 inline void chaincomplex<euclidom>::simple_form (int which, bool quiet)
02730 {
02731 //      if ((which < 0) || (which >= len))
02732 //              throw "Trying to find the simple form of a wrong matrix.";
02733 
02734         // if the generator tracing matrices are not initialized, do it now
02735         if (generators)
02736         {
02737                 if (!generators_initialized [which])
02738                         generators [which]. identity (numgen [which]);
02739                 generators_initialized [which] = 1;
02740                 if ((which > 0) && (!generators_initialized [which - 1]))
02741                 {
02742                         generators [which - 1]. identity
02743                                 (numgen [which - 1]);
02744                         generators_initialized [which - 1] = 1;
02745                 }
02746         }
02747 
02748         // verify that the adjacent matrices have sufficient size
02749         if (which > 0)
02750         {
02751                 int n = boundary [which]. getnrows ();
02752                 mmatrix<euclidom> &other = boundary [which - 1];
02753                 if (other. getncols () < n)
02754                         other. define (other. getnrows (), n);
02755         }
02756         if (which < len - 1)
02757         {
02758                 int n = boundary [which]. getncols ();
02759                 mmatrix<euclidom> &other = boundary [which + 1];
02760                 if (other. getnrows () < n)
02761                         other. define (n, other. getncols ());
02762         }
02763 
02764         // compute simple form of the desired boundary matrix
02765         if (!quiet && which)
02766                 sout << "Reducing D_" << which << ": ";
02767         boundary [which]. simple_form (quiet);
02768         if (!quiet && which)
02769                 sout << '\n';
02770 
02771         return;
02772 } /* chaincomplex<euclidom>::simple_form */
02773 
02774 template <class euclidom>
02775 inline void chaincomplex<euclidom>::simple_form (const int *level,
02776         bool quiet)
02777 {
02778         for (int i = len - 1; i >= 0; -- i)
02779         {
02780                 if (!level || level [i] || (i && level [i - 1]))
02781                         simple_form (i, quiet);
02782         }
02783         return;
02784 } /* chaincomplex<euclidom>::simple_form */
02785 
02786 template <class euclidom>
02787 inline int chaincomplex<euclidom>::simple_homology (chain<euclidom> &result,
02788         int which) const
02789 {
02790         int g = boundary [which]. findcol (-1, 0);
02791         while (g >= 0)
02792         {
02793                 euclidom e;
02794                 if (which == dim ())
02795                         e = 0;
02796                 else
02797                         e = boundary [which + 1]. get (g, -1);
02798                 if (e == 0)
02799                 {
02800                         e = 1;
02801                         result. add (g, e);
02802                 }
02803                 else if (e. delta () > 1)
02804                         result. add (g, e. normalized ());
02805                 g = boundary [which]. findcol (-1, g + 1);
02806         }
02807 
02808         return which;
02809 } /* chaincomplex<euclidom>::simple_homology */
02810 
02811 template <class euclidom>
02812 inline int chaincomplex<euclidom>::simple_homology (chain<euclidom> *&result,
02813         const int *level) const
02814 {
02815         // if the chain complex is empty, then just set the result to NULL
02816         if (!len)
02817         {
02818                 result = NULL;
02819                 return dim ();
02820         }
02821 
02822         result = new chain<euclidom> [len];
02823         if (!result)
02824                 throw "Not enough memory to create homology chains.";
02825 
02826         for (int q = 0; q < len; ++ q)
02827         {
02828                 if (!level || level [q])
02829                         simple_homology (result [q], q);
02830         }
02831 
02832         return dim ();
02833 } /* chaincomplex<euclidom>::simple_homology */
02834 
02835 template <class euclidom>
02836 inline void chaincomplex<euclidom>::take_homology
02837         (const chain<euclidom> *hom_chain)
02838 {
02839         if (!hom_chain)
02840                 return;
02841         for (int q = 0; q < len; ++ q)
02842                 def_gen (q, hom_chain [q]. size ());
02843         return;
02844 } /* chaincomplex<euclidom>::take_homology */
02845 
02846 template <class euclidom>
02847 inline outputstream &chaincomplex<euclidom>::show_homology
02848         (outputstream &out, const chain<euclidom> *hom, const int *level)
02849         const
02850 {
02851         int max_level = len - 1;
02852         while ((max_level >= 0) && !hom [max_level]. size ())
02853                 -- max_level;
02854         ++ max_level;
02855         for (int q = 0; q < max_level; ++ q)
02856         {
02857                 if (!level || level [q])
02858                 {
02859                         out << "H_" << q << " = ";
02860                         chomp::homology::show_homology (out, hom [q]);
02861                         out << '\n';
02862                 }
02863         }
02864         return out;
02865 } /* chaincomplex<euclidom>::show_homology */
02866 
02867 template <class euclidom>
02868 inline std::ostream &chaincomplex<euclidom>::show_homology (std::ostream &out,
02869         const chain<euclidom> *hom, const int *level) const
02870 {
02871         outputstream tout (out);
02872         show_homology (tout, hom, level);
02873         return out;
02874 } /* chaincomplex<euclidom>::show_homology */
02875 
02876 template <class euclidom>
02877 inline outputstream &chaincomplex<euclidom>::show_generators
02878         (outputstream &out, const chain<euclidom> &list, int q) const
02879 {
02880         if (!generators || (q < 0) || (q >= len))
02881                 return out;
02882         for (int i = 0; i < list. size (); ++ i)
02883                 out << gethomgen (q, list. num (i)) << '\n';
02884         return out;
02885 } /* chaincomplex<euclidom>::show_generators */
02886 
02887 template <class euclidom>
02888 inline std::ostream &chaincomplex<euclidom>::show_generators (std::ostream &out,
02889         const chain<euclidom> &list, int q) const
02890 {
02891         outputstream tout (out);
02892         show_generators (tout, list, q);
02893         return out;
02894 } /* chaincomplex<euclidom>::show_generators */
02895 
02896 template <class euclidom>
02897 inline outputstream &chaincomplex<euclidom>::compute_and_show_homology
02898         (outputstream &out, chain<euclidom> *&hom, const int *level)
02899 {
02900         simple_form (level, false);
02901         simple_homology (hom, level);
02902         show_homology (out, hom, level);
02903         return out;
02904 } /* chaincomplex<euclidom>::compute_and_show_homology */
02905 
02906 template <class euclidom>
02907 inline std::ostream &chaincomplex<euclidom>::compute_and_show_homology
02908         (std::ostream &out, chain<euclidom> *&hom, const int *level)
02909 {
02910         outputstream tout (out);
02911         compute_and_show_homology (tout, hom, level);
02912         return out;
02913 } /* chaincomplex<euclidom>::compute_and_show_homology */
02914 
02915 // --------------------------------------------------
02916 
02918 template <class euclidom>
02919 inline std::ostream &operator << (std::ostream &out,
02920         const chaincomplex<euclidom> &c)
02921 {
02922         out << "chain complex" << '\n';
02923         out << "max dimension " << c. dim () << '\n';
02924         out << "dimension 0: " << c. getnumgen (0) << '\n';
02925         for (int i = 1; i <= c. dim (); ++ i)
02926         {
02927                 out << "dimension " << i << ": " << c. getnumgen (i) << '\n';
02928                 for (int j = 0; j < c. getnumgen (i); ++ j)
02929                 {
02930                         if (c. getboundary (i). getcol (j). size ())
02931                         {
02932                                 out << "\t# " << (j + 1) << " = " <<
02933                                         c. getboundary (i). getcol (j) <<
02934                                                 '\n';
02935                         }
02936                 }
02937         }
02938         return out;
02939 } /* operator << */
02940 
02941 
02942 // --------------------------------------------------
02943 // -------------------- chainmap --------------------
02944 // --------------------------------------------------
02945 
02949 template <class euclidom>
02950 class chainmap
02951 {
02952 public:
02955         chainmap (const chaincomplex<euclidom> &domain,
02956                 const chaincomplex<euclidom> &range);
02957 
02959         chainmap (const chainmap<euclidom> &c);
02960         
02962         chainmap<euclidom> &operator = (const chainmap<euclidom> &c);
02963 
02965         ~chainmap ();
02966 
02968         int dim () const;
02969 
02971         const mmatrix<euclidom> &operator [] (int i) const;
02972 
02975         void add (int q, int m, int n, euclidom e);
02976 
02978         void invert (void);
02979 
02982         void compose (const chainmap<euclidom> &m1,
02983                 const chainmap<euclidom> &m2);
02984 
02988         outputstream &show (outputstream &out,
02989                 const char *maplabel = "f", const char *xtxt = NULL,
02990                 const char *ytxt = NULL, const int *level = NULL) const;
02991 
02995         std::ostream &show (std::ostream &out,
02996                 const char *maplabel = "f", const char *xtxt = NULL,
02997                 const char *ytxt = NULL, const int *level = NULL) const;
02998 
03002         void take_homology (const chainmap<euclidom> &m,
03003                 const chain<euclidom> *hom_domain,
03004                 const chain<euclidom> *hom_range);
03005 
03009         outputstream &show_homology (outputstream &out,
03010                 const chain<euclidom> *hom_domain,
03011                 const chain<euclidom> *hom_range, const int *level = NULL,
03012                 const char *xtxt = NULL, const char *ytxt = NULL) const;
03013 
03017         std::ostream &show_homology (std::ostream &out,
03018                 const chain<euclidom> *hom_domain,
03019                 const chain<euclidom> *hom_range,
03020                 const int *level = NULL,
03021                 const char *xtxt = NULL, const char *ytxt = NULL)
03022                 const;
03023 
03024 private:
03026         int len;
03027 
03029         mmatrix<euclidom> *map;
03030 
03031 }; /* class chainmap */
03032 
03033 // --------------------------------------------------
03034 
03035 template <class euclidom>
03036 inline chainmap<euclidom>::chainmap (const chaincomplex<euclidom> &domain,
03037         const chaincomplex<euclidom> &range)
03038 {
03039         // set the dimension
03040         len = domain. len;
03041         if (range. len < domain. len)
03042                 len = range. len;
03043 
03044         // allocate new matrices
03045         if (len)
03046                 map = new mmatrix<euclidom> [len];
03047         else
03048                 map = NULL;
03049 
03050         for (int i = 0; i < len; ++ i)
03051         {
03052                 // define the size of the matrix (number of rows and columns)
03053                 map [i]. define (range. getnumgen (i),
03054                         domain. getnumgen (i));
03055 
03056                 // link the matrices to the ones in the chain complexes
03057                 domain. boundary [i]. dom_dom. add (map [i]);
03058                 range. boundary [i]. dom_img. add (map [i]);
03059                 if (i < domain. len - 1)
03060                         domain. boundary [i + 1]. img_dom. add (map [i]);
03061                 if (i < range. len - 1)
03062                         range. boundary [i + 1]. img_img. add (map [i]);
03063         }
03064 
03065         return;
03066 } /* chainmap<euclidom>::chainmap */
03067 
03068 template <class euclidom>
03069 inline chainmap<euclidom>::chainmap (const chainmap<euclidom> &c)
03070 {
03071         len = c. len;
03072         if (len)
03073                 map = new mmatrix<euclidom> [len];
03074         else
03075                 map = 0;
03076 
03077         for (int i = 0; i < len; ++ i)
03078                 map [i] = c. map [i];
03079 
03080         return;
03081 } /* chainmap<euclidom>::chainmap */
03082 
03083 template <class euclidom>
03084 inline chainmap<euclidom> &chainmap<euclidom>::operator =
03085         (const chainmap<euclidom> &c)
03086 {
03087         if (map)
03088                 delete [] map;
03089 
03090         len = c. len;
03091         if (len)
03092                 map = new mmatrix<euclidom> [len];
03093         else
03094                 map = 0;
03095 
03096         for (int i = 0; i < len; ++ i)
03097                 map [i] = c. map [i];
03098 
03099         return;
03100 } /* chainmap<euclidom>::operator = */
03101 
03102 template <class euclidom>
03103 inline chainmap<euclidom>::~chainmap ()
03104 {
03105         if (map)
03106                 delete [] map;
03107         return;
03108 } /* chainmap<euclidom>::~chainmap */
03109 
03110 template <class euclidom>
03111 inline int chainmap<euclidom>::dim () const
03112 {
03113         return len - 1;
03114 } /* chainmap<euclidom>::dim */
03115 
03116 template <class euclidom>
03117 inline const mmatrix<euclidom> &chainmap<euclidom>::operator [] (int i) const
03118 {
03119 //      if ((i < 0) || (i >= len))
03120 //              throw "Chain map level out of range.";
03121         return map [i];
03122 } /* chainmap<euclidom>::operator [] */
03123 
03124 template <class euclidom>
03125 inline void chainmap<euclidom>::add (int q, int m, int n, euclidom e)
03126 {
03127         map [q]. add (m, n, e);
03128         return;
03129 } /* chainmap<euclidom>::add */
03130 
03131 template <class euclidom>
03132 inline void chainmap<euclidom>::take_homology (const chainmap<euclidom> &m,
03133         const chain<euclidom> *hom_domain, const chain<euclidom> *hom_range)
03134 {
03135         if (!hom_domain || !hom_range)
03136                 return;
03137 
03138         for (int q = 0; q < len; ++ q)
03139         {
03140                 int dlen = hom_domain [q]. size ();
03141                 const chain<euclidom> &r = hom_range [q];
03142                 int rlen = r. size ();
03143                 map [q]. define (rlen, dlen);
03144                 // go through the homology generators in the domain
03145                 for (int i = 0; i < dlen; ++ i)
03146                 {
03147                         // retrieve the real number of the homology generator
03148                         int x = hom_domain [q]. num (i);
03149 
03150                         // get the image of this element by the chain map
03151                         const chain<euclidom> &img = m [q]. getcol (x);
03152 
03153                         // transform numbers in this image to hom. generators
03154                         int j = 0;
03155                         for (int k = 0; k < img. size (); ++ k)
03156                         {
03157                                 // find the current element in the range
03158                                 while ((j < rlen) &&
03159                                         (r. num (j) < img. num (k)))
03160                                         ++ j;
03161 
03162                                 // if found in the range, add it
03163                                 if ((j < rlen) &&
03164                                         (r. num (j) == img. num (k)))
03165                                         map [q]. add (j, i, img. coef (k));
03166                         }
03167                 }
03168         }
03169         return;
03170 } /* chainmap<euclidom>::take_homology */
03171 
03172 template <class euclidom>
03173 inline void chainmap<euclidom>::invert (void)
03174 {
03175         for (int q = 0; q < len; ++ q)
03176                 map [q]. invert ();
03177         return;
03178 } /* chainmap<euclidom>::invert */
03179 
03180 template <class euclidom>
03181 inline void chainmap<euclidom>::compose (const chainmap<euclidom> &m1,
03182         const chainmap<euclidom> &m2)
03183 {
03184         for (int q = 0; q < len; ++ q)
03185                 map [q]. multiply (m1. map [q], m2. map [q]);
03186         return;
03187 } /* chainmap<euclidom>::compose */
03188 
03189 template <class euclidom>
03190 inline outputstream &chainmap<euclidom>::show (outputstream &out,
03191         const char *maplabel, const char *xtxt, const char *ytxt,
03192         const int *level) const
03193 {
03194         for (int q = 0; q < len; ++ q)
03195         {
03196                 if (level && !level [q])
03197                         continue;
03198                 out << "Dim " << q << ":";
03199                 map [q]. showmap (out, maplabel, xtxt, ytxt);
03200         }
03201         return out;
03202 } /* chainmap<euclidom>::show */
03203 
03204 template <class euclidom>
03205 inline std::ostream &chainmap<euclidom>::show (std::ostream &out,
03206         const char *maplabel, const char *xtxt, const char *ytxt,
03207         const int *level) const
03208 {
03209         outputstream tout (out);
03210         show (tout, maplabel, xtxt, ytxt, level);
03211         return out;
03212 } /* chainmap<euclidom>::show */
03213 
03214 template <class euclidom>
03215 inline outputstream &chainmap<euclidom>::show_homology (outputstream &out,
03216         const chain<euclidom> *hom_domain,
03217         const chain<euclidom> *hom_range, const int *level,
03218         const char *xtxt, const char *ytxt) const
03219 {
03220         int max_len = len - 1;
03221         while ((max_len >= 0) && !hom_domain [max_len]. size ())
03222                 -- max_len;
03223         ++ max_len;
03224         for (int q = 0; q < max_len; ++ q)
03225         {
03226                 if (!level || level [q])
03227                 {
03228                         out << "Dim " << q << ":";
03229                         int hlen = hom_domain [q]. size ();
03230                         if (!hlen)
03231                                 out << "\t0" << '\n';
03232                         for (int i = 0; i < hlen; ++ i)
03233                         {
03234                                 out << "\tf (";
03235                                 if (xtxt)
03236                                         out << xtxt;
03237                                 out << (i + 1) << ") = ";
03238                                 map [q]. show_hom_col (out,
03239                                         hom_domain [q]. num (i),
03240                                         hom_range [q], ytxt);
03241                                 out << '\n';
03242                         }
03243                 }
03244         }
03245         return out;
03246 } /* chainmap<euclidom>::show_homology */
03247 
03248 template <class euclidom>
03249 inline std::ostream &chainmap<euclidom>::show_homology (std::ostream &out,
03250         const chain<euclidom> *hom_domain,
03251         const chain<euclidom> *hom_range, const int *level,
03252         const char *xtxt, const char *ytxt) const
03253 {
03254         outputstream tout (out);
03255         show_homology (tout, hom_domain, hom_range, level, xtxt, ytxt);
03256         return out;
03257 } /* chainmap<euclidom>::show_homology */
03258 
03259 // --------------------------------------------------
03260 
03262 template <class euclidom>
03263 inline std::ostream &operator << (std::ostream &out,
03264         const chainmap<euclidom> &m)
03265 {
03266         out << "chain map" << '\n';
03267         for (int i = 0; i <= m. dim (); ++ i)
03268         {
03269                 out << "dimension " << i << '\n';
03270                 for (int j = 0; j < m [i]. getncols (); ++ j)
03271                 {
03272                         if (m [i]. getcol (j). size ())
03273                         {
03274                                 out << "\t# " << (j + 1) << " = " <<
03275                                         m [i]. getcol (j) << '\n';
03276                         }
03277                 }
03278         }
03279         return out;
03280 } /* operator << */
03281 
03282 
03283 // --------------------------------------------------
03284 // -------------- displaying homology ---------------
03285 // --------------------------------------------------
03286 
03289 template <class euclidom>
03290 inline outputstream &show_homology (outputstream &out,
03291         const chain<euclidom> &c)
03292 {
03293         int countfree = 0;
03294         bool writeplus = false;
03295         for (int i = 0; i < c. size (); ++ i)
03296         {
03297                 if (c. coef (i). delta () == 1)
03298                         ++ countfree;
03299                 else
03300                 {
03301                         out << (writeplus ? " + " : "") <<
03302                                 euclidom::ringsymbol () << "_" <<
03303                                 c. coef (i);
03304                         writeplus = true;
03305                 }
03306 
03307                 if (countfree && ((i == c. size () - 1) ||
03308                         (c. coef (i + 1). delta () != 1)))
03309                 {
03310                         out << (writeplus ? " + " : "") <<
03311                                 euclidom::ringsymbol ();
03312                         if (countfree > 1)
03313                                 out << "^" << countfree;
03314                         countfree = 0;
03315                         writeplus = true;
03316                 }
03317         }
03318 
03319         // if there was nothing to show, then just show zero
03320         if (!c. size ())
03321                 out << "0";
03322 
03323         return out;
03324 } /* show_homology */
03325 
03328 template <class euclidom>
03329 inline std::ostream &show_homology (std::ostream &out,
03330         const chain<euclidom> &c)
03331 {
03332         outputstream tout (out);
03333         show_homology (tout, c);
03334         return out;
03335 } /* show_homology */
03336 
03337 
03338 } // namespace homology
03339 } // namespace chomp
03340 
03341 #endif // _CHOMP_HOMOLOGY_CHAINS_H_
03342 
03344