The Conley-Morse Graphs Software
matchdec.h
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////////
2///
3/// @file matchdec.h
4///
5/// Matching Morse decompositions.
6/// This file contains the definitions of a procedure for matching
7/// Morse decompositions. A relation between the sets of Morse sets
8/// for two Morse decompositions is determined by checking which Morse sets
9/// intersect their counterparts. If this relation is a bijection then
10/// the edges in Morse graphs is also verified.
11///
12/// @author Pawel Pilarczyk
13///
14/////////////////////////////////////////////////////////////////////////////
15
16// Copyright (C) 1997-2014 by Pawel Pilarczyk.
17//
18// This file is part of my research software package. This is free software:
19// you can redistribute it and/or modify it under the terms of the GNU
20// General Public License as published by the Free Software Foundation,
21// either version 3 of the License, or (at your option) any later version.
22//
23// This software is distributed in the hope that it will be useful,
24// but WITHOUT ANY WARRANTY; without even the implied warranty of
25// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26// GNU General Public License for more details.
27//
28// You should have received a copy of the GNU General Public License
29// along with this software; see the file "license.txt". If not,
30// please, see <https://www.gnu.org/licenses/>.
31
32// Started on February 16, 2008. Last revision: March 19, 2008.
33
34
35#ifndef _CMGRAPHS_MATCHDEC_H_
36#define _CMGRAPHS_MATCHDEC_H_
37
38
39// include some standard C++ header files
40#include <vector>
41#include <algorithm>
42#include <new>
43
44// include selected header files from the CHomP library
45#include "chomp/system/config.h"
46#include "chomp/system/textfile.h"
47#include "chomp/struct/digraph.h"
48#include "chomp/struct/flatmatr.h"
49#include "chomp/struct/autoarray.h"
50
51// include local header files
52#include "config.h"
53#include "typedefs.h"
54#include "typedyns.h"
55#include "matcharr.h"
56
57
58// --------------------------------------------------
59// --------- intersections of cubical sets ----------
60// --------------------------------------------------
61
62/// Verifies whether two sets of cubes intersect each other.
63/// Returns "true" if they share at least one common cube
64/// or "false" otherwise.
65template <class typeCubes>
66inline bool intersect (const typeCubes &X, const typeCubes &Y)
67{
68 // choose the smaller set and the larger one
69 bool XY = (X. size () < Y. size ());
70 const typeCubes &smaller = XY ? X : Y;
71 const typeCubes &larger = XY? Y : X;
72
73 // check each cube in the smaller set if it is in the larger one
74 int smallerSize = smaller. size ();
75 for (int i = 0; i < smallerSize; ++ i)
76 {
77 if (larger. check (smaller [i]))
78 return true;
79 }
80
81 return false;
82} /* intersect */
83
84/// Verifies whether two sets of cubes intersect each other.
85/// The first set is with respect to a twice finer grid that the other one.
86/// Returns "true" if they share at least one common cube
87/// or "false" otherwise.
88template <class typeCubes>
89inline bool intersectSub (const typeCubes &fine, const typeCubes &coarse)
90{
91 using chomp::homology::auto_array;
92
93 typedef typename typeCubes::value_type typeCube;
94 typedef typename typeCube::CoordType typeCoord;
95
96 // determine the number of cubes in the first set
97 int size = fine. size ();
98 if (!size)
99 return false;
100
101 // determine the dimension of the cubes and allocate working memory
102 int dim = fine [0]. dim ();
103 auto_array<typeCoord> coordPtr (new typeCoord [dim]);
104 typeCoord *coord = coordPtr. get ();
105
106 // check each cube in the finer set if it is contained
107 // in some cube in the coarser set
108 for (int i = 0; i < size; ++ i)
109 {
110 fine [i]. coord (coord);
111 for (int j = 0; j < dim; ++ j)
112 coord [j] /= 2;
113 if (coarse. check (typeCube (coord, dim)))
114 return true;
115 }
116
117 return false;
118} /* intersectSub */
119
120
121// --------------------------------------------------
122// -------------- matching Morse sets ---------------
123// --------------------------------------------------
124
125/// Verifies if the two given Morse decompositions are equivalent
126/// by matching Morse sets which intersect each other.
127/// If requested, matches also the ordering in the Morse decomposition.
128inline bool matchMorseSets (const theMorseDecompositionType &morseDecM,
129 const std::vector<int> &wrongIndM, const theCubMapType &theCubMap1M,
130 std::vector<spcCubes> &refinedM,
131 const theMorseDecompositionType &morseDecN,
132 const std::vector<int> &wrongIndN, const theCubMapType &theCubMap1N,
133 std::vector<spcCubes> &refinedN,
134 bool matchOrdering)
135{
136 using chomp::homology::sbug;
137
138 // check the numbers of Morse sets in both Morse decompositions
139 int nSets = morseDecM. count ();
140 if (nSets != morseDecN. count ())
141 return false;
142 if (!nSets)
143 return true;
144
145 // try to determine which Morse sets in one Morse decomposition
146 // intersect which Morse sets in the other Morse decomposition
147 std::vector<std::vector<int> > MtoN (nSets);
148 std::vector<std::vector<int> > NtoM (nSets);
149 for (int m = 0; m < nSets; ++ m)
150 {
151 for (int n = 0; n < nSets; ++ n)
152 {
153 if (!intersect (morseDecM [m], morseDecN [n]))
154 continue;
155 MtoN [m]. push_back (n);
156 NtoM [n]. push_back (m);
157 }
158 }
159
160 // check the bijection of intersections
161 bool bijection = true;
162 for (int i = 0; i < nSets; ++ i)
163 {
164 if (MtoN [i]. empty () || NtoM [i]. empty ())
165 return false;
166 if ((MtoN [i]. size () > 1) || (NtoM [i]. size () > 1))
167 bijection = false;
168 }
169
170 // in case of no bijection, try refining some of the Morse sets
171 if (!bijection)
172 {
173 // show a message on what is going to be done
174 sbug << "Note: No bijection in matching. Refining...\n";
175
176 // increase the arrays of refined Morse sets
177 if (refinedM. empty ())
178 refinedM. resize (nSets);
179 if (refinedN. empty ())
180 refinedN. resize (nSets);
181
182 // prepare a list of Morse sets which take part
183 // in the ambiguous intersections
184 std::vector<bool> refineM (nSets, false);
185 std::vector<bool> refineN (nSets, false);
186 for (int n = 0; n < nSets + nSets; ++ n)
187 {
188 // prepare variables for M -> N or N -> M
189 int index = (n < nSets) ? n : (n - nSets);
190 std::vector<std::vector<int> > &AtoB =
191 (n < nSets) ? MtoN : NtoM;
192 if (AtoB [index]. size () <= 1)
193 continue;
194 std::vector<bool> &refineA =
195 (n < nSets) ? refineM : refineN;
196 std::vector<bool> &refineB =
197 (n < nSets) ? refineN : refineM;
198
199 // mark the numbers of sets which should be refined
200 refineA [index] = true;
201 for (unsigned i = 0; i < AtoB [index]. size (); ++ i)
202 refineB [AtoB [index] [i]] = true;
203 }
204
205 // refine all the Morse sets for which ambiguity was found
206 for (int n = 0; n < nSets + nSets; ++ n)
207 {
208 // prepare variables for M -> N or N -> M
209 int index = (n < nSets) ? n : (n - nSets);
210 std::vector<bool> &refineA =
211 (n < nSets) ? refineM : refineN;
212 if (!refineA [index])
213 continue;
214 std::vector<spcCubes> &refinedA =
215 (n < nSets) ? refinedM : refinedN;
216 if (!refinedA [index]. empty ())
217 continue;
218 const theMorseDecompositionType &morseDecA =
219 (n < nSets) ? morseDecM : morseDecN;
220 if (morseDecA [index]. size () > maxRefineSize0)
221 continue;
222 const theCubMapType &theCubMap1 =
223 (n < nSets) ? theCubMap1M : theCubMap1N;
224 sbug << "- match subdiv " <<
225 morseDecA [index]. size () << " -> ";
226 subdivideCubes (morseDecA [index], refinedA [index]);
227 sbug << refinedA [index]. size () << ". ";
228 int result = invariantPart (refinedA [index],
229 theCubMap1);
230 if (result < 0)
231 {
232 spcCubes emptySet;
233 refinedA [index] = emptySet;
234 }
235 }
236
237 // compare the refined Morse sets to avoid the ambiguity
238 for (int n = 0; n < nSets + nSets; ++ n)
239 {
240 // prepare variables for M -> N or N -> M
241 int indA = (n < nSets) ? n : (n - nSets);
242 std::vector<std::vector<int> > &AtoB =
243 (n < nSets) ? MtoN : NtoM;
244 if (AtoB. size () <= 1)
245 continue;
246 std::vector<std::vector<int> > &BtoA =
247 (n < nSets) ? NtoM : MtoN;
248 const theMorseDecompositionType &morseDecA =
249 (n < nSets) ? morseDecM : morseDecN;
250 const theMorseDecompositionType &morseDecB =
251 (n < nSets) ? morseDecN : morseDecM;
252 std::vector<spcCubes> &refinedA =
253 (n < nSets) ? refinedM : refinedN;
254 std::vector<spcCubes> &refinedB =
255 (n < nSets) ? refinedN : refinedM;
256
257 // modify the relation A -> B
258 std::vector<int>::iterator begin =
259 AtoB [indA]. begin ();
260 for (unsigned i = 0; i < AtoB [indA]. size (); ++ i)
261 {
262 // determine the index in B
263 int indB = AtoB [indA] [i];
264
265 // check which Morse sets are refined
266 bool refA = !refinedA [indA]. empty ();
267 bool refB = !refinedB [indB]. empty ();
268
269 // verify the intersection of the sets
270 if (refA && refB && intersect
271 (refinedA [indA], refinedB [indB]))
272 {
273 continue;
274 }
275 else if (refA && !refB && intersectSub
276 (refinedA [indA], morseDecB [indB]))
277 {
278 continue;
279 }
280 else if (!refA && refB && intersectSub
281 (refinedB [indB], morseDecA [indA]))
282 {
283 continue;
284 }
285 else if (!refA && !refB)
286 continue;
287
288 // remove the link A <-> B
289 BtoA [indB]. erase (std::find
290 (BtoA [indB]. begin (),
291 BtoA [indB]. end (), indA));
292 AtoB [indA]. erase (begin + i);
293 -- i;
294 }
295 }
296
297 // check the bijection of intersections for the second time
298 for (int i = 0; i < nSets; ++ i)
299 {
300 if (MtoN [i]. empty () || NtoM [i]. empty ())
301 {
302 sbug << "WARNING: The intersection became "
303 "empty!!!\n";
304 return false;
305 }
306 if ((MtoN [i]. size () > 1) ||
307 (NtoM [i]. size () > 1))
308 {
309 sbug << "Note: No bijection in matching, "
310 "even after refinements.\n";
311 return false;
312 }
313 }
314 }
315
316 // check if the Morse sets with wrong indices match each other
317 if (wrongIndM. size () != wrongIndN. size ())
318 return false;
319 int wrongIndSize = wrongIndM. size ();
320 for (int i = 0; i < wrongIndSize; ++ i)
321 {
322 int number = MtoN [wrongIndM [i]] [0];
323 bool found = false;
324 for (int j = 0; j < wrongIndSize; ++ j)
325 {
326 if (wrongIndN [j] != number)
327 continue;
328 found = true;
329 break;
330 }
331 if (!found)
332 return false;
333 }
334
335 // compare the graphs of the Morse decompositions
336 if (matchOrdering)
337 {
338 // create the arrays with connections for both Morse decomps
339 chomp::homology::flatMatrix<char> orderM (nSets);
340 chomp::homology::flatMatrix<char> orderN (nSets);
341 for (int i = 0; i < nSets; ++ i)
342 {
343 for (int j = 0; j < nSets; ++ j)
344 {
345 orderM [i] [j] = morseDecM.
346 connected (i, j) ? 1 : 0;
347 orderN [i] [j] = morseDecN. connected
348 (MtoN [i] [0], MtoN [j] [0]) ? 1 : 0;
349 }
350 }
351
352 // compute the transitive closure of the ordering
353 chomp::homology::transitiveClosure (orderM, nSets);
354 chomp::homology::transitiveClosure (orderN, nSets);
355
356 // compare the arrays if they are the same indeed
357 const char *memoryM = orderM. memory ();
358 const char *memoryN = orderN. memory ();
359 int memSize = nSets * nSets;
360 for (int i = 0; i < memSize; ++ i)
361 {
362 if (*(memoryM ++) != *(memoryN ++))
363 {
364 sbug << "Note: Different Morse ordering.\n";
365 return false;
366 }
367 }
368 // sbug << "Note: Morse order matched.\n";
369 }
370
371 return true;
372} /* matchMorseSets */
373
374
375// --------------------------------------------------
376// ---------- matching Morse decompositions ---------
377// --------------------------------------------------
378
379/// Matches Morse decompositions corresponding to parameter cubes
380/// in the entire range. The set of cubes is used to determine
381/// the numbers in the indexing of Morse decompositions.
382inline void matchMorseDecompositions (const parCubes &paramBoxes,
383 const std::vector<theMorseDecompositionType *> &morseDec,
384// const std::vector<theMapType *> &theMap,
385// const double *offset, const double *width, int subdivDepth,
386// const std::vector<theCubMapType *> &theCubMap0,
387 const std::vector<theCubMapType *> &theCubMap1,
388 const std::vector<std::vector<int> > &wrongIndices,
389 const parCoord *parLeft, const parCoord *parRight,
390 std::vector<std::vector<parCube> > &matchClasses)
391{
392 using chomp::homology::sbug;
393
394 // create an array for matching the set of Morse decompositions
395 parCoord sizes [paramDim];
396 for (int i = 0; i < paramDim; ++ i)
397 sizes [i] = parRight [i] - parLeft [i];
398 MatchArray<parCoord,int> matchArray (paramDim, sizes, parLeft);
399
400 // determine the total number of boxes to process
401 int nBoxes = paramBoxes. size ();
402
403 // prepare an array of refined Morse sets
404 std::vector<std::vector<spcCubes> > refined (nBoxes);
405
406 // process all the neighbors of each Morse set while avoiding
407 // repetitive verification for the same pairs
408 for (int boxNumber = 0; boxNumber < nBoxes; ++ boxNumber)
409 {
410 // retrieve the coordinates of the box
411 parCoord coord [paramDim];
412 paramBoxes [boxNumber]. coord (coord);
413
414 // prepare the coordinates of the corners of the neighborhood
415 parCoord coordLeft [paramDim];
416 parCoord coordRight [paramDim];
417 for (int i = 0; i < paramDim; ++ i)
418 {
419 coordLeft [i] = coord [i] - 1;
420 if (coordLeft [i] < parLeft [i])
421 coordLeft [i] = parLeft [i];
422 coordRight [i] = coord [i] + 2;
423 if (coordRight [i] > parRight [i])
424 coordRight [i] = parRight [i];
425 }
426
427 // iterate the neighbors of the cube (including itself)
428 parRect neighbors (coordLeft, coordRight, paramDim);
429 const parCoord *neighborCoord;
430 while ((neighborCoord = neighbors. get ()) != 0)
431 {
432 // make sure that the neighbor precedes
433 // the current box in the lexicographical order
434 int compare = 0;
435 for (int i = 0; i < paramDim; ++ i)
436 {
437 if (neighborCoord [i] < coord [i])
438 {
439 compare = -1;
440 break;
441 }
442 else if (neighborCoord [i] > coord [i])
443 {
444 compare = 1;
445 break;
446 }
447 }
448 if (compare >= 0)
449 continue;
450
451 // if the boxes have already been joined
452 // then skip the verification of continuation
453 if (matchArray. joined (coord, neighborCoord))
454 continue;
455
456 // check matching between the corresponding
457 // Morse decompositions
458 int neighborNumber = paramBoxes. getnumber
459 (parCube (neighborCoord, paramDim));
460 if (neighborNumber < 0)
461 throw "Matching a non-existent neighbor.";
462 sbug << "Matching " << parCube (coord, paramDim) <<
463 " & " << parCube (neighborCoord, paramDim) <<
464 "...\n";
465 bool matchResult = matchMorseSets
466 (*(morseDec [boxNumber]),
467 wrongIndices [boxNumber],
468 *(theCubMap1 [boxNumber]),
469 refined [boxNumber],
470 *(morseDec [neighborNumber]),
471 wrongIndices [neighborNumber],
472 *(theCubMap1 [neighborNumber]),
473 refined [neighborNumber],
475 if (matchResult == true)
476 {
477 sbug << "Success. :)\n";
478 matchArray. join (coord, neighborCoord);
479 }
480 else
481 {
482 sbug << "Failure. :(\n";
483 }
484 }
485 }
486
487 // retrieve classes larger than 1 from the array
488 matchArray. saveClasses (matchClasses);
489
490 return;
491} /* matchMorseDecompositions */
492
493
494#endif // _CMGRAPHS_MATCHDEC_H_
495
A generic map computation routine that computes a rigorous cubical multivalued map based on a functio...
Definition: mapcomp.h:69
The Morse decoposition class.
Definition: morsedec.h:65
Choice of configuration settings.
void invariantPart(typeCubes &X, const chomp::homology::diGraph<> &g, chomp::homology::diGraph<> *gInv=0)
Computes X := Inv (X) using the algorithm by Bill Kalies and Hyunju Ban.
Definition: invpart.h:60
Array for matching Morse decompositions.
bool matchMorseSets(const theMorseDecompositionType &morseDecM, const std::vector< int > &wrongIndM, const theCubMapType &theCubMap1M, std::vector< spcCubes > &refinedM, const theMorseDecompositionType &morseDecN, const std::vector< int > &wrongIndN, const theCubMapType &theCubMap1N, std::vector< spcCubes > &refinedN, bool matchOrdering)
Verifies if the two given Morse decompositions are equivalent by matching Morse sets which intersect ...
Definition: matchdec.h:128
bool intersect(const typeCubes &X, const typeCubes &Y)
Verifies whether two sets of cubes intersect each other.
Definition: matchdec.h:66
bool intersectSub(const typeCubes &fine, const typeCubes &coarse)
Verifies whether two sets of cubes intersect each other.
Definition: matchdec.h:89
void matchMorseDecompositions(const parCubes &paramBoxes, const std::vector< theMorseDecompositionType * > &morseDec, const std::vector< theCubMapType * > &theCubMap1, const std::vector< std::vector< int > > &wrongIndices, const parCoord *parLeft, const parCoord *parRight, std::vector< std::vector< parCube > > &matchClasses)
Matches Morse decompositions corresponding to parameter cubes in the entire range.
Definition: matchdec.h:382
const int paramDim
The dimension of the parameter space to iterate.
Definition: p_differ.h:67
const int maxRefineSize0
The maximal allowed size of a set of cubes in the phase space which can be refined at the initial sub...
Definition: p_differ.h:144
const bool compareMorseOrdering
Should the ordering between the Morse sets be taken into consideration while determining whether two ...
Definition: p_differ.h:201
Customizable data types for the Conley-Morse graphs computation program.
Data types for the dynamical systems data structures.
chomp::homology::tCubeFix< paramDim, parCoord > parCube
The type of a cube in the set of parameters.
Definition: typeparam.h:58
short int parCoord
The type of coordinates of cubes in the set of parameters.
Definition: typeparam.h:53
chomp::homology::tRectangle< parCoord > parRect
The type of a rectangle used to iterate sets of cubes of parameters.
Definition: typeparam.h:64
chomp::homology::hashedset< parCube > parCubes
The type of a set of cubes in the set of parameters.
Definition: typeparam.h:61
chomp::homology::hashedset< spcCube > spcCubes
The type of a set of cubes in the phase space.
Definition: typespace.h:58
void subdivideCubes(const typeCubes &X, typeCubes &result)
Subdivides one set of cubes to another set of cubes with respect to twice finer grid.
Definition: utils.h:590