The Conley-Morse Graphs Software
conindex.h
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////////
2///
3/// @file conindex.h
4///
5/// Conley index computation routines.
6/// This file contains the definition of routines for the computation
7/// of the Conley index using the CHomP library.
8///
9/// @author Pawel Pilarczyk
10///
11/////////////////////////////////////////////////////////////////////////////
12
13// Copyright (C) 1997-2014 by Pawel Pilarczyk.
14//
15// This file is part of my research software package. This is free software:
16// you can redistribute it and/or modify it under the terms of the GNU
17// General Public License as published by the Free Software Foundation,
18// either version 3 of the License, or (at your option) any later version.
19//
20// This software is distributed in the hope that it will be useful,
21// but WITHOUT ANY WARRANTY; without even the implied warranty of
22// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23// GNU General Public License for more details.
24//
25// You should have received a copy of the GNU General Public License
26// along with this software; see the file "license.txt". If not,
27// please, see <https://www.gnu.org/licenses/>.
28
29// Started on July 19, 2006. Last revision: February 2, 2011.
30
31
32#ifndef _CMGRAPHS_CONINDEX_H_
33#define _CMGRAPHS_CONINDEX_H_
34
35
36// include some standard C++ header files
37#include <iostream>
38#include <algorithm>
39#include <new>
40
41// include selected header files from the CHomP library
42#include "chomp/system/textfile.h"
43#include "chomp/system/timeused.h"
44#include "chomp/homology/homology.h"
45#include "chomp/struct/autoarray.h"
46
47// include local header files
48#include "config.h"
49#include "typedefs.h"
50#include "mapcomp.h"
51#include "indpair.h"
52
53
54// --------------------------------------------------
55// ------- the CLAPACK eigenvalues subroutine -------
56// --------------------------------------------------
57
58extern "C" {
59int dgeev_ (char *jobvl, char *jobvr, int32 *n,
60 double *a, int32 *lda, double *wr, double *wi, double *vl,
61 int32 *ldvl, double *vr, int32 *ldvr, double *work,
62 int32 *lwork, int32 *info);
63}
64
65
66// --------------------------------------------------
67// ------------------ CONLEY INDEX ------------------
68// --------------------------------------------------
69
70template <class IndexPair, class euclidom>
71class ConleyIndex;
72
73template <class IndexPair, class euclidom>
74std::istream &operator >> (std::istream &in,
76
77template <class IndexPair, class euclidom>
78std::ostream &operator << (std::ostream &out,
80
81/// The class that computes and returns properties of the Conley index.
82/// The index pair object is used to get the cubical index pair.
83template <class IndexPair = EmptyIndexPair,
84 class euclidom = chomp::homology::integer>
86{
87public:
88 /// The default constructor.
89 ConleyIndex (const IndexPair *c = 0);
90
91 /// The copy constructor.
93
94 /// The destructor.
95 ~ConleyIndex ();
96
97 /// The assignment operator.
100
101 /// Sets the index pair to be used to compute the Conley index.
102 void setIndexPair (const IndexPair *f);
103
104 /// Computes the Conley index. If requested, uses the two-layer
105 /// construction. Otherwise, first tries the flat model, and switches
106 /// to the two-layer construction only in the case of failure.
107 int compute (bool twolayer = false);
108
109 /// Reduces the index map using some shift equivalences to certain
110 /// extent. Shrinks the matrices and generators if requested to.
111 int reduce (bool shrink = true);
112
113 /// Truncates the Conley index to the new top level.
114 void truncate (int newlevel);
115
116 /// Computes the eigenvalues of the index map.
117 /// The eigenvalues are appended to the given vectors of doubles
118 /// with the "push_back" method.
119 /// Returns the number of eigenvalues or -1 in case of failure.
120 int eigenvalues (int level, std::vector<double> &Re,
121 std::vector<double> &Im, bool nonzero = true,
122 bool sorted = true) const;
123
124 /// Verifies if the index is trivial. Returns true if yes,
125 /// false if it is non-trivial. Note: This information is tabulated.
126 bool trivial () const;
127
128 /// Retrieves the nth Betti number.
129 int BettiNumber (int n) const;
130
131 /// Retrieves the 'i'th [torsion] coefficient at the nth level.
132 /// Returns 0 if 'i' is beyond the available scope.
133 euclidom Coefficient (int n, int i) const;
134
135 /// Retrieves the top level, or the maximal dimension of the index.
136 /// The numbers of available levels are from 0 to dim inclusive.
137 /// Returns -1 if the index is undefined.
138 int dim () const;
139
140 /// Retrieves the matrix of the index map at the given level.
141 /// Returns 0 if the map at this level is zero.
142 const chomp::homology::mmatrix<euclidom> *Map (int n) const;
143
144 /// Retrieves a human-readable text representation of the map.
145 std::string MapString (int n, const char *newline = "\n") const;
146
147 /// Retrieves a human-readable text showing the eigenvalues.
148 std::string EigenString (int n) const;
149
150 /// Retrieves a human-readable text representation of the homology.
151 std::string HomString () const;
152
153 /// Defines the Conley index by the given Betti numbers
154 /// and the given maps in homology.
155 void define (const int *betti,
156 const chomp::homology::mmatrix<euclidom> *matr,
157 int _toplevel);
158
159 /// Defines the Conley index by the given Betti numbers
160 /// and adds the identity map.
161 void define (const int *betti, int _toplevel);
162
163private:
164 /// An object that feeds this class with cubes.
165 const IndexPair *cf;
166
167 /// The number of the top homology level.
169
170 /// The torsion coefficients of the corresponding homology
171 /// generators. If delta () == 1, then no torsion.
172 std::vector<std::vector<euclidom> > coef;
173
174 /// The matrices of the index map at each level.
175 chomp::homology::mmatrix<euclidom> *indmap;
176
177 /// Converts the Conley index to a string (without the index pair).
178 friend std::ostream &operator << <> (std::ostream &out,
180
181 /// Retrieves the Conley index from a string
182 /// (without the index pair).
183 friend std::istream &operator >> <> (std::istream &in,
185
186 /// Rounds a real number to the given precision.
187 /// If the absolute value of the number is below the given threshold
188 /// then the number is truncated to 0.
189 static double round (double x, double epsilon, double threshold);
190
191 /// Variable that stores the tabulated information on whether
192 /// the index is nontrivial. Values used: -1 = unknown, 0 = trivial,
193 /// 1 = nontrivial.
194 mutable int nontrivialindex;
195
196}; /* class ConleyIndex */
197
198// --------------------------------------------------
199
200/// An auxiliary class that represents complex numbers.
201/// It is used in the procedure for computing eigenvalues.
203{
204 double re, im;
205 ppComplex (double _re, double _im): re (_re), im (_im) {}
206
207}; /* struct ppComplex */
208
209inline bool operator < (const ppComplex &x, const ppComplex &y)
210{
211 if (x. re < y. re)
212 return true;
213 else if (x. re > y. re)
214 return false;
215 return (x. im < y. im);
216} /* operator < */
217
218// --------------------------------------------------
219
220template <class IndexPair, class euclidom>
222{
223 cf = c;
224 toplevel = -1;
225 indmap = 0;
226 nontrivialindex = -1;
227 return;
228} /* ConleyIndex::ConleyIndex */
229
230template <class IndexPair, class euclidom>
233{
234 cf = c. cf;
235 toplevel = c. toplevel;
236 coef = c. coef;
237 if (toplevel >= 0)
238 indmap = new chomp::homology::mmatrix<euclidom> [toplevel + 1];
239 else
240 indmap = 0;
241 for (int i = 0; i <= toplevel; ++ i)
242 indmap [i] = c. indmap [i];
243 nontrivialindex = c. nontrivialindex;
244 return;
245} /* ConleyIndex::ConleyIndex */
246
247template <class IndexPair, class euclidom>
251{
252 cf = c. cf;
253 toplevel = c. toplevel;
254 coef = c. coef;
255 if (indmap)
256 delete [] indmap;
257 if (toplevel >= 0)
258 indmap = new chomp::homology::mmatrix<euclidom> [toplevel + 1];
259 else
260 indmap = 0;
261 for (int i = 0; i <= toplevel; ++ i)
262 indmap [i] = c. indmap [i];
263 nontrivialindex = c. nontrivialindex;
264 return *this;
265} /* ConleyIndex::operator = */
266
267template <class IndexPair, class euclidom>
269{
270 if (indmap)
271 delete [] indmap;
272 return;
273} /* ConleyIndex::~ConleyIndex */
274
275template <class IndexPair, class euclidom>
277 (const IndexPair *f)
278{
279 cf = f;
280 return;
281} /* ConleyIndex::setIndexPair */
282
283template <class IndexPair, class euclidom>
284double ConleyIndex<IndexPair,euclidom>::round (double x, double epsilon,
285 double threshold)
286{
287 if ((x < 0) && (x > -threshold))
288 return 0;
289 if ((x > 0) && (x < threshold))
290 return 0;
291 x /= epsilon;
292 long xl = static_cast<long> (x);
293 if (xl - x > 0.5)
294 -- xl;
295 else if (x - xl > 0.5)
296 ++ xl;
297 return (xl * epsilon);
298} /* ConleyIndex::round */
299
300template <class IndexPair, class euclidom>
302{
303 if ((n < 0) || (n > toplevel))
304 return 0;
305 int size = coef [n]. size ();
306 int count = 0;
307 for (int i = 0; i < size; ++ i)
308 if (coef [n] [i]. delta () == 1)
309 ++ count;
310 return count;
311} /* ConleyIndex::BettiNumber */
312
313template <class IndexPair, class euclidom>
314inline const chomp::homology::mmatrix<euclidom> *
316{
317 if (!indmap || (n < 0) || (n > toplevel))
318 return 0;
319 return (indmap + n);
320} /* ConleyIndex::Map */
321
322template <class IndexPair, class euclidom>
324 (int n, int i) const
325{
326 euclidom zero;
327 zero = 0;
328 if ((n < 0) || (n > toplevel))
329 return zero;
330 int size = coef [n]. size ();
331 if ((i < 0) || (i >= size))
332 return zero;
333 return coef [n] [i];
334} /* ConleyIndex::Coefficient */
335
336template <class IndexPair, class euclidom>
338{
339 return toplevel;
340} /* ConleyIndex::dim */
341
342template <class IndexPair, class euclidom>
344 const char *newline) const
345{
346 if (!indmap || (n < 0) || (n > toplevel))
347 return std::string ();
348 std::ostringstream out;
349 const chomp::homology::mmatrix<euclidom> &m = indmap [n];
350 bool nonzero = false;
351 for (int j = 0; j < m. getncols (); j ++)
352 if (m. getcol (j). size ())
353 {
354 if (!nonzero)
355 {
356 out << "Map " << n << ":" << newline;
357 nonzero = true;
358 }
359 out << "#" << (j + 1) << " = " << m. getcol (j) <<
360 newline;
361 }
362 if (!nonzero)
363 out << "Map " << n << " = 0" << newline;
364 return out. str ();
365} /* ConleyIndex::MapString */
366
367template <class IndexPair, class euclidom>
369{
370 if (coef. size () <= 0)
371 return std::string ("0");
372 std::ostringstream out;
373 int coefsize = coef. size ();
374 for (int i = 0; i < coefsize; ++ i)
375 {
376 bool nonzero = false;
377 if (i)
378 out << ", ";
379 int counter = 0;
380 int size = coef [i]. size ();
381 for (int j = 0; j < size; ++ j)
382 {
383 if (coef [i] [j]. delta () > 1)
384 {
385 if (nonzero)
386 out << "+";
387 if (counter)
388 {
389 out << "Z";
390 if (counter > 1)
391 out << "^" << counter;
392 out << "+";
393 counter = 0;
394 }
395 out << "Z_" << coef [i] [j];
396 nonzero = true;
397 }
398 else
399 ++ counter;
400 }
401 if (counter)
402 {
403 if (nonzero)
404 out << "+";
405 out << "Z";
406 if (counter > 1)
407 out << "^" << counter;
408 nonzero = true;
409 }
410 if (!nonzero)
411 out << "0";
412 }
413 return out. str ();
414} /* ConleyIndex::HomString */
415
416template <class IndexPair, class euclidom>
418{
419// using chomp::homology::sbug;
420// using chomp::homology::chain;
421// using chomp::homology::chainmap;
422// using chomp::homology::timeused;
423 using namespace chomp::homology;
424
425 typedef typename IndexPair::CubeType CubeType;
426 typedef typename IndexPair::CubSetType CubSetType;
427 typedef typename CubeType::CoordType CoordType;
428 typedef chomp::homology::mvmap<CubeType,CubeType> MvMapType;
429
430 // measure the time of creating data structures
431 sbug << "Preparing to compute the Conley index...\n";
432 timeused prepTime;
433
434 // create the cubical map for the homology computation
435 CubSetType X, A, Y, B;
436 int dim = cf -> dim ();
437 int countS = cf -> countInv ();
438 CoordType c [CubeType::MaxDim];
439 for (int i = 0; i < countS; ++ i)
440 {
441 cf -> getcube (i, c);
442 CubeType q (c, dim);
443 X. add (q);
444 Y. add (q);
445 }
446 int countExit = cf -> countExit ();
447 for (int i = 0; i < countExit; ++ i)
448 {
449 cf -> getcube (countS + i, c);
450 CubeType q (c, dim);
451 A. add (q);
452 B. add (q);
453 }
454 for (int i = 0; i < countExit; ++ i)
455 {
456 int countImg = cf -> imgcount (countS + i);
457 for (int j = 0; j < countImg; ++ j)
458 {
459 int n = cf -> getimgcube (countS + i, j);
460 cf -> getcube (n, c);
461 CubeType q (c, dim);
462 B. add (q);
463 }
464 }
465
466 MvMapType F;
467 for (int i = 0; i < countS + countExit; ++ i)
468 {
469 cf -> getcube (i, c);
470 const CubeType q (c, dim);
471 F [q];
472 int countImg = cf -> imgcount (i);
473 for (int j = 0; j < countImg; ++ j)
474 {
475 int n = cf -> getimgcube (i, j);
476 cf -> getcube (n, c);
477 CubeType r (c, dim);
478 F [q]. add (r);
479 }
480 }
481
482 // DEBUG !!!
483 static char debugfilename [] = "_/_x.cub";
484 if (debugfilename [1] == '9')
485 debugfilename [1] = 'A';
486 if (debugfilename [1] < 'Z')
487 ++ (debugfilename [1]);
488
489 // DEBUG !!!
490 if (false)
491 {
492 { debugfilename [3] = 'x'; std::ofstream f (debugfilename); f << X; }
493 { debugfilename [3] = 'a'; std::ofstream f (debugfilename); f << A; }
494 { debugfilename [3] = 'y'; std::ofstream f (debugfilename); f << Y; }
495 { debugfilename [3] = 'b'; std::ofstream f (debugfilename); f << B; }
496 { debugfilename [3] = 'f'; std::ofstream f (debugfilename); f << F; }
497 }
498
499 // indicate the time used for the preparation
500 sbug << "Preparation completed in " << prepTime << ".\n";
501 prepTime = 0;
502
503 // measure the time of creating data structures
504 sbug << "Computing the Conley index map in homology...\n";
505 timeused compTime;
506
507 // compute the map in homology
508 chain<euclidom> *homXA = 0, *homYB = 0;
509 chainmap<euclidom> *homF = 0;
510 int maxlevelXA = -1, maxlevelYB = -1, maxlevelF = -1;
511 bool error = false;
512 try
513 {
514 // chomp::homology::outputstream::mute mcon (scon);
515 // chomp::homology::outputstream::mute mout (sout);
516 // chomp::homology::outputstream::mute mbug (sbug);
517 if (twolayer)
518 {
519 maxlevelF = chomp::homology::Homology2l
520 (F, "F", X, "X", A, "A",
521 homXA, maxlevelXA, homF, 0xFF);
522 maxlevelYB = maxlevelXA;
523 }
524 else
525 {
526 maxlevelF = chomp::homology::Homology
527 (F, "F", X, "X", A, "A",
528 Y, "Y", B, "B", homXA, maxlevelXA,
529 homYB, maxlevelYB, homF, true, 0x03);
530 }
531 }
532 catch (...)
533 {
534 // if failed for two-layer map, then this is a bad error
535 if (twolayer)
536 throw;
537
538 // otherwise the map must be computed using the new method
539 else
540 {
541 sout << "*** Homology computation failed. "
542 "Using a careful two-layer method. ***\n";
543 error = true;
544 }
545 }
546
547 // if the levels don't agree, the map must be computed again
548 if (!error && ((maxlevelF != maxlevelXA) ||
549 (maxlevelXA != maxlevelYB)))
550 {
551 if (twolayer)
552 throw "Wrong homology levels in the Conley index.";
553 sout << "*** Homology levels don't agree. "
554 "Using a careful two-layer method. ***\n";
555 error = true;
556 }
557
558 // show the time used for the computation of the index map
559 sbug << "The map computed in " << compTime << ".\n";
560 compTime = 0;
561
562 // if an error occurred for the flat model, use the two-layer one
563 if (error)
564 {
565 delete [] homXA;
566 delete [] homYB;
567 delete homF;
568 CubSetType emptyset;
569 X = emptyset;
570 A = emptyset;
571 Y = emptyset;
572 B = emptyset;
573 MvMapType emptymap;
574 F = emptymap;
575 return this -> compute (true);
576 }
577
578 toplevel = dim; /* previously I had here "dim + 1" --- why? */
579 for (int level = 0; level <= toplevel; ++ level)
580 {
581 std::vector<euclidom> coefficients;
582 if (level <= maxlevelXA)
583 {
584 for (int i = 0; i < homXA [level]. size (); ++ i)
585 coefficients. push_back
586 (homXA [level]. coef (i));
587 }
588 coef. push_back (coefficients);
589 }
590 if (indmap)
591 delete [] indmap;
592 if (toplevel >= 0)
593 indmap = new mmatrix<euclidom> [toplevel + 1];
594 else
595 {
596 indmap = 0;
597 nontrivialindex = 0;
598 }
599 for (int i = 0; i <= maxlevelXA; ++ i)
600 indmap [i] = (*homF) [i];
601
602 // DEBUG !!!
603 if (false && homF)
604 {
605 debugfilename [3] = 'h';
606 std::ofstream f (debugfilename);
607 f << *homF;
608 }
609
610 delete [] homXA;
611 delete [] homYB;
612 delete homF;
613 return 0;
614} /* ConleyIndex::compute */
615
616template <class IndexPair, class euclidom>
618{
619 // remove those generators whose image is zero or which do not
620 // appear in any image, i.e., their preimage is zero
621 const int twice_the_level = (toplevel + 1) << 1;
622 for (int level = 0; level < twice_the_level; ++ level)
623 {
624 // retrieve the right matrix and determine: column or row?
625 bool columns = (level > toplevel);
626 chomp::homology::mmatrix<euclidom> &matr = indmap [columns ?
627 (level - toplevel - 1) : level];
628
629 // get the lengths of columns/rows of the matrix
630 int n = columns ? matr. getncols () : matr. getnrows ();
631 if (n <= 0)
632 continue;
633 int *lengths = new int [n];
634 for (int i = 0; i < n; ++ i)
635 lengths [i] = columns ? matr. getcol (i). size () :
636 matr. getrow (i). size ();
637
638 // remove from each column these elements which have
639 // zero columns themselves
640 for (int i = 0; i < n; ++ i)
641 {
642 int length = lengths [i];
643 if (!length)
644 continue;
645 chomp::homology::chain<euclidom> col_row = columns ?
646 matr. getcol (i) : matr. getrow (i);
647 for (int j = 0; j < length; ++ j)
648 {
649 int row_col = col_row. num (j);
650 if (lengths [row_col] > 0)
651 continue;
652 matr. add (columns ? row_col : i,
653 columns ? i : row_col,
654 -col_row. coef (j));
655 }
656 }
657
658 // forget the column lengths
659 delete [] lengths;
660 }
661
662 // shrink the matrices and generators if requested to
663 for (int level = toplevel; shrink && (level >= 0); -- level)
664 {
665 // retrieve the references to this level's data
666 chomp::homology::mmatrix<euclidom> &matr = indmap [level];
667 std::vector<euclidom> &coefs = coef [level];
668
669 // if the matrix is empty
670 if (!matr. getncols () || !coefs. size ())
671 {
672 coefs. clear ();
673 chomp::homology::mmatrix<euclidom> emptymatr;
674 matr = emptymatr;
675 // if (level == toplevel)
676 // -- toplevel;
677 continue;
678 }
679
680 // select the numbers of generators/columns to keep
681 std::vector<int> selected;
682 int ncols = matr. getncols ();
683 for (int i = 0; i < ncols; ++ i)
684 if (matr. getcol (i). size () >= 1)
685 selected. push_back (i);
686 int length = selected. size ();
687
688 // if the index at this level is trivial, skip the rest
689 if (!length)
690 {
691 coefs. clear ();
692 chomp::homology::mmatrix<euclidom> emptymatr;
693 matr = emptymatr;
694 // if (level == toplevel)
695 // -- toplevel;
696 continue;
697 }
698
699 // create a new matrix
700 chomp::homology::mmatrix<euclidom> newmatr;
701 newmatr. define (length, length);
702 for (int i = 0; i < length; ++ i)
703 {
704 for (int j = 0; j < length; ++ j)
705 {
706 newmatr. add (i, j, matr. get (selected [i],
707 selected [j]));
708 }
709 }
710 matr = newmatr;
711
712 // create a new sequence of coefficients
713 std::vector<euclidom> newcoefs (length);
714 for (int i = 0; i < length; ++ i)
715 newcoefs [i] = coefs [selected [i]];
716 coefs = newcoefs;
717 }
718
719 // change the sign of negative matrix entries where possible
720 // unless 1 == -1 in the Euclidean domain in question
721 euclidom e1, minus1;
722 e1 = 1;
723 minus1 = -e1;
724 if (e1 != minus1)
725 {
726 for (int level = 0; level <= toplevel; ++ level)
727 {
728 // retrieve the reference to the matrix at this level
729 chomp::homology::mmatrix<euclidom> &matr =
730 indmap [level];
731
732 // find single -1's and change their sign
733 int n = matr. getncols ();
734 for (int i = 0; i < n; ++ i)
735 {
736 const chomp::homology::chain<euclidom> &column =
737 matr. getcol (i);
738 if (column. size () != 1)
739 continue;
740 if (column. coef (0) != minus1)
741 continue;
742 if (column. num (0) <= i)
743 continue;
744 matr. multiplyrow (i, minus1);
745 matr. multiplycol (i, minus1);
746 }
747 }
748 }
749
750 return 0;
751} /* ConleyIndex::reduce */
752
753template <class IndexPair, class euclidom>
755{
756 if ((newlevel >= -1) && (newlevel <= toplevel))
757 {
758 toplevel = newlevel;
759 coef. erase (coef. begin () + toplevel + 1, coef. end ());
760 }
761 return;
762} /* ConleyIndex<IndexPair,euclidom>::truncate */
763
764template <class IndexPair, class euclidom>
766 std::vector<double> &Re, std::vector<double> &Im,
767 bool nonzero, bool sorted) const
768{
769 using chomp::homology::auto_array;
770
771 // if the level is out of scope, return the error code
772 if ((level < 0) || (level > toplevel))
773 return -1;
774
775 // retrieve the matrix and its size
776 const chomp::homology::mmatrix<euclidom> &m = indmap [level];
777 int fullsize = m. getncols ();
778 if (fullsize <= 0)
779 return 0;
780
781 // retrieve the indices not related to torsion
782 int size = fullsize;
783 const std::vector<euclidom> &coefs = coef [level];
784 std::vector<int> indices (size);
785 int current = 0;
786 for (int i = 0; i < fullsize; ++ i)
787 {
788 if (coefs [i]. delta () > 1)
789 {
790 indices [i] = -1;
791 -- size;
792 }
793 else
794 {
795 indices [i] = current;
796 ++ current;
797 }
798 }
799 if (size <= 0)
800 return 0;
801
802 // prepare data for the LAPACK function to compute the eigenvalues
803 char N = 'N';
804 int32 dimension = size;
805 auto_array<double> APtr (new double [size * size]);
806 double *A = APtr. get ();
807 auto_array<double> rePtr (new double [size]);
808 double *re = rePtr. get ();
809 auto_array<double> imPtr (new double [size]);
810 double *im = imPtr. get ();
811 int32 worksize = 3 * size + (2 * size + 128);
812 auto_array<double> workPtr (new double [worksize]);
813 double *work = workPtr. get ();
814 int32 result = 0;
815
816 // translate the chain matrix to the matrix of doubles
817 double *ptr = A;
818 for (int i = 0; i < size; ++ i)
819 {
820 for (int j = 0; j < size; ++ j)
821 {
822 *(ptr ++) = 0;
823 }
824 }
825 for (int col = 0; col < fullsize; ++ col)
826 {
827 int icol = indices [col];
828 if (icol < 0)
829 continue;
830 const chomp::homology::chain<euclidom> c = m. getcol (col);
831 int len = c. size ();
832 for (int i = 0; i < len; ++ i)
833 {
834 int irow = indices [c. num (i)];
835 if (irow < 0)
836 continue;
837 euclidom e = c. coef (i);
838 int n = e. delta ();
839 euclidom e1;
840 e1 = n;
841 if (e1 != e)
842 n = -n;
843 A [size * irow + icol] = n;
844 }
845 }
846
847 // call the LAPACK function to compute the eigenvalues of the map
848 // (note: the eigenvalues of A^T are the same as of the eigenvalues
849 // of A, so I don't care that the matrices are reprsented
850 // in a different way in Fortran)
851 dgeev_ (&N, &N, &dimension, A, &dimension, re, im,
852 0, &dimension, 0, &dimension, work, &worksize, &result);
853
854 // throw an error message in case of failure
855 if (result < 0)
856 throw "Conley Index eigenvalues: LAPACK error.";
857 else if (result > 0)
858 throw "The QR algorithm failed in the Conley Index "
859 "Eigenvalues computation.";
860
861 // gather the output data
862 std::vector<ppComplex> values;
863 const double epsilon = 0.001;
864 const double threshold = 0.01;
865 for (int i = 0; i < size; ++ i)
866 {
867 re [i] = round (re [i], epsilon, threshold);
868 im [i] = round (im [i], epsilon, threshold);
869 if (nonzero && !re [i] && !im [i])
870 continue;
871 values. push_back (ppComplex (re [i], im [i]));
872 }
873
874 // make a note of any nontrivial eigenvalues
875 if (values. size ())
876 nontrivialindex = 1;
877
878 // sort the eigenvalues if requested to
879 if (sorted)
880 std::sort (values. begin (), values. end ());
881
882 // write the results to the provided data structures
883 for (std::vector<ppComplex>::const_iterator it = values. begin ();
884 it != values. end (); ++ it)
885 {
886 Re. push_back (it -> re);
887 Im. push_back (it -> im);
888 }
889
890 return values. size ();
891} /* ConleyIndex<IndexPair,euclidom>::eigenvalues */
892
893template <class IndexPair, class euclidom>
895{
896 // if the answer has already been computed before, use it now
897 if (nontrivialindex >= 0)
898 return !nontrivialindex;
899
900 for (int level = 0; level <= toplevel; ++ level)
901 {
902 std::vector<double> Re, Im;
903 int n = eigenvalues (level, Re, Im, true, false);
904 if (n)
905 {
906 nontrivialindex = 1;
907 return false;
908 }
909 // if (coef [level]. size () && (indmap [level]. getncols () > 0))
910 // return false;
911 }
912 nontrivialindex = 0;
913 return true;
914} /* ConleyIndex::trivial */
915
916template <class IndexPair, class euclidom>
917inline std::string ConleyIndex<IndexPair,euclidom>::EigenString (int n) const
918{
919 // make sure the level is correct
920 if (!indmap || (n < 0) || (n > toplevel))
921 return std::string ();
922
923 // prepare the output string stream
924 std::ostringstream out;
925
926 // compute the nonzero eigenvalues and sort them
927 std::vector<double> Re, Im;
928 int count = eigenvalues (n, Re, Im);
929 if (count > 0)
930 nontrivialindex = 1;
931
932 // output the eigenvalues
933 out << "Eigenvalues " << n << ": (";
934 if (count >= 0)
935 {
936 for (int i = 0; i < count; ++ i)
937 {
938 if (i)
939 out << ", ";
940 if (Re [i])
941 {
942 out << Re [i];
943 if (Im [i] > 0)
944 out << "+";
945 }
946 if (Im [i])
947 out << Im [i] << "i";
948 }
949 }
950 else
951 out << "ERROR";
952 out << ").";
953
954 return out. str ();
955} /* ConleyIndex::EigenString */
956
957template <class IndexPair, class euclidom>
958inline void ConleyIndex<IndexPair,euclidom>::define (const int *betti,
959 const chomp::homology::mmatrix<euclidom> *matr, int _toplevel)
960{
961 // reset the potentially remembered nontriviality
962 nontrivialindex = -1;
963
964 // set the top level of homology
965 toplevel = _toplevel;
966
967 // create the coefficients vector
968 coef. clear ();
969 euclidom e;
970 e = 1;
971 for (int i = 0; i <= toplevel; ++ i)
972 {
973 std::vector<euclidom> b;
974 for (int j = betti [i]; j > 0; -- j)
975 b. push_back (e);
976 coef. push_back (b);
977 }
978
979 // set the index maps
980 if (indmap)
981 {
982 delete [] indmap;
983 indmap = 0;
984 }
985 if (toplevel >= 0)
986 {
987 indmap = new chomp::homology::mmatrix<euclidom>
988 [toplevel + 1];
989 }
990 for (int level = 0; level <= toplevel; ++ level)
991 {
992 indmap [level] = matr [level];
993 }
994 return;
995} /* ConleyIndex::define */
996
997template <class IndexPair, class euclidom>
998inline void ConleyIndex<IndexPair,euclidom>::define (const int *betti,
999 int _toplevel)
1000{
1001 // create an array of the identity maps
1002 chomp::homology::mmatrix<euclidom> *matr = (_toplevel < 0) ? 0 :
1003 new chomp::homology::mmatrix<euclidom> [_toplevel + 1];
1004 for (int level = 0; level <= _toplevel; ++ level)
1005 {
1006 if (betti [level] > 0)
1007 matr [level]. identity (betti [level]);
1008 }
1009
1010 // define the index
1011 this -> define (betti, matr, _toplevel);
1012
1013 // clean up and finalize
1014 if (matr)
1015 delete [] matr;
1016 return;
1017} /* ConleyIndex::define */
1018
1019// --------------------------------------------------
1020
1021template <class IndexPair, class euclidom>
1022std::ostream &operator << (std::ostream &out,
1024{
1025 // write the top level
1026 out << c. toplevel << " ";
1027 if (c. toplevel < 0)
1028 return out;
1029
1030 // write the coefficients
1031 for (int i = 0; i <= c. toplevel; ++ i)
1032 {
1033 int size = c. coef [i]. size ();
1034 out << size << " ";
1035 for (int j = 0; j < size; ++ j)
1036 out << c. coef [i] [j] << " ";
1037 }
1038
1039 // write the maps
1040 for (int i = 0; i <= c. toplevel; ++ i)
1041 {
1042 const chomp::homology::mmatrix<euclidom> &m = c. indmap [i];
1043 out << m. getnrows () << " " << m. getncols () << " ";
1044 for (int j = 0; j < m. getncols (); ++ j)
1045 {
1046 const chomp::homology::chain<euclidom> &col =
1047 m. getcol (j);
1048 out << col. size () << " ";
1049 for (int k = 0; k < col. size (); ++ k)
1050 {
1051 out << col. num (k) << " ";
1052 out << col. coef (k) << " ";
1053 }
1054 }
1055 }
1056
1057 return out;
1058} /* operator << */
1059
1060template <class IndexPair, class euclidom>
1061std::istream &operator >> (std::istream &in,
1063{
1064 // reset the data
1065 c. nontrivialindex = -1;
1066 if (c. indmap)
1067 {
1068 delete [] c. indmap;
1069 c. indmap = 0;
1070 }
1071 c. coef. clear ();
1072
1073 // read the top level
1074 in >> c. toplevel;
1075 if (c. toplevel < 0)
1076 return in;
1077
1078 // read the coefficients
1079 for (int i = 0; i <= c. toplevel; ++ i)
1080 {
1081 int size = -1;
1082 in >> size;
1083 if (size < 0)
1084 throw "Cannot decode the Conley index from input.";
1085 std::vector<euclidom> coef;
1086 for (int j = 0; j < size; ++ j)
1087 {
1088 euclidom e;
1089 e = 0;
1090 in >> e;
1091 if (e. delta () <= 0)
1092 throw "Wrong coefficient in the "
1093 "Conley index from input.";
1094 coef. push_back (e);
1095 }
1096 c. coef. push_back (coef);
1097 }
1098
1099 // read the maps
1100 if (c. toplevel >= 0)
1101 c. indmap = new chomp::homology::mmatrix<euclidom>
1102 [c. toplevel + 1];
1103 for (int i = 0; i <= c. toplevel; ++ i)
1104 {
1105 chomp::homology::mmatrix<euclidom> &m = c. indmap [i];
1106 int nrows = 0, ncols = 0;
1107 in >> nrows >> ncols;
1108 if ((nrows < 0) || (ncols < 0))
1109 throw "Wrong matrix size in the Conley index "
1110 "from input.";
1111 if ((nrows > 0) && (ncols > 0))
1112 m. define (nrows, ncols);
1113 for (int j = 0; j < ncols; ++ j)
1114 {
1115 int length = -1;
1116 in >> length;
1117 if (length < 0)
1118 throw "Negative column length in the "
1119 "Conley index from input.";
1120 for (int k = 0; k < length; ++ k)
1121 {
1122 int num = -1;
1123 in >> num;
1124 if ((num < 0) || (num >= nrows))
1125 throw "Wrong row number in the "
1126 "Conley index from input.";
1127 euclidom e;
1128 e = 0;
1129 in >> e;
1130 if (e. delta () <= 0)
1131 throw "Wrong matrix entry in the "
1132 "Conley index from input.";
1133 m. add (num, j, e);
1134 }
1135 }
1136 }
1137
1138 return in;
1139} /* operator >> */
1140
1141/// Writes the Conley index information in human-readable form
1142/// to an output stream.
1143template <class IndexPair, class euclidom>
1144std::ostream &writeIndexInfo (std::ostream &out,
1146 const char *newline = "\n")
1147{
1148 int toplevel = c. dim ();
1149 out << "Homology: " << c. HomString () << newline;
1150 for (int n = 0; n <= toplevel; ++ n)
1151 {
1152 out << "- Level " << n << ":" << newline;
1153 out << "Nonzero eigenvalues: " << c. EigenString (n) <<
1154 newline;
1155 out << c. MapString (n, newline);
1156 }
1157 return out;
1158} /* writeIndexInfo */
1159
1160
1161#endif // _CMGRAPHS_CONINDEX_H_
1162
The class that computes and returns properties of the Conley index.
Definition: conindex.h:86
bool trivial() const
Verifies if the index is trivial.
Definition: conindex.h:894
const chomp::homology::mmatrix< euclidom > * Map(int n) const
Retrieves the matrix of the index map at the given level.
Definition: conindex.h:315
int eigenvalues(int level, std::vector< double > &Re, std::vector< double > &Im, bool nonzero=true, bool sorted=true) const
Computes the eigenvalues of the index map.
Definition: conindex.h:765
int nontrivialindex
Variable that stores the tabulated information on whether the index is nontrivial.
Definition: conindex.h:194
void define(const int *betti, const chomp::homology::mmatrix< euclidom > *matr, int _toplevel)
Defines the Conley index by the given Betti numbers and the given maps in homology.
Definition: conindex.h:958
std::vector< std::vector< euclidom > > coef
The torsion coefficients of the corresponding homology generators.
Definition: conindex.h:172
const IndexPair * cf
An object that feeds this class with cubes.
Definition: conindex.h:165
int toplevel
The number of the top homology level.
Definition: conindex.h:168
~ConleyIndex()
The destructor.
Definition: conindex.h:268
euclidom Coefficient(int n, int i) const
Retrieves the 'i'th [torsion] coefficient at the nth level.
Definition: conindex.h:324
void setIndexPair(const IndexPair *f)
Sets the index pair to be used to compute the Conley index.
Definition: conindex.h:277
int dim() const
Retrieves the top level, or the maximal dimension of the index.
Definition: conindex.h:337
int compute(bool twolayer=false)
Computes the Conley index.
Definition: conindex.h:417
ConleyIndex(const IndexPair *c=0)
The default constructor.
Definition: conindex.h:221
std::string HomString() const
Retrieves a human-readable text representation of the homology.
Definition: conindex.h:368
std::string MapString(int n, const char *newline="\n") const
Retrieves a human-readable text representation of the map.
Definition: conindex.h:343
chomp::homology::mmatrix< euclidom > * indmap
The matrices of the index map at each level.
Definition: conindex.h:175
int BettiNumber(int n) const
Retrieves the nth Betti number.
Definition: conindex.h:301
void truncate(int newlevel)
Truncates the Conley index to the new top level.
Definition: conindex.h:754
static double round(double x, double epsilon, double threshold)
Rounds a real number to the given precision.
Definition: conindex.h:284
int reduce(bool shrink=true)
Reduces the index map using some shift equivalences to certain extent.
Definition: conindex.h:617
std::string EigenString(int n) const
Retrieves a human-readable text showing the eigenvalues.
Definition: conindex.h:917
The empty index pair class simulates an empty index pair.
Definition: indpair.h:67
A generic class that computes an index pair given the isolating neighborhood and a means to compute t...
Definition: indpair.h:104
cubetype CubeType
The type of a cube.
Definition: indpair.h:107
cubsettype CubSetType
The type of a set of cubes.
Definition: indpair.h:110
Choice of configuration settings.
std::istream & operator>>(std::istream &in, ConleyIndex< IndexPair, euclidom > &c)
Definition: conindex.h:1061
int dgeev_(char *jobvl, char *jobvr, int32 *n, double *a, int32 *lda, double *wr, double *wi, double *vl, int32 *ldvl, double *vr, int32 *ldvr, double *work, int32 *lwork, int32 *info)
bool operator<(const ppComplex &x, const ppComplex &y)
Definition: conindex.h:209
std::ostream & operator<<(std::ostream &out, const ConleyIndex< IndexPair, euclidom > &c)
Definition: conindex.h:1022
std::ostream & writeIndexInfo(std::ostream &out, const ConleyIndex< IndexPair, euclidom > &c, const char *newline="\n")
Writes the Conley index information in human-readable form to an output stream.
Definition: conindex.h:1144
The Conley index pair computation.
Map computation routines.
An auxiliary class that represents complex numbers.
Definition: conindex.h:203
ppComplex(double _re, double _im)
Definition: conindex.h:205
double re
Definition: conindex.h:204
double im
Definition: conindex.h:204
Customizable data types for the Conley-Morse graphs computation program.