00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef _CMGRAPHS_COMPMDEC_H_
00039 #define _CMGRAPHS_COMPMDEC_H_
00040
00041
00042
00043 #include <algorithm>
00044 #include <new>
00045 #include <iostream>
00046 #include <iomanip>
00047 #include <string>
00048 #include <fstream>
00049 #include <sstream>
00050 #include <cstdio>
00051
00052
00053 #include "chomp/system/textfile.h"
00054 #include "chomp/cubes/pointset.h"
00055 #include "chomp/struct/digraph.h"
00056 #include "chomp/struct/multitab.h"
00057 #include "chomp/system/timeused.h"
00058
00059
00060 #include "config.h"
00061 #include "typedefs.h"
00062 #include "conindex.h"
00063 #include "morsedec.h"
00064 #include "indcache.h"
00065 #include "invpart.h"
00066 #include "utils.h"
00067
00068
00069
00070
00071
00072
00073
00074
00075 class TConnTable
00076 {
00077 public:
00078
00079 TConnTable (int _n, chomp::homology::multitable
00080 <chomp::homology::multitable<int> > &_connections,
00081 chomp::homology::multitable<int> &_conncount,
00082 const int *_numTranslate);
00083
00084
00085 void operator () (int source, int target, int v);
00086
00087 private:
00088
00089 int n;
00090
00091
00092
00093 chomp::homology::multitable<chomp::homology::multitable<int> >
00094 &connections;
00095
00096
00097 chomp::homology::multitable<int> &conncount;
00098
00099
00100 const int *numTranslate;
00101
00102 };
00103
00104 inline TConnTable::TConnTable (int _n,
00105 chomp::homology::multitable<chomp::homology::multitable<int> > &
00106 _connections, chomp::homology::multitable<int> &_conncount,
00107 const int *_numTranslate):
00108 n (_n), connections (_connections), conncount (_conncount),
00109 numTranslate (_numTranslate)
00110 {
00111 int maxcount = n * n;
00112 for (int i = 0; i < maxcount; ++ i)
00113 conncount [i] = 0;
00114 return;
00115 }
00116
00117 inline void TConnTable::operator () (int source, int target, int v)
00118 {
00119 int pos = n * source + target;
00120 connections [pos] [conncount [pos] ++] = numTranslate [v];
00121 return;
00122 }
00123
00124
00125
00126
00127
00128 class TConnMorse
00129 {
00130 public:
00131
00132 TConnMorse (theMorseDecompositionType &_morseDec,
00133 const spcCubes &_X, const int *_numTranslate);
00134
00135
00136 void operator () (int source, int target, int v);
00137
00138 private:
00139
00140 theMorseDecompositionType &morseDec;
00141
00142
00143 const spcCubes &X;
00144
00145
00146 const int *numTranslate;
00147
00148 };
00149
00150 inline TConnMorse::TConnMorse (theMorseDecompositionType &_morseDec,
00151 const spcCubes &_X, const int *_numTranslate):
00152 morseDec (_morseDec), X (_X), numTranslate (_numTranslate)
00153 {
00154 return;
00155 }
00156
00157 inline void TConnMorse::operator () (int source, int target, int v)
00158 {
00159 morseDec. addconn (source, target, X [numTranslate [v]]);
00160 return;
00161 }
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 inline void setDummyIndex (theMorseDecompositionType &morseDec, int n,
00172 int nonzero = -1)
00173 {
00174 int betti [spaceDim + 1];
00175 for (int i = 0; i <= spaceDim; ++ i)
00176 betti [i] = (i == nonzero) ? 1 : 0;
00177 theConleyIndexType ind;
00178 ind. define (betti, spaceDim);
00179 morseDec. setindex (n, ind);
00180 return;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 inline int computeConleyIndex (theMorseDecompositionType &morseDec, int n,
00196 const double *offset, const double *width,
00197 int subdivDepth, const theMapType &theMap,
00198 const theCubMapType &theCubMap0, const theCubMapType &theCubMap1,
00199 int &subdivNonemptyInv, int &noIsolation, int &attractor)
00200 {
00201 using chomp::homology::sbug;
00202
00203
00204
00205 spcCubes X;
00206 for (int subdivisions = 0;; ++ subdivisions)
00207 {
00208
00209 theCubMapType subdivCubMap (offset, width,
00210 1 << (subdivDepth + subdivisions), theMap);
00211 subdivCubMap. cache = false;
00212 const theCubMapType &theCubMap =
00213 (subdivisions > 1) ? subdivCubMap :
00214 (subdivisions ? theCubMap1 : theCubMap0);
00215 bool crop = theCubMap. cropping;
00216
00217
00218 if (subdivisions)
00219 {
00220 try
00221 {
00222 int result = invariantPart (X, theCubMap);
00223 if (result < 0)
00224 {
00225 subdivNonemptyInv = 1;
00226 return -1;
00227 }
00228 if (X. empty ())
00229 {
00230 setDummyIndex (morseDec, n);
00231 subdivNonemptyInv = 0;
00232 return 0;
00233 }
00234 }
00235 catch (const char *msg)
00236 {
00237 subdivNonemptyInv = 1;
00238 sbug << "Failed: " << msg << "\n";
00239 sbug << "Failure: Unable to compute Inv.\n";
00240 return -1;
00241 }
00242 }
00243
00244
00245 const spcCubes &theSet = subdivisions ? X : morseDec [n];
00246
00247
00248
00249 try
00250 {
00251
00252 theIndexPairType P (theCubMap);
00253
00254
00255 int size = theSet. size ();
00256 for (int i = 0; i < size; ++ i)
00257 P. add (theSet [i]);
00258
00259
00260 theCubMap. cropping = true;
00261 theCubMap. cropped = false;
00262 P. compute ();
00263 theCubMap. cropping = crop;
00264
00265
00266 if (ignoreIsolationForConleyIndex ||
00267 !theCubMap. cropped)
00268 {
00269
00270 attractor = P. countExit () ? 0 : 1;
00271
00272
00273 theConleyIndexType ind;
00274 ind. setIndexPair (&P);
00275
00276
00277 ind. compute ();
00278 ind. setIndexPair (0);
00279
00280
00281 morseDec. setindex (n, ind);
00282 return 0;
00283 }
00284 }
00285 catch (const char *msg)
00286 {
00287 theCubMap. cropping = crop;
00288 sbug << "Failed: " << msg << "\n";
00289 }
00290
00291
00292 if (subdivisions == refineDepth)
00293 {
00294 sbug << "Failure: Max refinement depth " <<
00295 refineDepth << " reached.\n";
00296 subdivNonemptyInv = 1;
00297 if (theCubMap. cropped)
00298 noIsolation = 1;
00299 return -1;
00300 }
00301
00302
00303 int maxRefineSize =
00304 subdivisions? maxRefineSize0 : maxRefineSize1;
00305
00306
00307 if (theSet. size () > maxRefineSize)
00308 {
00309 sbug << "Failure: The set size " <<
00310 theSet. size () << " is beyond the max "
00311 "allowed " << maxRefineSize << ".\n";
00312 subdivNonemptyInv = 1;
00313 if (theCubMap. cropped)
00314 noIsolation = 1;
00315 return -1;
00316 }
00317
00318
00319 sbug << "- subdiv " << (subdivDepth + subdivisions + 1) <<
00320 ": " << theSet. size () << " -> ";
00321 spcCubes Y;
00322 subdivideCubes (theSet, Y);
00323 spcCubes emptySet;
00324 X = emptySet;
00325 X. swap (Y);
00326 sbug << X. size () << " ";
00327 }
00328
00329 return -1;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 template <class typeCubes, class typeMorseDec>
00353 void invMorseDec (const typeCubes &X, const chomp::homology::diGraph<> &g,
00354 typeMorseDec &morseDec,
00355 const double *offset, const double *width, int subdivDepth,
00356 const theMapType &theMap,
00357 const theCubMapType &theCubMap0, const theCubMapType &theCubMap1,
00358 int skipIndices,
00359 const std::string &cacheFileName, bool &morseDecComputed,
00360 std::vector<int> &wrongIndices, std::vector<int> &skippedIndices,
00361 std::vector<int> &attractors, bool connOrbits,
00362 const double *leftMapParam, const double *rightMapParam,
00363 int paramCount)
00364 {
00365 using chomp::homology::sbug;
00366 using chomp::homology::diGraph;
00367 using chomp::homology::multitable;
00368
00369
00370 if (X. empty ())
00371 return;
00372
00373
00374
00375 bool computeconn = connOrbits || (maxJoinSize > 0);
00376
00377
00378 multitable<int> compVertices, compEnds;
00379 diGraph<> *sccAddr = 0;
00380 diGraph<> *transpAddr = 0;
00381 int nSets = chomp::homology::SCC (g, compVertices, compEnds,
00382 sccAddr, transpAddr);
00383
00384
00385
00386 morseDec. setnumber (nSets);
00387 int countSCCcubes = 0;
00388 for (int n = 0; n < nSets; ++ n)
00389 {
00390
00391 int beginVertex = n ? compEnds [n - 1] : 0;
00392 int endVertex = compEnds [n];
00393 countSCCcubes += endVertex - beginVertex;
00394
00395
00396 for (int i = beginVertex; i < endVertex; ++ i)
00397 morseDec. add (n, X [compVertices [i]]);
00398 }
00399
00400
00401 {
00402
00403 int *newNumbers = computeconn ? new int [X. size ()] : 0;
00404 diGraph<> collapsed;
00405 chomp::homology::collapseVertices (g, nSets, compVertices,
00406 compEnds, collapsed, newNumbers);
00407
00408
00409 int *oldNumbers = computeconn ?
00410 new int [X. size () - countSCCcubes + nSets] : 0;
00411 if (oldNumbers)
00412 {
00413 for (int i = 0; i < X. size (); ++ i)
00414 oldNumbers [newNumbers [i]] = i;
00415 }
00416 if (newNumbers)
00417 delete [] newNumbers;
00418
00419
00420 diGraph<> connGraph;
00421 TConnMorse conn (morseDec, X, oldNumbers);
00422 if (computeconn)
00423 {
00424 chomp::homology::inclusionGraph (collapsed, nSets,
00425 connGraph, conn);
00426 }
00427 else
00428 {
00429 chomp::homology::inclusionGraph (collapsed, nSets,
00430 connGraph);
00431 }
00432 if (oldNumbers)
00433 delete [] oldNumbers;
00434
00435
00436 for (int v = 0; v < nSets; ++ v)
00437 {
00438 int nEdges = connGraph. countEdges (v);
00439 for (int e = 0; e < nEdges; ++ e)
00440 {
00441 int w = connGraph. getEdge (v, e);
00442 morseDec. addconn (v, w);
00443 }
00444 }
00445 }
00446
00447
00448 bool cacheIndices = !cacheFileName. empty ();
00449 std::string indFileNameStr = cacheFileName;
00450 const char *indFileName = indFileNameStr. c_str ();
00451 std::string lockFileNameStr = cacheFileName + ".lock";
00452 const char *lockFileName = lockFileNameStr. c_str ();
00453
00454
00455 bool cachedAvailable = false;
00456 IndexCache cached (nSets);
00457 if (cacheIndices && fileExists (indFileName))
00458 {
00459 if (fileExists (lockFileName))
00460 sbug << "! Skipping cached indices (locked).\n";
00461 else if (cached. read (indFileName, morseDec) != 0)
00462 sbug << "! Error while reading cached indices.\n";
00463 else
00464 {
00465 sbug << "[using cached Conley indices]\n";
00466 cachedAvailable = true;
00467 }
00468 }
00469 morseDecComputed = !cachedAvailable;
00470
00471
00472 spcCubes wrongCubes;
00473 spcCubes attrCubes;
00474 spcCubes skipCubes;
00475 std::vector<int> subdivNonemptyInv (nSets, -1);
00476 for (int n = 0; n < nSets; ++ n)
00477 {
00478 if (cachedAvailable)
00479 {
00480 if (cached. wrongIndex [n])
00481 wrongCubes. add (morseDec [n] [0]);
00482 if (cached. attractor [n])
00483 attrCubes. add (morseDec [n] [0]);
00484 if (cached. skipped [n])
00485 skipCubes. add (morseDec [n] [0]);
00486 continue;
00487 }
00488
00489
00490 if ((skipIndices > 0) &&
00491 (morseDec [n]. size () >= skipIndices))
00492 {
00493 sbug << "* Skipping ConIndex (" << n << ").\n";
00494 setDummyIndex (morseDec, n);
00495 subdivNonemptyInv [n] = 1;
00496 cached. skipped [n] = true;
00497 skipCubes. add (morseDec [n] [0]);
00498 }
00499
00500 else
00501 {
00502 sbug << "* Computing the Conley index "
00503 "of the Morse set no. " << n << " (" <<
00504 morseDec [n]. size () << " cubes)...\n";
00505 int noIsolation = -1;
00506 int attractor = -1;
00507 int result = computeConleyIndex (morseDec, n,
00508 offset, width, subdivDepth, theMap,
00509 theCubMap0, theCubMap1,
00510 subdivNonemptyInv [n], noIsolation,
00511 attractor);
00512 if (attractor > 0)
00513 {
00514 cached. attractor [n] = true;
00515 attrCubes. add (morseDec [n] [0]);
00516 }
00517 if (((result < 0) || (noIsolation > 0)) &&
00518 setConleyIndex (morseDec, n, subdivDepth,
00519 leftMapParam, rightMapParam, paramCount))
00520 {
00521 sbug << "* The index was set to an apriori "
00522 "known one.\n";
00523 }
00524 else if (result < 0)
00525 {
00526 sbug << "* Failed to compute the index.\n";
00527 setDummyIndex (morseDec, n);
00528 cached. wrongIndex [n] = true;
00529 wrongCubes. add (morseDec [n] [0]);
00530 }
00531 else if (noIsolation > 0)
00532 {
00533 sbug << "* No isolation detected. The index "
00534 "could not be computed reliably.\n";
00535 cached. wrongIndex [n] = true;
00536 wrongCubes. add (morseDec [n] [0]);
00537 }
00538 else
00539 {
00540 sbug << "* The computed index is " <<
00541 (morseDec. trivial (n) ?
00542 "" : "non") << "trivial.\n";
00543 }
00544 }
00545 }
00546
00547
00548 std::vector<int> passThru;
00549 for (int n = 0; n < nSets; ++ n)
00550 {
00551
00552 if (cachedAvailable)
00553 {
00554 if (cached. emptyInv [n])
00555 passThru. push_back (n);
00556 continue;
00557 }
00558
00559
00560 if (subdivNonemptyInv [n] == 1)
00561 continue;
00562
00563
00564
00565 if (subdivNonemptyInv [n] == 0)
00566 {
00567 passThru. push_back (n);
00568 cached. emptyInv [n] = true;
00569 continue;
00570 }
00571
00572
00573 if (!morseDec. trivial (n))
00574 continue;
00575
00576
00577 if (morseDec [n]. size () > maxRefineSize0)
00578 continue;
00579
00580
00581 sbug << "Refining the set no. " << n << " (" <<
00582 morseDec [n]. size () << " cubes)...\n";
00583 if (checkEmptyInv (morseDec [n], finalDepth,
00584 offset, width, theMap, theCubMap0, theCubMap1))
00585 {
00586 sbug << "Empty inv. The set will be removed.\n";
00587 passThru. push_back (n);
00588 cached. emptyInv [n] = true;
00589 }
00590 else
00591 {
00592 sbug << "Invariant part may be nonempty.\n";
00593 }
00594 }
00595
00596
00597
00598 if (cacheIndices && !cachedAvailable && !fileExists (indFileName) &&
00599 !fileExists (lockFileName))
00600 {
00601
00602 std::ofstream lockFile (lockFileName);
00603 lockFile. close ();
00604
00605
00606 cached. write (indFileName, morseDec);
00607
00608
00609 std::remove (lockFileName);
00610 }
00611
00612
00613 for (int i = passThru. size () - 1; i >= 0; -- i)
00614 {
00615 morseDec. passthru (passThru [i]);
00616 }
00617
00618
00619 if (maxJoinSize > 0)
00620 {
00621 sbug << "* " << morseDec. count () << " Morse sets; sizes: ";
00622 for (int i = 0; i < morseDec. count (); ++ i)
00623 sbug << (i ? " " : "") << morseDec [i]. size ();
00624 sbug << "\n! Joining trivial Morse sets (size: " <<
00625 maxJoinSize << ", conn: " << maxJoinConnection <<
00626 ", dist: " << maxJoinDistance << ")...\n";
00627 morseDec. jointrivial (maxJoinSize, maxJoinConnection,
00628 maxJoinDistance);
00629 }
00630
00631
00632 nSets = morseDec. count ();
00633
00634
00635
00636 for (int i = 0; i < wrongCubes. size (); ++ i)
00637 {
00638 int n = 0;
00639 while ((n < nSets) && !morseDec [n]. check (wrongCubes [i]))
00640 ++ n;
00641 if (n < nSets)
00642 wrongIndices. push_back (n);
00643 else
00644 {
00645 wrongIndices. push_back (-1);
00646 sbug << "Note: A Morse set with a wrong index "
00647 "could not be identified.\n";
00648 }
00649 }
00650
00651
00652 for (int i = 0; i < skipCubes. size (); ++ i)
00653 {
00654 int n = 0;
00655 while ((n < nSets) && !morseDec [n]. check (skipCubes [i]))
00656 ++ n;
00657 if (n < nSets)
00658 skippedIndices. push_back (n);
00659 else
00660 {
00661 skippedIndices. push_back (-1);
00662 sbug << "Note: A Morse set whose index was skipped "
00663 "could not be identified.\n";
00664 }
00665 }
00666
00667
00668 for (int i = 0; i < attrCubes. size (); ++ i)
00669 {
00670 int n = 0;
00671 while ((n < nSets) && !morseDec [n]. check (attrCubes [i]))
00672 ++ n;
00673 if (n < nSets)
00674 attractors. push_back (n);
00675 else
00676 {
00677 attractors. push_back (-1);
00678 sbug << "Note: A Morse set which is an attractor "
00679 "could not be identified.\n";
00680 }
00681 }
00682
00683
00684 sbug << "* " << morseDec. count () << " Morse sets [" <<
00685 attrCubes. size () << " attractor(s)]; sizes: ";
00686 for (int i = 0; i < morseDec. count (); ++ i)
00687 sbug << (i ? " " : "") << morseDec [i]. size ();
00688 sbug << "\n";
00689
00690 return;
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 inline theMorseDecompositionType *computeMorseDecomposition
00705 (const theMapType &theMap,
00706 const theCubMapType theCubMap0, const theCubMapType theCubMap1,
00707 const double *offset, const double *width, int skipIndices,
00708 const std::string &cacheFileName, bool &morseDecComputed,
00709 std::vector<int> &wrongIndices, std::vector<int> &skippedIndices,
00710 std::vector<int> &attractors, bool connOrbits,
00711 const double *leftMapParam, const double *rightMapParam,
00712 int paramCount)
00713 {
00714 using chomp::homology::sbug;
00715 using chomp::homology::diGraph;
00716 using chomp::homology::multitable;
00717
00718
00719 theMorseDecompositionType *morseDecPtr =
00720 new theMorseDecompositionType (theCubMap0);
00721 theMorseDecompositionType &morseDec = *morseDecPtr;
00722
00723
00724 spcCoord zero [spaceDim];
00725 for (int i = 0; i < spaceDim; ++ i)
00726 zero [i] = 0;
00727 spcCubes X;
00728 X. add (spcCube (zero, spaceDim));
00729
00730
00731 for (int subdivDepth = 1; subdivDepth <= finalDepth; ++ subdivDepth)
00732 {
00733
00734 {
00735 spcCubes Y;
00736 subdivideCubes (X, Y);
00737 X. swap (Y);
00738 }
00739
00740
00741
00742 if (subdivDepth < initialDepth)
00743 continue;
00744
00745
00746 sbug << "Depth " << subdivDepth << ": " <<
00747 X. size () << ". ";
00748
00749
00750
00751 theCubMapType localCubMap (offset, width,
00752 1 << subdivDepth, theMap);
00753
00754
00755
00756 const theCubMapType &theCubMap =
00757 (subdivDepth == finalDepth) ?
00758 theCubMap0 : localCubMap;
00759
00760
00761 sbug << "F... ";
00762 diGraph<> g;
00763 computeMapGraph (X, g, theCubMap);
00764
00765
00766 int avgImgSize = g. countEdges () /
00767 (X. size () ? X. size () : 1);
00768 sbug << "[avg " << avgImgSize << "] ";
00769
00770
00771
00772 if (subdivDepth == finalDepth)
00773 {
00774 sbug << "Morse dec...\n";
00775 invMorseDec (X, g, morseDec,
00776 offset, width, finalDepth,
00777 theMap, theCubMap0, theCubMap1,
00778 skipIndices, cacheFileName, morseDecComputed,
00779 wrongIndices, skippedIndices, attractors,
00780 connOrbits, leftMapParam, rightMapParam,
00781 paramCount);
00782 break;
00783 }
00784
00785
00786 sbug << "Inv... ";
00787 invariantPart (X, g);
00788 sbug << X. size () << " left.\n";
00789
00790
00791 if (false)
00792 {
00793 std::ostringstream fstr;
00794 fstr << "_inv" << subdivDepth;
00795 std::string filename = fstr. str ();
00796 std::ofstream f (filename. c_str ());
00797 f << "; Inv(X) at level " << subdivDepth << ".\n";
00798 f << X << "\n";
00799 sbug << "Inv(X) saved to " << filename << ".\n";
00800 }
00801 }
00802
00803 return morseDecPtr;
00804 }
00805
00806
00807 #endif // _CMGRAPHS_COMPMDEC_H_
00808
00809