conindex.h

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////////
00002 ///
00003 /// @file conindex.h
00004 ///
00005 /// Conley index computation routines.
00006 /// This file contains the definition of routines for the computation
00007 /// of the Conley index using the CHomP library.
00008 ///
00009 /// @author Pawel Pilarczyk
00010 ///
00011 /////////////////////////////////////////////////////////////////////////////
00012 
00013 // Copyright (C) 1997-2008 by Pawel Pilarczyk.
00014 //
00015 // This file is part of my research software package.  This is free software;
00016 // you can redistribute it and/or modify it under the terms of the GNU
00017 // General Public License as published by the Free Software Foundation;
00018 // either version 2 of the License, or (at your option) any later version.
00019 //
00020 // This software is distributed in the hope that it will be useful,
00021 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 // GNU General Public License for more details.
00024 //
00025 // You should have received a copy of the GNU General Public License along
00026 // with this software; see the file "license.txt".  If not, write to the
00027 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00028 // MA 02111-1307, USA.
00029 
00030 // Started on July 19, 2006. Last revision: June 22, 2008.
00031 
00032 
00033 #ifndef _CMGRAPHS_CONINDEX_H_
00034 #define _CMGRAPHS_CONINDEX_H_
00035 
00036 
00037 // include some standard C++ header files
00038 #include <iostream>
00039 #include <algorithm>
00040 #include <new>
00041 
00042 // include selected header files from the CHomP library
00043 #include "chomp/system/textfile.h"
00044 #include "chomp/system/timeused.h"
00045 #include "chomp/homology/homology.h"
00046 
00047 // include selected header files from the CAPD library
00048 #include "interval/doubleInterval.h"
00049 
00050 // include local header files
00051 #include "config.h"
00052 
00053 
00054 // --------------------------------------------------
00055 // ------- the CLAPACK eigenvalues subroutine -------
00056 // --------------------------------------------------
00057 
00058 extern "C" {
00059 int dgeev_ (char *jobvl, char *jobvr, long int *n,
00060         double * a, long int *lda, double *wr, double *wi, double *vl, 
00061         long int *ldvl, double *vr, long int *ldvr, double *work, 
00062         long int *lwork, long int *info);
00063 }
00064 
00065 
00066 // --------------------------------------------------
00067 // ----------------- MapComputation -----------------
00068 // --------------------------------------------------
00069 
00070 /// The identity map class. This is a sample class that shows how one should
00071 /// define a function class for the "MapComputation" class below.
00072 class IdentityMap
00073 {
00074 public:
00075         /// Computes the image of a given box in terms of a rectangular box.
00076         int operator () (const interval *x, interval *y, int dim) const;
00077 
00078 }; /* class IdentityMap */
00079 
00080 inline int IdentityMap::operator () (const interval *x, interval *y, int dim)
00081         const
00082 {
00083         for (int i = 0; i < dim; ++ i)
00084                 y [i] = x [i];
00085         return 0;
00086 } /* IdentityMap::operator () */
00087 
00088 // --------------------------------------------------
00089 
00090 /// The undefined map class.
00091 class UndefinedMap
00092 {
00093 public:
00094         /// Computes the image of a given box in terms of a rectangular box.
00095         int operator () (const interval *x, interval *y, int dim) const;
00096 
00097 }; /* class UndefinedMap */
00098 
00099 inline int UndefinedMap::operator () (const interval *, interval *, int)
00100         const
00101 {
00102         throw "Trying to use an undefined map.";
00103         return 0;
00104 } /* UndefinedMap::operator () */
00105 
00106 // --------------------------------------------------
00107 
00108 /// The generic map computation routine that computes a rigorous
00109 /// cubical multivalued map based on a function that computes the image
00110 /// of intervals using interval arithmetic. The "mapcomp" class must have
00111 /// a static method called "compute" which is used to compute the map
00112 /// in interval arithmetic (see the sample class IdentityMap for details).
00113 template <class mapcomp, class cubetype,
00114         class cubsettype = chomp::homology::hashedset<cubetype> >
00115 class MapComputation
00116 {
00117 public:
00118         /// The default constructor.
00119         MapComputation (const double *_offset, const double *_width,
00120                 int _intwidth, const mapcomp &_M = mapcomp ());
00121 
00122         /// The destructor.
00123         ~MapComputation ();
00124 
00125         /// The operator for computing the image of a box in terms of a set
00126         /// of boxes (a multivalued cubical map). The integral coefficients
00127         /// of cubes are transformed to real numbers according to the
00128         /// rectangular area defined by offset from the origin and its width,
00129         /// as well as the width of this area in terms of integral
00130         /// coefficients. Note: 'intwidth' does not have to be a power of 2.
00131         int operator () (const cubetype &q, cubsettype &img) const;
00132 
00133         /// Using cache for the map.
00134         bool cache;
00135 
00136         /// Is cropping of images to the designated box in effect?
00137         mutable bool cropping;
00138 
00139         /// Was the image cropped at least once? Reset this variable
00140         /// to "false" in order to detect image cropping again.
00141         mutable bool cropped;
00142 
00143         /// The maximal image diameter encountered so far.
00144         /// Set this variable to zero to gather meaningful information.
00145         static int maxImgDiam;
00146 
00147         /// The maximal image volume encountered so far.
00148         /// Set this variable to zero to gather meaningful information.
00149         static int maxImgVol;
00150 
00151 private:
00152         /// The number of times the cache was used successfully.
00153         mutable int cacheused;
00154 
00155         /// The offset of the cubical rectangle.
00156         const double *offset;
00157 
00158         /// The width of the rectangle in each direction.
00159         const double *width;
00160 
00161         /// The width of the rectangle in terms of the number of cubes.
00162         int intwidth;
00163 
00164         /// The map used to compute an interval enclosure of the image
00165         /// of an interval box.
00166         const mapcomp &M;
00167 
00168         /// The cache domain.
00169         mutable cubsettype computed;
00170 
00171         /// The cache left vertex.
00172         mutable chomp::homology::multitable<cubetype> leftcache;
00173 
00174         /// The cache right vertex.
00175         mutable chomp::homology::multitable<cubetype> rightcache;
00176 
00177         /// Use interval arithmetic to compute the coordinate scope.
00178         /// Note: 'coord' may point to the same location
00179         /// as 'left' or 'right'.
00180         int compute (const typename cubetype::CoordType *coord, int dim,
00181                 typename cubetype::CoordType *left,
00182                 typename cubetype::CoordType *right) const;
00183 
00184 }; /* class MapComputation */
00185 
00186 // --------------------------------------------------
00187 
00188 template <class mapcomp, class cubetype, class cubsettype>
00189 int MapComputation<mapcomp,cubetype,cubsettype>::maxImgDiam;
00190 
00191 template <class mapcomp, class cubetype, class cubsettype>
00192 int MapComputation<mapcomp,cubetype,cubsettype>::maxImgVol;
00193 
00194 // --------------------------------------------------
00195 
00196 template <class mapcomp, class cubetype, class cubsettype>
00197 inline MapComputation<mapcomp,cubetype,cubsettype>::MapComputation
00198         (const double *_offset, const double *_width,
00199         int _intwidth, const mapcomp &_M):
00200         cache (false), cropping (false), cropped (false), cacheused (0),
00201         offset (_offset), width (_width), intwidth (_intwidth), M (_M)
00202 {
00203         return;
00204 } /* MapComputation::MapComputation */
00205 
00206 template <class mapcomp, class cubetype, class cubsettype>
00207 inline MapComputation<mapcomp,cubetype,cubsettype>::~MapComputation ()
00208 {
00209         // DEBUG
00210 //      if (cache && !computed. empty ())
00211 //              chomp::homology::sbug << "MAP: " << computed. size () <<
00212 //                      " images cached, used " << cacheused << " times.\n";
00213 
00214         // DEBUG: Save the map.
00215         if (cache && false)
00216         {
00217                 std::ofstream f ("f.map");
00218                 for (int i = 0; i < computed. size (); ++ i)
00219                 {
00220                         typename cubetype::CoordType c [cubetype::MaxDim];
00221                         f << "[" << computed [i];
00222                         computed [i]. coord (c);
00223                         for (int j = 0; j < computed [i]. dim (); ++ j)
00224                                 ++ c [j];
00225                         f << cubetype (c, computed [i]. dim ()) << "] ";
00226                         f << "[" << leftcache [i] << rightcache [i] << "]\n";
00227                 }
00228         }
00229         return;
00230 } /* MapComputation::~MapComputation */
00231 
00232 template <class mapcomp, class cubetype, class cubsettype>
00233 inline int MapComputation<mapcomp,cubetype,cubsettype>::compute
00234         (const typename cubetype::CoordType *coord, int dim,
00235         typename cubetype::CoordType *left,
00236         typename cubetype::CoordType *right) const
00237 {
00238         // compute the actual box corresponding to the cube
00239         std::auto_ptr<interval> xPtr (new interval [dim]);
00240         interval *x = xPtr. get ();
00241         for (int i = 0; i < dim; ++ i)
00242         {
00243                 x [i] = interval (coord [i], coord [i] + 1);
00244                 x [i] /= intwidth;
00245                 x [i] *= width [i];
00246                 x [i] += offset [i];
00247         }
00248 
00249         // compute the image of this box
00250         std::auto_ptr<interval> yPtr (new interval [dim]);
00251         interval *y = yPtr. get ();
00252         M (x, y, dim);
00253 
00254         // rescale the image box to the integer coordinates and make sure
00255         // that the actual image is contained in the INTERIOR of the box
00256         for (int i = 0; i < dim; ++ i)
00257         {
00258                 y [i] -= offset [i];
00259                 y [i] /= width [i];
00260                 y [i] *= intwidth;
00261 
00262                 double left_b = y [i]. leftBound ();
00263                 left [i] =
00264                         static_cast<typename cubetype::CoordType> (left_b);
00265                 for (int j = 0; (j < 4) && (left [i] >= left_b); ++ j)
00266                         -- left [i];
00267                 if ((left [i] >= left_b) || (left_b - left [i] > 2))
00268                         throw "Map computation: Left bound out of range.";
00269 
00270                 double right_b = y [i]. rightBound ();
00271                 right [i] =
00272                         static_cast<typename cubetype::CoordType> (right_b);
00273                 for (int j = 0; (j < 4) && (right [i] <= right_b); ++ j)
00274                         ++ right [i];
00275                 if ((right [i] <= right_b) || (right [i] - right_b > 2))
00276                         throw "Map computation: Right bound out of range.";
00277         }
00278 
00279         return 0;
00280 } /* MapComputation::compute */
00281 
00282 template <class mapcomp, class cubetype, class cubsettype>
00283 inline int MapComputation<mapcomp,cubetype,cubsettype>::operator ()
00284         (const cubetype &q, cubsettype &img) const
00285 {
00286         typedef typename cubetype::CoordType coordType;
00287 
00288         // prepare arrays for the range of the image box
00289         int dim = q. dim ();
00290         std::auto_ptr<coordType> leftPtr (new coordType [dim]);
00291         coordType *left = leftPtr. get ();
00292         std::auto_ptr<coordType> rightPtr (new coordType [dim]);
00293         coordType *right = rightPtr. get ();
00294 
00295         // check if the image of this cube has already been computed
00296         int number = cache ? computed. getnumber (q) : -1;
00297 
00298         // compute the image of this box if necessary
00299         if (number < 0)
00300         {
00301                 q. coord (left);
00302                 compute (left, dim, left, right);
00303 
00304                 // store this image in the cache if requested to
00305                 if (cache)
00306                 {
00307                         leftcache [computed. size ()] = cubetype (left, dim);
00308                         rightcache [computed. size ()] =
00309                                 cubetype (right, dim);
00310                         computed. add (q);
00311                 }
00312         }
00313 
00314         // use the cached values for the image of this box
00315         else
00316         {
00317                 ++ cacheused;
00318                 leftcache [number]. coord (left);
00319                 rightcache [number]. coord (right);
00320         }
00321 
00322         // crop the image of this box to the given area if necessary
00323         if (cropping)
00324         {
00325                 for (int i = 0; i < dim; ++ i)
00326                 {
00327                         if (left [i] < 0)
00328                         {
00329                                 left [i] = 0;
00330                                 if (right [i] <= left [i])
00331                                         right [i] = left [i] + 1;
00332                                 cropped = true;
00333                         }
00334                         if (right [i] > intwidth)
00335                         {
00336                                 right [i] = intwidth;
00337                                 if (left [i] >= right [i])
00338                                         left [i] = right [i] - 1;
00339                                 cropped = true;
00340                         }
00341                 }
00342         }
00343 
00344         // make sure that the size of the image is reasonably small
00345         int volume = 1;
00346         for (int i = 0; i < dim; ++ i)
00347         {
00348                 int size = right [i] - left [i];
00349                 if (maxImgDiam < size)
00350                         maxImgDiam = size;
00351                 if (size > maxImageDiameter)
00352                         throw "Excessive diameter of box image.";
00353                 volume *= size;
00354                 if (volume > maxImageVolume)
00355                         throw "Excessive volume of box image.";
00356         }
00357         if (maxImgVol < volume)
00358                 maxImgVol = volume;
00359 
00360         // cover the image box with cubes
00361         chomp::homology::tRectangle<typename cubetype::CoordType>
00362                 r (left, right, dim);
00363         const typename cubetype::CoordType *c;
00364         while ((c = r. get ()) != 0)
00365         {
00366                 img. add (cubetype (c, dim));
00367         }
00368 
00369         return 0;
00370 } /* MapComputation::operator () */
00371 
00372 // --------------------------------------------------
00373 
00374 /// The undefined map computation class.
00375 template<class cubetype, class cubsettype>
00376 class UndefinedComputation
00377 {
00378 public:
00379         int operator () (const cubetype &q, cubsettype &img) const;
00380 
00381 }; /* class UndefinedComputation */
00382 
00383 template<class cubetype, class cubsettype>
00384 int UndefinedComputation<cubetype, cubsettype>::operator ()
00385         (const cubetype &q, cubsettype &img) const
00386 {
00387         throw "Trying to use undefined map computation.";
00388         return 0;
00389 } /* UndefinedComputation::operator () */
00390 
00391 
00392 // --------------------------------------------------
00393 // ------------------- INDEX PAIR -------------------
00394 // --------------------------------------------------
00395 // The interface of a class that feeds cubes to the
00396 // Conley index computation procedure.
00397 
00398 /// The empty index pair class simulates an empty index pair.
00399 /// This is a general template for you to build an appropriate index pair.
00400 /// This might just be an interface to access an array of cubes in which
00401 /// the isolating neighborhood occupies the front of the array, and then
00402 /// cubes that form the exit set follow. Afterwards, all the other cubes
00403 /// that appear in the images of those two groups of cubes are listed.
00404 class EmptyIndexPair
00405 {
00406 public:
00407         /// Returns the dimension of the underlying space.
00408         int dim () const {return 1;}
00409 
00410         /// Returns the number of cubes in the isolating neighborhood.
00411         int countInv () const {return 0;}
00412 
00413         /// Returns the number of cubes in the exit set.
00414         int countExit () const {return 0;}
00415 
00416         /// Returns the coordinates of the n-th cube
00417         /// (first Inv, then Exit, followed by outside).
00418         int getcube (int n, int *coord) const {return 0;}
00419 
00420         /// Returns the number of cubes in the image of the n-th cube.
00421         int imgcount (int n) const {return 0;}
00422 
00423         /// Returns the number of the n-th cube in the image.
00424         int getimgcube (int n, int i) const {return 0;}
00425 
00426 }; /* class EmptyIndexPair */
00427 
00428 // --------------------------------------------------
00429 
00430 /// A generic class that computes an index pair given the isolating
00431 /// neighborhood and a means to compute the multivalued cubical map.
00432 template <class mapcomp, class cubetype = chomp::homology::cube,
00433         class cubsettype = chomp::homology::hashedset<cubetype> >
00434 class IndexPair
00435 {
00436 public:
00437         /// The only allowed constructor.
00438         IndexPair (const mapcomp &_M = mapcomp ());
00439 
00440         /// Adds a cube to S.
00441         int add (const cubetype &q);
00442 
00443         /// Returns the dimension of the phase space.
00444         int dim () const;
00445 
00446         /// Returns the number of cubes in the isolating neighborhood.
00447         int countInv () const;
00448         
00449         /// Returns the invariant part as a set of cubes.
00450         const cubsettype &getInv () const;
00451 
00452         /// Returns the number of cubes in the exit set.
00453         int countExit () const;
00454 
00455         /// Returns the exit set as a set of cubes.
00456         const cubsettype &getExit () const;
00457 
00458         /// Retrieves the coordinates of the n-th cube.
00459         int getcube (int n, int *coord) const;
00460 
00461         /// Returns the number of cubes in the image of the n-th cube
00462         /// (which is either in S, or in the exit set).
00463         int imgcount (int n) const;
00464 
00465         /// Returns the number of the i-th cube in the image of the n-th cube.
00466         int getimgcube (int n, int i) const;
00467 
00468         /// Computes the map on one cube. If the cube is in S, then its image
00469         /// that sticks out of S is added to the exit set.
00470         int compute (int n);
00471 
00472         /// Computes the map on the entire set S, and also on the exit set,
00473         /// so that the whole information necessary to compute the index map
00474         /// on this index pair is obatined and stored within this object.
00475         int compute ();
00476 
00477         /// Clears the sets and the stored map.
00478         int clear ();
00479 
00480 private:
00481         /// The isolating neighborhood whose Conley index is computed.
00482         cubsettype S;
00483 
00484         /// The image of S without S.
00485         cubsettype exitSet;
00486 
00487         /// Additional images of cubes fromthe exit set.
00488         cubsettype outside;
00489 
00490         /// The multivalued cubical map that has been computed so far.
00491         chomp::homology::mvmap<cubetype,cubetype> F;
00492 
00493         /// The map object.
00494         const mapcomp &M;
00495 
00496 }; /* class IndexPair */
00497 
00498 // --------------------------------------------------
00499 
00500 template <class mapcomp, class cubetype, class cubsettype>
00501 inline IndexPair<mapcomp,cubetype,cubsettype>::IndexPair
00502         (const mapcomp &_M): M (_M)
00503 {
00504         return;
00505 } /* IndexPair::IndexPair */
00506 
00507 template <class mapcomp, class cubetype, class cubsettype>
00508 inline int IndexPair<mapcomp,cubetype,cubsettype>::dim () const
00509 {
00510         if (!S. empty ())
00511                 return S [0]. dim ();
00512         else if (!exitSet. empty ())
00513                 return exitSet [0]. dim ();
00514         else
00515                 return -1;
00516 } /* IndexPair::dim */
00517 
00518 template <class mapcomp, class cubetype, class cubsettype>
00519 inline int IndexPair<mapcomp,cubetype,cubsettype>::countInv () const 
00520 {
00521         return S. size ();
00522 } /* IndexPair::countInv */
00523 
00524 template <class mapcomp, class cubetype, class cubsettype>
00525 inline const cubsettype &IndexPair<mapcomp,cubetype,cubsettype>::getInv ()
00526         const
00527 {
00528         return S;
00529 } /* IndexPair::getInv */
00530 
00531 template <class mapcomp, class cubetype, class cubsettype>
00532 inline int IndexPair<mapcomp,cubetype,cubsettype>::countExit () const 
00533 {
00534         return exitSet. size ();
00535 } /* IndexPair::countExit */
00536 
00537 template <class mapcomp, class cubetype, class cubsettype>
00538 inline const cubsettype &IndexPair<mapcomp,cubetype,cubsettype>::getExit ()
00539         const
00540 {
00541         return exitSet;
00542 } /* IndexPair::getExit */
00543 
00544 template <class mapcomp, class cubetype, class cubsettype>
00545 inline int IndexPair<mapcomp,cubetype,cubsettype>::getcube
00546         (int n, int *coord) const
00547 {
00548         int countS = S. size ();
00549         if (n < countS)
00550         {
00551                 S [n]. coord (coord);
00552                 return 0;
00553         }
00554         int countExit = exitSet. size ();
00555         if (n < countS + countExit)
00556         {
00557                 exitSet [n - countS]. coord (coord);
00558                 return 0;
00559         }
00560         outside [n - countS - countExit]. coord (coord);
00561         return 0;
00562 } /* IndexPair::getcube */
00563 
00564 template <class mapcomp, class cubetype, class cubsettype>
00565 inline int IndexPair<mapcomp,cubetype,cubsettype>::imgcount (int n) const
00566 {
00567         int countS = S. size ();
00568         if (n < countS)
00569                 return F (S [n]). size ();
00570         else
00571                 return F (exitSet [n - countS]). size ();
00572 } /* IndexPair::imgcount */
00573 
00574 template <class mapcomp, class cubetype, class cubsettype>
00575 inline int IndexPair<mapcomp,cubetype,cubsettype>::getimgcube
00576         (int n, int i) const
00577 {
00578         int countS = S. size ();
00579         const cubetype &q = (n < countS) ? (F (S [n])) [i] :
00580                 (F (exitSet [n - countS])) [i];
00581         int num = S. getnumber (q);
00582         if (num >= 0)
00583                 return num;
00584         num = exitSet. getnumber (q);
00585         if (num >= 0)
00586                 return (countS + num);
00587         int countExit = exitSet. size ();
00588         num = outside. getnumber (q);
00589         if (num >= 0)
00590                 return (countS + countExit + num);
00591         throw "Index pair not prepared.";
00592 //      num = countS + exitSet. size () + outside. size ();
00593 //      outside. add (q);
00594 //      return num;
00595 } /* IndexPair::getimgcube */
00596 
00597 // --------------------------------------------------
00598 
00599 template <class mapcomp, class cubetype, class cubsettype>
00600 inline int IndexPair<mapcomp,cubetype,cubsettype>::compute (int n)
00601 {
00602         // determine the cube whose image is to be computed
00603         int countS = S. size ();
00604         const cubetype &q = (n < countS) ? S [n] : exitSet [n - countS];
00605 
00606         // compute the image of this cube
00607         cubsettype img;
00608         M (q, img);
00609         F [q]. add (img);
00610 
00611         // add the cubes in the image to the exit set or to the outside set
00612         for (int i = 0; i < img. size (); ++ i)
00613         {
00614                 if ((n < countS) && !S. check (img [i]))
00615                         exitSet. add (img [i]);
00616                 if (n >= countS)
00617                 {
00618                         if (S. check (img [i]))
00619                                 throw "Wrong index pair detected.";
00620                         else if (!exitSet. check (img [i]))
00621                                 outside. add (img [i]);
00622                 }
00623         }
00624 
00625         // verify if the size of the index pair is within the given limit
00626         if (countS + exitSet. size () + outside. size () > maxIndexPairSize)
00627                 throw "Excessive index pair size.";
00628 
00629         return 0;
00630 } /* IndexPair::compute */
00631 
00632 template <class mapcomp, class cubetype, class cubsettype>
00633 inline int IndexPair<mapcomp,cubetype,cubsettype>::compute ()
00634 {
00635         chomp::homology::sbug << "Computing the index pair... ";
00636 
00637         int countS = S. size ();
00638         for (int i = 0; i < countS; ++ i)
00639                 compute (i);
00640         int countSX = countS + exitSet. size ();
00641         for (int i = countS; i < countSX; ++ i)
00642                 compute (i);
00643 
00644         chomp::homology::sbug << S. size () << " + " << exitSet. size () <<
00645                 " + " << outside. size () << " cubes.\n";
00646         return 0;
00647 } /* IndexPair::compute */
00648 
00649 template <class mapcomp, class cubetype, class cubsettype>
00650 inline int IndexPair<mapcomp,cubetype,cubsettype>::add (const cubetype &q)
00651 {
00652         typename cubetype::CoordType coord [cubetype::MaxDim];
00653         q. coord (coord);
00654         cubetype r (coord, q. dim ());
00655         S. add (r);
00656         return 0;
00657 } /* IndexPair::add */
00658 
00659 template <class mapcomp, class cubetype, class cubsettype>
00660 inline int IndexPair<mapcomp,cubetype,cubsettype>::clear ()
00661 {
00662         cubsettype empty;
00663         S = empty;
00664         exitSet = empty;
00665         outside = empty;
00666         chomp::homology::mvmap<cubetype,cubetype> nomap;
00667         F = nomap;
00668         return 0;
00669 } /* IndexPair::clear */
00670 
00671 
00672 // --------------------------------------------------
00673 // ------------------ CONLEY INDEX ------------------
00674 // --------------------------------------------------
00675 
00676 template <class IndexPair, class euclidom>
00677 class ConleyIndex;
00678 
00679 template <class IndexPair, class euclidom>
00680 std::istream &operator >> (std::istream &in,
00681         ConleyIndex<IndexPair,euclidom> &c);
00682 
00683 template <class IndexPair, class euclidom>
00684 std::ostream &operator << (std::ostream &out,
00685         const ConleyIndex<IndexPair,euclidom> &c);
00686 
00687 /// The class that computes and returns properties of the Conley index.
00688 /// The index pair object is used to get the cubical index pair.
00689 template <class IndexPair = EmptyIndexPair,
00690         class euclidom = chomp::homology::integer>
00691 class ConleyIndex
00692 {
00693 public:
00694         /// The default constructor.
00695         ConleyIndex (const IndexPair *c = 0);
00696 
00697         /// The copy constructor.
00698         ConleyIndex (const ConleyIndex<IndexPair,euclidom> &c);
00699 
00700         /// The destructor.
00701         ~ConleyIndex ();
00702 
00703         /// The assignment operator.
00704         ConleyIndex<IndexPair,euclidom> &operator =
00705                 (const ConleyIndex<IndexPair,euclidom> &c);
00706 
00707         /// Sets the index pair to be used to compute the Conley index.
00708         void setIndexPair (const IndexPair *f);
00709 
00710         /// Computes the Conley index. If requested, uses the two-layer
00711         /// construction. Otherwise, first tries the flat model, and switches
00712         /// to the two-layer construction only in the case of failure.
00713         int compute (bool twolayer = false);
00714 
00715         /// Reduces the index map using some shift equivalences to certain
00716         /// extent. Shrinks the matrices and generators if requested to.
00717         int reduce (bool shrink = true);
00718         
00719         /// Truncates the Conley index to the new top level.
00720         void truncate (int newlevel);
00721 
00722         /// Computes the eigenvalues of the index map.
00723         /// The eigenvalues are appended to the given vectors of doubles
00724         /// with the "push_back" method.
00725         /// Returns the number of eigenvalues or -1 in case of failure.
00726         int eigenvalues (int level, std::vector<double> &Re,
00727                 std::vector<double> &Im, bool nonzero = true,
00728                 bool sorted = true) const;
00729 
00730         /// Verifies if the index is trivial. Returns true if yes,
00731         /// false if it is non-trivial. Note: This information is tabulated.
00732         bool trivial () const;
00733 
00734         /// Retrieves the nth Betti number.
00735         int BettiNumber (int n) const;
00736 
00737         /// Retrieves the 'i'th [torsion] coefficient at the nth level.
00738         /// Returns 0 if 'i' is beyond the available scope.
00739         euclidom Coefficient (int n, int i) const;
00740 
00741         /// Retrieves the top level, or the maximal dimension of the index.
00742         /// The numbers of available levels are from 0 to dim inclusive.
00743         /// Returns -1 if the index is undefined.
00744         int dim () const;
00745 
00746         /// Retrieves the matrix of the index map at the given level.
00747         /// Returns 0 if the map at this level is zero.
00748         const chomp::homology::mmatrix<euclidom> *Map (int n) const;
00749 
00750         /// Retrieves a human-readable text representation of the map.
00751         std::string MapString (int n, const char *newline = "\n") const;
00752 
00753         /// Retrieves a human-readable text showing the eigenvalues.
00754         std::string EigenString (int n) const;
00755 
00756         /// Retrieves a human-readable text representation of the homology.
00757         std::string HomString () const;
00758 
00759         /// Defines the Conley index by the given Betti numbers
00760         /// and the given maps in homology.
00761         void define (const int *betti,
00762                 const chomp::homology::mmatrix<euclidom> *matr,
00763                 int _toplevel);
00764 
00765         /// Defines the Conley index by the given Betti numbers
00766         /// and adds the identity map.
00767         void define (const int *betti, int _toplevel);
00768 
00769 private:
00770         /// An object that feeds this class with cubes.
00771         const IndexPair *cf;
00772 
00773         /// The number of the top homology level.
00774         int toplevel;
00775 
00776         /// The torsion coefficients of the corresponding homology
00777         /// generators. If delta () == 1, then no torsion.
00778         std::vector<std::vector<euclidom> > coef;
00779 
00780         /// The matrices of the index map at each level.
00781         chomp::homology::mmatrix<euclidom> *indmap;
00782 
00783         /// Converts the Conley index to a string (without the index pair).
00784         friend std::ostream &operator << <> (std::ostream &out,
00785                 const ConleyIndex<IndexPair,euclidom> &c);
00786 
00787         /// Retrieves the Conley index from a string
00788         /// (without the index pair).
00789         friend std::istream &operator >> <> (std::istream &in,
00790                 ConleyIndex<IndexPair,euclidom> &c);
00791 
00792         /// Rounds a real number to the given precision.
00793         /// If the absolute value of the number is below the given threshold
00794         /// then the number is truncated to 0.
00795         static double round (double x, double epsilon, double threshold);
00796 
00797         /// Variable that stores the tabulated information on whether
00798         /// the index is nontrivial. Values used: -1 = unknown, 0 = trivial,
00799         /// 1 = nontrivial.
00800         mutable int nontrivialindex;
00801 
00802 }; /* class ConleyIndex */
00803 
00804 // --------------------------------------------------
00805 
00806 /// An auxiliary class that represents complex numbers.
00807 /// It is used in the procedure for computing eigenvalues.
00808 struct ppComplex
00809 {
00810         double re, im;
00811         ppComplex (double _re, double _im): re (_re), im (_im) {}
00812 
00813 }; /* struct ppComplex */
00814 
00815 inline bool operator < (const ppComplex &x, const ppComplex &y)
00816 {
00817         if (x. re < y. re)
00818                 return true;
00819         else if (x. re > y. re)
00820                 return false;
00821         return (x. im < y. im);
00822 } /* operator < */
00823 
00824 // --------------------------------------------------
00825 
00826 template <class IndexPair, class euclidom>
00827 inline ConleyIndex<IndexPair,euclidom>::ConleyIndex (const IndexPair *c)
00828 {
00829         cf = c;
00830         toplevel = -1;
00831         indmap = 0;
00832         nontrivialindex = -1;
00833         return;
00834 } /* ConleyIndex::ConleyIndex */
00835 
00836 template <class IndexPair, class euclidom>
00837 inline ConleyIndex<IndexPair,euclidom>::ConleyIndex
00838         (const ConleyIndex<IndexPair,euclidom> &c)
00839 {
00840         cf = c. cf;
00841         toplevel = c. toplevel;
00842         coef = c. coef;
00843         if (toplevel >= 0)
00844                 indmap = new chomp::homology::mmatrix<euclidom> [toplevel + 1];
00845         else
00846                 indmap = 0;
00847         for (int i = 0; i <= toplevel; ++ i)
00848                 indmap [i] = c. indmap [i];
00849         nontrivialindex = c. nontrivialindex;
00850         return;
00851 } /* ConleyIndex::ConleyIndex */
00852 
00853 template <class IndexPair, class euclidom>
00854 inline ConleyIndex<IndexPair,euclidom> &
00855         ConleyIndex<IndexPair,euclidom>::operator =
00856         (const ConleyIndex<IndexPair,euclidom> &c)
00857 {
00858         cf = c. cf;
00859         toplevel = c. toplevel;
00860         coef = c. coef;
00861         if (indmap)
00862                 delete [] indmap;
00863         if (toplevel >= 0)
00864                 indmap = new chomp::homology::mmatrix<euclidom> [toplevel + 1];
00865         else
00866                 indmap = 0;
00867         for (int i = 0; i <= toplevel; ++ i)
00868                 indmap [i] = c. indmap [i];
00869         nontrivialindex = c. nontrivialindex;
00870         return *this;
00871 } /* ConleyIndex::operator = */
00872 
00873 template <class IndexPair, class euclidom>
00874 inline ConleyIndex<IndexPair,euclidom>::~ConleyIndex ()
00875 {
00876         if (indmap)
00877                 delete [] indmap;
00878         return;
00879 } /* ConleyIndex::~ConleyIndex */
00880 
00881 template <class IndexPair, class euclidom>
00882 inline void ConleyIndex<IndexPair,euclidom>::setIndexPair
00883         (const IndexPair *f)
00884 {
00885         cf = f;
00886         return;
00887 } /* ConleyIndex::setIndexPair */
00888 
00889 template <class IndexPair, class euclidom>
00890 double ConleyIndex<IndexPair,euclidom>::round (double x, double epsilon,
00891         double threshold)
00892 {
00893         if ((x < 0) && (x > -threshold))
00894                 return 0;
00895         if ((x > 0) && (x < threshold))
00896                 return 0;
00897         x /= epsilon;
00898         long xl = static_cast<long> (x);
00899         if (xl - x > 0.5)
00900                 -- xl;
00901         else if (x - xl > 0.5)
00902                 ++ xl;
00903         return (xl * epsilon);
00904 } /* ConleyIndex::round */
00905 
00906 template <class IndexPair, class euclidom>
00907 inline int ConleyIndex<IndexPair,euclidom>::BettiNumber (int n) const
00908 {
00909         if ((n < 0) || (n > toplevel))
00910                 return 0;
00911         int size = coef [n]. size ();
00912         int count = 0;
00913         for (int i = 0; i < size; ++ i)
00914                 if (coef [n] [i]. delta () == 1)
00915                         ++ count;
00916         return count;
00917 } /* ConleyIndex::BettiNumber */
00918 
00919 template <class IndexPair, class euclidom>
00920 inline const chomp::homology::mmatrix<euclidom> *
00921         ConleyIndex<IndexPair,euclidom>::Map (int n) const
00922 {
00923         if (!indmap || (n < 0) || (n > toplevel))
00924                 return 0;
00925         return (indmap + n);
00926 } /* ConleyIndex::Map */
00927 
00928 template <class IndexPair, class euclidom>
00929 inline euclidom ConleyIndex<IndexPair,euclidom>::Coefficient
00930         (int n, int i) const
00931 {
00932         euclidom zero;
00933         zero = 0;
00934         if ((n < 0) || (n > toplevel))
00935                 return zero;
00936         int size = coef [n]. size ();
00937         if ((i < 0) || (i >= size))
00938                 return zero;
00939         return coef [n] [i];
00940 } /* ConleyIndex::Coefficient */
00941 
00942 template <class IndexPair, class euclidom>
00943 inline int ConleyIndex<IndexPair,euclidom>::dim () const
00944 {
00945         return toplevel;
00946 } /* ConleyIndex::dim */
00947 
00948 template <class IndexPair, class euclidom>
00949 inline std::string ConleyIndex<IndexPair,euclidom>::MapString (int n,
00950         const char *newline) const
00951 {
00952         if (!indmap || (n < 0) || (n > toplevel))
00953                 return std::string ();
00954         std::ostringstream out;
00955         const chomp::homology::mmatrix<euclidom> &m = indmap [n];
00956         bool nonzero = false;
00957         for (int j = 0; j < m. getncols (); j ++)
00958                 if (m. getcol (j). size ())
00959                 {
00960                         if (!nonzero)
00961                         {
00962                                 out << "Map " << n << ":" << newline;
00963                                 nonzero = true;
00964                         }
00965                         out << "#" << (j + 1) << " = " << m. getcol (j) <<
00966                                 newline;
00967                 }
00968         if (!nonzero)
00969                 out << "Map" << n << " = 0" << newline;
00970         return out. str ();
00971 } /* ConleyIndex::MapString */
00972 
00973 template <class IndexPair, class euclidom>
00974 inline std::string ConleyIndex<IndexPair,euclidom>::HomString () const
00975 {
00976         if (coef. size () <= 0)
00977                 return std::string ("0");
00978         std::ostringstream out;
00979         int coefsize = coef. size ();
00980         for (int i = 0; i < coefsize; ++ i)
00981         {
00982                 bool nonzero = false;
00983                 if (i)
00984                         out << ", ";
00985                 int counter = 0;
00986                 int size = coef [i]. size ();
00987                 for (int j = 0; j < size; ++ j)
00988                 {
00989                         if (coef [i] [j]. delta () > 1)
00990                         {
00991                                 if (nonzero)
00992                                         out << "+";
00993                                 if (counter)
00994                                 {
00995                                         out << "Z";
00996                                         if (counter > 1)
00997                                                 out << "^" << counter;
00998                                         out << "+";
00999                                         counter = 0;
01000                                 }
01001                                 out << "Z_" << coef [i] [j];
01002                                 nonzero = true;
01003                         }
01004                         else
01005                                 ++ counter;
01006                 }
01007                 if (counter)
01008                 {
01009                         if (nonzero)
01010                                 out << "+";
01011                         out << "Z";
01012                         if (counter > 1)
01013                                 out << "^" << counter;
01014                         nonzero = true;
01015                 }
01016                 if (!nonzero)
01017                         out << "0";
01018         }
01019         return out. str ();
01020 } /* ConleyIndex::HomString */
01021 
01022 template <class IndexPair, class euclidom>
01023 inline int ConleyIndex<IndexPair,euclidom>::compute (bool twolayer)
01024 {
01025         using namespace chomp::homology;
01026 
01027         // measure the time of creating data structures
01028         sbug << "Preparing to compute the Conley index...\n";
01029         timeused prepTime;
01030 
01031         // create the cubical map with the shifted dimension or not
01032         int shifted = twolayer ? 1 : 0; // raise dimension (see below)
01033         SetOfCubes X, A, Y, B;
01034         SetOfCubes Xflat, Aflat;
01035         int dim = cf -> dim ();
01036         int countS = cf -> countInv ();
01037         int c [Cube::MaxDim];
01038         typename Cube::CoordType coord [Cube::MaxDim];
01039         coord [dim] = 2;
01040         for (int i = 0; i < countS; ++ i)
01041         {
01042                 cf -> getcube (i, c);
01043                 for (int j = 0; j < dim; ++ j)
01044                 {
01045                         coord [j] = static_cast<typename Cube::CoordType>
01046                                 (c [j]);
01047                         if (coord [j] != c [j])
01048                                 throw "Cube coordinatess out of range.";
01049                 }
01050                 Cube q (coord, dim + shifted);
01051                 X. add (q);
01052                 Y. add (q);
01053                 Cube qflat (coord, dim);
01054                 Xflat. add (qflat);
01055         }
01056         int countExit = cf -> countExit ();
01057         coord [dim] = 1;
01058         for (int i = 0; i < countExit; ++ i)
01059         {
01060                 cf -> getcube (countS + i, c);
01061                 for (int j = 0; j < dim; ++ j)
01062                 {
01063                         coord [j] = static_cast<typename Cube::CoordType>
01064                                 (c [j]);
01065                         if (coord [j] != c [j])
01066                                 throw "Cube coordinatess out of range.";
01067                 }
01068                 Cube q (coord, dim + shifted);
01069                 A. add (q);
01070                 B. add (q);
01071                 Cube qflat (coord, dim);
01072                 Aflat. add (qflat);
01073         }
01074         coord [dim] = 0;
01075         for (int i = 0; i < countExit; ++ i)
01076         {
01077                 int countImg = cf -> imgcount (countS + i);
01078                 for (int j = 0; j < countImg; ++ j)
01079                 {
01080                         int n = cf -> getimgcube (countS + i, j);
01081                         cf -> getcube (n, c);
01082                         for (int j = 0; j < dim; ++ j)
01083                         {
01084                                 coord [j] = static_cast<typename
01085                                         Cube::CoordType> (c [j]);
01086                                 if (coord [j] != c [j])
01087                                         throw "Coordinatess out of range.";
01088                         }
01089                         Cube q (coord, dim + shifted);
01090                         B. add (q);
01091                 }
01092         }
01093 
01094         cubicalmap F;
01095         for (int i = 0; i < countS + countExit; ++ i)
01096         {
01097                 if (i < countS)
01098                         coord [dim] = 2;
01099                 else
01100                         coord [dim] = 1;
01101                 cf -> getcube (i, c);
01102                 for (int j = 0; j < dim; ++ j)
01103                         coord [j] = (typename Cube::CoordType) (c [j]);
01104                 const Cube q (coord, dim + shifted);
01105                 F [q];
01106                 int countImg = cf -> imgcount (i);
01107                 for (int j = 0; j < countImg; ++ j)
01108                 {
01109                         int n = cf -> getimgcube (i, j);
01110                         cf -> getcube (n, c);
01111                         for (int j = 0; j < dim; ++ j)
01112                                 coord [j] = (typename Cube::CoordType)
01113                                         (c [j]);
01114                         Cube qtest (coord, dim);
01115                         if (Xflat. check (qtest))
01116                                 coord [dim] = 2;
01117                         else if (Aflat. check (qtest))
01118                                 coord [dim] = 1;
01119                         else
01120                                 coord [dim] = 0;
01121                         Cube r (coord, dim + shifted);
01122                         F [q]. add (r);
01123                 }
01124         }
01125 
01126         // release the flat sets of cubes
01127         SetOfCubes emptyset;
01128         Xflat = emptyset;
01129         Aflat = emptyset;
01130 
01131         // DEBUG !!!
01132         static char debugfilename [] = "_/_x.cub";
01133         if (debugfilename [1] == '9')
01134                 debugfilename [1] = 'A';
01135         if (debugfilename [1] < 'Z')
01136                 ++ (debugfilename [1]);
01137 
01138         // DEBUG !!!
01139         if (false)
01140         {
01141                 { debugfilename [3] = 'x'; std::ofstream f (debugfilename); f << X; }
01142                 { debugfilename [3] = 'a'; std::ofstream f (debugfilename); f << A; }
01143                 { debugfilename [3] = 'y'; std::ofstream f (debugfilename); f << Y; }
01144                 { debugfilename [3] = 'b'; std::ofstream f (debugfilename); f << B; }
01145                 { debugfilename [3] = 'f'; std::ofstream f (debugfilename); f << F; }
01146         }
01147 
01148         // indicate the time used for the preparation
01149         sbug << "Preparation completed in " << prepTime << ".\n";
01150         prepTime = 0;
01151 
01152         // measure the time of creating data structures
01153         sbug << "Computing the Conley index map in homology...\n";
01154         timeused compTime;
01155 
01156         // compute the map in homology
01157         chain<euclidom> *homXA = 0, *homYB = 0;
01158         chainmap<euclidom> *homF = 0;
01159         int maxlevelXA = -1, maxlevelYB = -1, maxlevelF = -1;
01160         bool error = false;
01161         try
01162         {
01163                 chomp::homology::outputstream::mute mcon (scon);
01164                 chomp::homology::outputstream::mute mout (sout);
01165                 chomp::homology::outputstream::mute mbug (sbug);
01166                 // since "Homology2l" is not well tested yet,
01167                 // it is safer to raise the dimension (see above)
01168                 // and use the alternative solution at the moment
01169         //      if (twolayer)
01170         //      {
01171         //              maxlevelF = Homology2l (F, "F", X, "X", A, "A",
01172         //                      homXA, maxlevelXA, homF, 0xFF);
01173         //              maxlevelYB = maxlevelXA;
01174         //      }
01175         //      else
01176                 {
01177                         maxlevelF = Homology (F, "F", X, "X", A, "A",
01178                                 Y, "Y", B, "B", homXA, maxlevelXA,
01179                                 homYB, maxlevelYB, homF, true);
01180                 }
01181         }
01182         catch (...)
01183         {
01184                 // if failed for two-layer map, then this is a bad error
01185                 if (twolayer)
01186                         throw;
01187 
01188                 // otherwise the map must be computed using the new method
01189                 else
01190                 {
01191                         sout << "*** Homology computation failed. "
01192                                 "Using a careful two-layer method. ***\n";
01193                         error = true;
01194                 }
01195         }
01196         
01197         // if the levels don't agree, the map must be computed again
01198         if (!error && ((maxlevelF != maxlevelXA) ||
01199                 (maxlevelXA != maxlevelYB)))
01200         {
01201                 if (twolayer)
01202                         throw "Wrong homology levels in the Conley index.";
01203                 sout << "*** Homology levels don't agree. "
01204                         "Using a careful two-layer method. ***\n";
01205                 error = true;
01206         }
01207 
01208         // show the time used for the computation of the index map
01209         sbug << "The map computed in " << compTime << ".\n";
01210         compTime = 0;
01211 
01212         // if an error occurred for the flat model, use the two-layer one
01213         if (error)
01214         {
01215                 delete [] homXA;
01216                 delete [] homYB;
01217                 delete homF;
01218                 X = emptyset;
01219                 A = emptyset;
01220                 Y = emptyset;
01221                 B = emptyset;
01222                 cubicalmap emptymap;
01223                 F = emptymap;
01224                 return this -> compute (true);
01225         }
01226 
01227         toplevel = dim; /* previously I had here "dim + 1" --- why? */
01228         for (int level = 0; level <= toplevel; ++ level)
01229         {
01230                 std::vector<euclidom> coefficients;
01231                 if (level <= maxlevelXA)
01232                 {
01233                         for (int i = 0; i < homXA [level]. size (); ++ i)
01234                                 coefficients. push_back
01235                                         (homXA [level]. coef (i));
01236                 }
01237                 coef. push_back (coefficients);
01238         }
01239         if (indmap)
01240                 delete [] indmap;
01241         if (toplevel >= 0)
01242                 indmap = new mmatrix<euclidom> [toplevel + 1];
01243         else
01244         {
01245                 indmap = 0;
01246                 nontrivialindex = 0;
01247         }
01248         for (int i = 0; i <= maxlevelXA; ++ i)
01249                 indmap [i] = (*homF) [i];
01250 
01251         // DEBUG !!!
01252         if (false && homF)
01253         {
01254                 debugfilename [3] = 'h';
01255                 std::ofstream f (debugfilename);
01256                 f << *homF;
01257         }
01258 
01259         delete [] homXA;
01260         delete [] homYB;
01261         delete homF;
01262         return 0;
01263 } /* ConleyIndex::compute */
01264 
01265 template <class IndexPair, class euclidom>
01266 inline int ConleyIndex<IndexPair,euclidom>::reduce (bool shrink)
01267 {
01268         // remove those generators whose image is zero or which do not
01269         // appear in any image, i.e., their preimage is zero
01270         const int twice_the_level = (toplevel + 1) << 1;
01271         for (int level = 0; level < twice_the_level; ++ level)
01272         {
01273                 // retrieve the right matrix and determine: column or row?
01274                 bool columns = (level > toplevel);
01275                 chomp::homology::mmatrix<euclidom> &matr = indmap [columns ?
01276                         (level - toplevel - 1) : level];
01277 
01278                 // get the lengths of columns/rows of the matrix
01279                 int n = columns ? matr. getncols () : matr. getnrows ();
01280                 if (n <= 0)
01281                         continue;
01282                 int *lengths = new int [n];
01283                 for (int i = 0; i < n; ++ i)
01284                         lengths [i] = columns ? matr. getcol (i). size () :
01285                                 matr. getrow (i). size ();
01286 
01287                 // remove from each column these elements which have
01288                 // zero columns themselves
01289                 for (int i = 0; i < n; ++ i)
01290                 {
01291                         int length = lengths [i];
01292                         if (!length)
01293                                 continue;
01294                         chomp::homology::chain<euclidom> col_row = columns ?
01295                                 matr. getcol (i) : matr. getrow (i);
01296                         for (int j = 0; j < length; ++ j)
01297                         {
01298                                 int row_col = col_row. num (j);
01299                                 if (lengths [row_col] > 0)
01300                                         continue;
01301                                 matr. add (columns ? row_col : i,
01302                                         columns ? i : row_col,
01303                                         -col_row. coef (j));
01304                         }
01305                 }
01306 
01307                 // forget the column lengths
01308                 delete [] lengths;
01309         }
01310 
01311         // shrink the matrices and generators if requested to
01312         for (int level = toplevel; shrink && (level >= 0); -- level)
01313         {
01314                 // retrieve the references to this level's data
01315                 chomp::homology::mmatrix<euclidom> &matr = indmap [level];
01316                 std::vector<euclidom> &coefs = coef [level];
01317 
01318                 // if the matrix is empty
01319                 if (!matr. getncols () || !coefs. size ())
01320                 {
01321                         coefs. clear ();
01322                         chomp::homology::mmatrix<euclidom> emptymatr;
01323                         matr = emptymatr;
01324                 //      if (level == toplevel)
01325                 //              -- toplevel;
01326                         continue;
01327                 }
01328 
01329                 // select the numbers of generators/columns to keep
01330                 std::vector<int> selected;
01331                 int ncols = matr. getncols ();
01332                 for (int i = 0; i < ncols; ++ i)
01333                         if (matr. getcol (i). size () >= 1)
01334                                 selected. push_back (i);
01335                 int length = selected. size ();
01336 
01337                 // if the index at this level is trivial, skip the rest
01338                 if (!length)
01339                 {
01340                         coefs. clear ();
01341                         chomp::homology::mmatrix<euclidom> emptymatr;
01342                         matr = emptymatr;
01343                 //      if (level == toplevel)
01344                 //              -- toplevel;
01345                         continue;
01346                 }
01347 
01348                 // create a new matrix
01349                 chomp::homology::mmatrix<euclidom> newmatr;
01350                 newmatr. define (length, length);
01351                 for (int i = 0; i < length; ++ i)
01352                 {
01353                         for (int j = 0; j < length; ++ j)
01354                         {
01355                                 newmatr. add (i, j, matr. get (selected [i],
01356                                         selected [j]));
01357                         }
01358                 }
01359                 matr = newmatr;
01360 
01361                 // create a new sequence of coefficients
01362                 std::vector<euclidom> newcoefs (length);
01363                 for (int i = 0; i < length; ++ i)
01364                         newcoefs [i] = coefs [selected [i]];
01365                 coefs = newcoefs;
01366         }
01367 
01368         // change the sign of negative matrix entries where possible
01369         // unless 1 == -1 in the Euclidean domain in question
01370         euclidom e1, minus1;
01371         e1 = 1;
01372         minus1 = -e1;
01373         if (e1 != minus1)
01374         {
01375                 for (int level = 0; level <= toplevel; ++ level)
01376                 {
01377                         // retrieve the reference to the matrix at this level
01378                         chomp::homology::mmatrix<euclidom> &matr =
01379                                 indmap [level];
01380 
01381                         // find single -1's and change their sign
01382                         int n = matr. getncols ();
01383                         for (int i = 0; i < n; ++ i)
01384                         {
01385                                 const chomp::homology::chain<euclidom> &column =
01386                                         matr. getcol (i);
01387                                 if (column. size () != 1)
01388                                         continue;
01389                                 if (column. coef (0) != minus1)
01390                                         continue;
01391                                 if (column. num (0) <= i)
01392                                         continue;
01393                                 matr. multiplyrow (i, minus1);
01394                                 matr. multiplycol (i, minus1);
01395                         }
01396                 }
01397         }
01398 
01399         return 0;
01400 } /* ConleyIndex::reduce */
01401 
01402 template <class IndexPair, class euclidom>
01403 inline void ConleyIndex<IndexPair,euclidom>::truncate (int newlevel)
01404 {
01405         if ((newlevel >= -1) && (newlevel <= toplevel))
01406         {
01407                 toplevel = newlevel;
01408                 coef. erase (coef. begin () + toplevel + 1, coef. end ());
01409         }
01410         return;
01411 } /* ConleyIndex<IndexPair,euclidom>::truncate */
01412 
01413 template <class IndexPair, class euclidom>
01414 inline int ConleyIndex<IndexPair,euclidom>::eigenvalues (int level,
01415         std::vector<double> &Re, std::vector<double> &Im,
01416         bool nonzero, bool sorted) const
01417 {
01418         // if the level is out of scope, return the error code
01419         if ((level < 0) || (level > toplevel))
01420                 return -1;
01421 
01422         // retrieve the matrix and its size
01423         const chomp::homology::mmatrix<euclidom> &m = indmap [level];
01424         int fullsize = m. getncols ();
01425         if (fullsize <= 0)
01426                 return 0;
01427 
01428         // retrieve the indices not related to torsion
01429         int size = fullsize;
01430         const std::vector<euclidom> &coefs = coef [level];
01431         std::vector<int> indices (size);
01432         int current = 0;
01433         for (int i = 0; i < fullsize; ++ i)
01434         {
01435                 if (coefs [i]. delta () > 1)
01436                 {
01437                         indices [i] = -1;
01438                         -- size;
01439                 }
01440                 else
01441                 {
01442                         indices [i] = current;
01443                         ++ current;
01444                 }
01445         }
01446         if (size <= 0)
01447                 return 0;
01448 
01449         // prepare data for the LAPACK function to compute the eigenvalues
01450         char N = 'N';
01451         long int dimension = size;
01452         std::auto_ptr<double> APtr (new double [size * size]);
01453         double *A = APtr. get ();
01454         std::auto_ptr<double> rePtr (new double [size]);
01455         double *re = rePtr. get ();
01456         std::auto_ptr<double> imPtr (new double [size]);
01457         double *im = imPtr. get ();
01458         long int worksize = 3 * size + (2 * size + 128);
01459         std::auto_ptr<double> workPtr (new double [worksize]);
01460         double *work = workPtr. get ();
01461         long int result = 0;
01462 
01463         // translate the chain matrix to the matrix of doubles
01464         double *ptr = A;
01465         for (int i = 0; i < size; ++ i)
01466         {
01467                 for (int j = 0; j < size; ++ j)
01468                 {
01469                         *(ptr ++) = 0;
01470                 }
01471         }
01472         for (int col = 0; col < fullsize; ++ col)
01473         {
01474                 int icol = indices [col];
01475                 if (icol < 0)
01476                         continue;
01477                 const chomp::homology::chain<euclidom> c = m. getcol (col);
01478                 int len = c. size ();
01479                 for (int i = 0; i < len; ++ i)
01480                 {
01481                         int irow = indices [c. num (i)];
01482                         if (irow < 0)
01483                                 continue;
01484                         euclidom e = c. coef (i);
01485                         int n = e. delta ();
01486                         euclidom e1;
01487                         e1 = n;
01488                         if (e1 != e)
01489                                 n = -n;
01490                         A [size * irow + icol] = n;
01491                 }
01492         }
01493 
01494         // call the LAPACK function to compute the eigenvalues of the map
01495         // (note: the eigenvalues of A^T are the same as of the eigenvalues
01496         // of A, so I don't care that the matrices are reprsented
01497         // in a different way in Fortran)
01498         dgeev_ (&N, &N, &dimension, A, &dimension, re, im,
01499                 0, &dimension, 0, &dimension, work, &worksize, &result);
01500 
01501         // throw an error message in case of failure
01502         if (result < 0)
01503                 throw "Conley Index eigenvalues: LAPACK error.";
01504         else if (result > 0)
01505                 throw "The QR algorithm failed in the Conley Index "
01506                         "Eigenvalues computation.";
01507 
01508         // gather the output data
01509         std::vector<ppComplex> values;
01510         const double epsilon = 0.001;
01511         const double threshold = 0.01;
01512         for (int i = 0; i < size; ++ i)
01513         {
01514                 re [i] = round (re [i], epsilon, threshold);
01515                 im [i] = round (im [i], epsilon, threshold);
01516                 if (nonzero && !re [i] && !im [i])
01517                         continue;
01518                 values. push_back (ppComplex (re [i], im [i]));
01519         }
01520 
01521         // make a note of any nontrivial eigenvalues
01522         if (values. size ())
01523                 nontrivialindex = 1;
01524 
01525         // sort the eigenvalues if requested to
01526         if (sorted)
01527                 std::sort (values. begin (), values. end ());
01528 
01529         // write the results to the provided data structures
01530         for (std::vector<ppComplex>::const_iterator it = values. begin ();
01531                 it != values. end (); ++ it)
01532         {
01533                 Re. push_back (it -> re);
01534                 Im. push_back (it -> im);
01535         }
01536 
01537         return values. size ();
01538 } /* ConleyIndex<IndexPair,euclidom>::eigenvalues */
01539 
01540 template <class IndexPair, class euclidom>
01541 inline bool ConleyIndex<IndexPair,euclidom>::trivial () const
01542 {
01543         // if the answer has already been computed before, use it now
01544         if (nontrivialindex >= 0)
01545                 return !nontrivialindex;
01546 
01547         for (int level = 0; level <= toplevel; ++ level)
01548         {
01549                 std::vector<double> Re, Im;
01550                 int n = eigenvalues (level, Re, Im, true, false);
01551                 if (n)
01552                 {
01553                         nontrivialindex = 1;
01554                         return false;
01555                 }
01556         //      if (coef [level]. size () && (indmap [level]. getncols () > 0))
01557         //              return false;
01558         }
01559         nontrivialindex = 0;
01560         return true;
01561 } /* ConleyIndex::trivial */
01562 
01563 template <class IndexPair, class euclidom>
01564 inline std::string ConleyIndex<IndexPair,euclidom>::EigenString (int n) const
01565 {
01566         // make sure the level is correct
01567         if (!indmap || (n < 0) || (n > toplevel))
01568                 return std::string ();
01569 
01570         // prepare the output string stream
01571         std::ostringstream out;
01572 
01573         // compute the nonzero eigenvalues and sort them
01574         std::vector<double> Re, Im;
01575         int count = eigenvalues (n, Re, Im);
01576         if (count > 0)
01577                 nontrivialindex = 1;
01578 
01579         // output the eigenvalues
01580         out << "Eigenvalues " << n << ": (";
01581         if (count >= 0)
01582         {
01583                 for (int i = 0; i < count; ++ i)
01584                 {
01585                         if (i)
01586                                 out << ", ";
01587                         if (Re [i])
01588                         {
01589                                 out << Re [i];
01590                                 if (Im [i] > 0)
01591                                         out << "+";
01592                         }
01593                         if (Im [i])
01594                                 out << Im [i] << "i";
01595                 }
01596         }
01597         else
01598                 out << "ERROR";
01599         out << ").";
01600 
01601         return out. str ();
01602 } /* ConleyIndex::EigenString */
01603 
01604 template <class IndexPair, class euclidom>
01605 inline void ConleyIndex<IndexPair,euclidom>::define (const int *betti,
01606         const chomp::homology::mmatrix<euclidom> *matr, int _toplevel)
01607 {
01608         // reset the potentially remembered nontriviality
01609         nontrivialindex = -1;
01610 
01611         // set the top level of homology
01612         toplevel = _toplevel;
01613 
01614         // create the coefficients vector
01615         coef. clear ();
01616         euclidom e;
01617         e = 1;
01618         for (int i = 0; i <= toplevel; ++ i)
01619         {
01620                 std::vector<euclidom> b;
01621                 for (int j = betti [i]; j > 0; -- j)
01622                         b. push_back (e);
01623                 coef. push_back (b);
01624         }
01625 
01626         // set the index maps
01627         if (indmap)
01628         {
01629                 delete [] indmap;
01630                 indmap = 0;
01631         }
01632         if (toplevel >= 0)
01633         {
01634                 indmap = new chomp::homology::mmatrix<euclidom>
01635                         [toplevel + 1];
01636         }
01637         for (int level = 0; level <= toplevel; ++ level)
01638         {
01639                 indmap [level] = matr [level];
01640         }
01641         return;
01642 } /* ConleyIndex::define */
01643 
01644 template <class IndexPair, class euclidom>
01645 inline void ConleyIndex<IndexPair,euclidom>::define (const int *betti,
01646         int _toplevel)
01647 {
01648         // create an array of the identity maps
01649         chomp::homology::mmatrix<euclidom> *matr = (_toplevel < 0) ? 0 :
01650                 new chomp::homology::mmatrix<euclidom> [_toplevel + 1];
01651         for (int level = 0; level <= _toplevel; ++ level)
01652         {
01653                 if (betti [level] > 0)
01654                         matr [level]. identity (betti [level]);
01655         }
01656 
01657         // define the index
01658         this -> define (betti, matr, _toplevel);
01659 
01660         // clean up and finalize
01661         if (matr)
01662                 delete [] matr;
01663         return;
01664 } /* ConleyIndex::define */
01665 
01666 // --------------------------------------------------
01667 
01668 template <class IndexPair, class euclidom>
01669 std::ostream &operator << (std::ostream &out,
01670         const ConleyIndex<IndexPair,euclidom> &c)
01671 {
01672         // write the top level
01673         out << c. toplevel << " ";
01674         if (c. toplevel < 0)
01675                 return out;
01676 
01677         // write the coefficients
01678         for (int i = 0; i <= c. toplevel; ++ i)
01679         {
01680                 int size = c. coef [i]. size ();
01681                 out << size << " ";
01682                 for (int j = 0; j < size; ++ j)
01683                         out << c. coef [i] [j] << " ";
01684         }
01685 
01686         // write the maps
01687         for (int i = 0; i <= c. toplevel; ++ i)
01688         {
01689                 const chomp::homology::mmatrix<euclidom> &m = c. indmap [i];
01690                 out << m. getnrows () << " " << m. getncols () << " ";
01691                 for (int j = 0; j < m. getncols (); ++ j)
01692                 {
01693                         const chomp::homology::chain<euclidom> &col =
01694                                 m. getcol (j);
01695                         out << col. size () << " ";
01696                         for (int k = 0; k < col. size (); ++ k)
01697                         {
01698                                 out << col. num (k) << " ";
01699                                 out << col. coef (k) << " ";
01700                         }
01701                 }
01702         }
01703 
01704         return out;
01705 } /* operator << */
01706 
01707 template <class IndexPair, class euclidom>
01708 std::istream &operator >> (std::istream &in,
01709         ConleyIndex<IndexPair,euclidom> &c)
01710 {
01711         // reset the data
01712         c. nontrivialindex = -1;
01713         if (c. indmap)
01714         {
01715                 delete [] c. indmap;
01716                 c. indmap = 0;
01717         }
01718         c. coef. clear ();
01719 
01720         // read the top level
01721         in >> c. toplevel;
01722         if (c. toplevel < 0)
01723                 return in;
01724 
01725         // read the coefficients
01726         for (int i = 0; i <= c. toplevel; ++ i)
01727         {
01728                 int size = -1;
01729                 in >> size;
01730                 if (size < 0)
01731                         throw "Cannot decode the Conley index from input.";
01732                 std::vector<euclidom> coef;
01733                 for (int j = 0; j < size; ++ j)
01734                 {
01735                         euclidom e;
01736                         e = 0;
01737                         in >> e;
01738                         if (e. delta () <= 0)
01739                                 throw "Wrong coefficient in the "
01740                                         "Conley index from input.";
01741                         coef. push_back (e);
01742                 }
01743                 c. coef. push_back (coef);
01744         }
01745 
01746         // read the maps
01747         if (c. toplevel >= 0)
01748                 c. indmap = new chomp::homology::mmatrix<euclidom>
01749                         [c. toplevel + 1];
01750         for (int i = 0; i <= c. toplevel; ++ i)
01751         {
01752                 chomp::homology::mmatrix<euclidom> &m = c. indmap [i];
01753                 int nrows = 0, ncols = 0;
01754                 in >> nrows >> ncols;
01755                 if ((nrows < 0) || (ncols < 0))
01756                         throw "Wrong matrix size in the Conley index "
01757                                 "from input.";
01758                 if ((nrows > 0) && (ncols > 0))
01759                         m. define (nrows, ncols);
01760                 for (int j = 0; j < ncols; ++ j)
01761                 {
01762                         int length = -1;
01763                         in >> length;
01764                         if (length < 0)
01765                                 throw "Negative column length in the "
01766                                         "Conley index from input.";
01767                         for (int k = 0; k < length; ++ k)
01768                         {
01769                                 int num = -1;
01770                                 in >> num;
01771                                 if ((num < 0) || (num >= nrows))
01772                                         throw "Wrong row number in the "
01773                                                 "Conley index from input.";
01774                                 euclidom e;
01775                                 e = 0;
01776                                 in >> e;
01777                                 if (e. delta () <= 0)
01778                                         throw "Wrong matrix entry in the "
01779                                                 "Conley index from input.";
01780                                 m. add (num, j, e);
01781                         }
01782                 }
01783         }
01784 
01785         return in;
01786 } /* operator >> */
01787 
01788 
01789 #endif // _CMGRAPHS_CONINDEX_H_
01790 
01791 

Generated on Sun Mar 28 17:47:57 2010 for The Conley-Morse Graphs Software by  doxygen 1.5.3