matchdec.h

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////////
00002 ///
00003 /// @file matchdec.h
00004 ///
00005 /// Matching Morse decompositions.
00006 /// This file contains the definitions of a procedure for matching
00007 /// Morse decompositions. A relation between the sets of Morse sets
00008 /// for two Morse decompositions is determined by checking which Morse sets
00009 /// intersect their counterparts. If this relation is a bijection then
00010 /// the edges in Morse graphs is also verified.
00011 ///
00012 /// @author Pawel Pilarczyk
00013 ///
00014 /////////////////////////////////////////////////////////////////////////////
00015 
00016 // Copyright (C) 1997-2008 by Pawel Pilarczyk.
00017 //
00018 // This file is part of my research software package.  This is free software;
00019 // you can redistribute it and/or modify it under the terms of the GNU
00020 // General Public License as published by the Free Software Foundation;
00021 // either version 2 of the License, or (at your option) any later version.
00022 //
00023 // This software is distributed in the hope that it will be useful,
00024 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00026 // GNU General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License along
00029 // with this software; see the file "license.txt".  If not, write to the
00030 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00031 // MA 02111-1307, USA.
00032 
00033 // Started on February 16, 2008. Last revision: March 19, 2008.
00034 
00035 
00036 #ifndef _CMGRAPHS_MATCHDEC_H_
00037 #define _CMGRAPHS_MATCHDEC_H_
00038 
00039 
00040 // include some standard C++ header files
00041 #include <vector>
00042 #include <algorithm>
00043 #include <new>
00044 
00045 // include selected header files from the CHomP library
00046 #include "chomp/system/config.h"
00047 #include "chomp/system/textfile.h"
00048 #include "chomp/struct/digraph.h"
00049 #include "chomp/struct/flatmatr.h"
00050 
00051 // include local header files
00052 #include "config.h"
00053 #include "typedefs.h"
00054 #include "matcharr.h"
00055 
00056 
00057 // --------------------------------------------------
00058 // --------- intersections of cubical sets ----------
00059 // --------------------------------------------------
00060 
00061 /// Verifies whether two sets of cubes intersect each other.
00062 /// Returns "true" if they share at least one common cube
00063 /// or "false" otherwise.
00064 template <class typeCubes>
00065 inline bool intersect (const typeCubes &X, const typeCubes &Y)
00066 {
00067         // choose the smaller set and the larger one
00068         bool XY = (X. size () < Y. size ());
00069         const typeCubes &smaller = XY ? X : Y;
00070         const typeCubes &larger = XY? Y : X;
00071 
00072         // check each cube in the smaller set if it is in the larger one
00073         int smallerSize = smaller. size ();
00074         for (int i = 0; i < smallerSize; ++ i)
00075         {
00076                 if (larger. check (smaller [i]))
00077                         return true;
00078         }
00079 
00080         return false;
00081 } /* intersect */
00082 
00083 /// Verifies whether two sets of cubes intersect each other.
00084 /// The first set is with respect to a twice finer grid that the other one.
00085 /// Returns "true" if they share at least one common cube
00086 /// or "false" otherwise.
00087 template <class typeCubes>
00088 inline bool intersectSub (const typeCubes &fine, const typeCubes &coarse)
00089 {
00090         typedef typename typeCubes::value_type typeCube;
00091         typedef typename typeCube::CoordType typeCoord;
00092 
00093         // determine the number of cubes in the first set
00094         int size = fine. size ();
00095         if (!size)
00096                 return false;
00097 
00098         // determine the dimension of the cubes and allocate working memory
00099         int dim = fine [0]. dim ();
00100         std::auto_ptr<typeCoord> coordPtr (new typeCoord [dim]);
00101         typeCoord *coord = coordPtr. get ();
00102 
00103         // check each cube in the finer set if it is contained
00104         // in some cube in the coarser set
00105         for (int i = 0; i < size; ++ i)
00106         {
00107                 fine [i]. coord (coord);
00108                 for (int j = 0; j < dim; ++ j)
00109                         coord [j] /= 2;
00110                 if (coarse. check (typeCube (coord, dim)))
00111                         return true;
00112         }
00113 
00114         return false;
00115 } /* intersectSub */
00116 
00117 
00118 // --------------------------------------------------
00119 // -------------- matching Morse sets ---------------
00120 // --------------------------------------------------
00121 
00122 /// Verifies if the two given Morse decompositions are equivalent
00123 /// by matching Morse sets which intersect each other.
00124 /// If requested, matches also the ordering in the Morse decomposition.
00125 inline bool matchMorseSets (const theMorseDecompositionType &morseDecM,
00126         const std::vector<int> &wrongIndM, const theCubMapType &theCubMap1M,
00127         std::vector<spcCubes> &refinedM,
00128         const theMorseDecompositionType &morseDecN,
00129         const std::vector<int> &wrongIndN, const theCubMapType &theCubMap1N,
00130         std::vector<spcCubes> &refinedN,
00131         bool matchOrdering)
00132 {
00133         using chomp::homology::sbug;
00134 
00135         // check the numbers of Morse sets in both Morse decompositions
00136         int nSets = morseDecM. count ();
00137         if (nSets != morseDecN. count ())
00138                 return false;
00139         if (!nSets)
00140                 return true;
00141 
00142         // try to determine which Morse sets in one Morse decomposition
00143         // intersect which Morse sets in the other Morse decomposition
00144         std::vector<std::vector<int> > MtoN (nSets);
00145         std::vector<std::vector<int> > NtoM (nSets);
00146         for (int m = 0; m < nSets; ++ m)
00147         {
00148                 for (int n = 0; n < nSets; ++ n)
00149                 {
00150                         if (!intersect (morseDecM [m], morseDecN [n]))
00151                                 continue;
00152                         MtoN [m]. push_back (n);
00153                         NtoM [n]. push_back (m);
00154                 }
00155         }
00156 
00157         // check the bijection of intersections
00158         bool bijection = true;
00159         for (int i = 0; i < nSets; ++ i)
00160         {
00161                 if (MtoN [i]. empty () || NtoM [i]. empty ())
00162                         return false;
00163                 if ((MtoN [i]. size () > 1) || (NtoM [i]. size () > 1))
00164                         bijection = false;
00165         }
00166 
00167         // in case of no bijection, try refining some of the Morse sets
00168         if (!bijection)
00169         {
00170                 // show a message on what is going to be done
00171                 sbug << "Note: No bijection in matching. Refining...\n";
00172 
00173                 // increase the arrays of refined Morse sets
00174                 if (refinedM. empty ())
00175                         refinedM. resize (nSets);
00176                 if (refinedN. empty ())
00177                         refinedN. resize (nSets);
00178 
00179                 // prepare a list of Morse sets which take part
00180                 // in the ambiguous intersections
00181                 std::vector<bool> refineM (nSets, false);
00182                 std::vector<bool> refineN (nSets, false);
00183                 for (int n = 0; n < nSets + nSets; ++ n)
00184                 {
00185                         // prepare variables for M -> N or N -> M
00186                         int index = (n < nSets) ? n : (n - nSets);
00187                         std::vector<std::vector<int> > &AtoB =
00188                                 (n < nSets) ? MtoN : NtoM;
00189                         if (AtoB [index]. size () <= 1)
00190                                 continue;
00191                         std::vector<bool> &refineA =
00192                                 (n < nSets) ? refineM : refineN;
00193                         std::vector<bool> &refineB =
00194                                 (n < nSets) ? refineN : refineM;
00195 
00196                         // mark the numbers of sets which should be refined
00197                         refineA [index] = true;
00198                         for (unsigned i = 0; i < AtoB [index]. size (); ++ i)
00199                                 refineB [AtoB [index] [i]] = true;
00200                 }
00201 
00202                 // refine all the Morse sets for which ambiguity was found
00203                 for (int n = 0; n < nSets + nSets; ++ n)
00204                 {
00205                         // prepare variables for M -> N or N -> M
00206                         int index = (n < nSets) ? n : (n - nSets);
00207                         std::vector<bool> &refineA =
00208                                 (n < nSets) ? refineM : refineN;
00209                         if (!refineA [index])
00210                                 continue;
00211                         std::vector<spcCubes> &refinedA =
00212                                 (n < nSets) ? refinedM : refinedN;
00213                         if (!refinedA [index]. empty ())
00214                                 continue;
00215                         const theMorseDecompositionType &morseDecA =
00216                                 (n < nSets) ? morseDecM : morseDecN;
00217                         if (morseDecA [index]. size () > maxRefineSize0)
00218                                 continue;
00219                         const theCubMapType &theCubMap1 =
00220                                 (n < nSets) ? theCubMap1M : theCubMap1N;
00221                         sbug << "- match subdiv " <<
00222                                 morseDecA [index]. size () << " -> ";
00223                         subdivideCubes (morseDecA [index], refinedA [index]);
00224                         sbug << refinedA [index]. size () << ". ";
00225                         int result = invariantPart (refinedA [index],
00226                                 theCubMap1);
00227                         if (result < 0)
00228                         {
00229                                 spcCubes emptySet;
00230                                 refinedA [index] = emptySet;
00231                         }
00232                 }
00233 
00234                 // compare the refined Morse sets to avoid the ambiguity
00235                 for (int n = 0; n < nSets + nSets; ++ n)
00236                 {
00237                         // prepare variables for M -> N or N -> M
00238                         int indA = (n < nSets) ? n : (n - nSets);
00239                         std::vector<std::vector<int> > &AtoB =
00240                                 (n < nSets) ? MtoN : NtoM;
00241                         if (AtoB. size () <= 1)
00242                                 continue;
00243                         std::vector<std::vector<int> > &BtoA =
00244                                 (n < nSets) ? NtoM : MtoN;
00245                         const theMorseDecompositionType &morseDecA =
00246                                 (n < nSets) ? morseDecM : morseDecN;
00247                         const theMorseDecompositionType &morseDecB =
00248                                 (n < nSets) ? morseDecN : morseDecM;
00249                         std::vector<spcCubes> &refinedA =
00250                                 (n < nSets) ? refinedM : refinedN;
00251                         std::vector<spcCubes> &refinedB =
00252                                 (n < nSets) ? refinedN : refinedM;
00253 
00254                         // modify the relation A -> B
00255                         std::vector<int>::iterator begin =
00256                                 AtoB [indA]. begin ();
00257                         for (unsigned i = 0; i < AtoB [indA]. size (); ++ i)
00258                         {
00259                                 // determine the index in B
00260                                 int indB = AtoB [indA] [i];
00261 
00262                                 // check which Morse sets are refined
00263                                 bool refA = !refinedA [indA]. empty ();
00264                                 bool refB = !refinedB [indB]. empty ();
00265 
00266                                 // verify the intersection of the sets
00267                                 if (refA && refB && intersect
00268                                         (refinedA [indA], refinedB [indB]))
00269                                 {
00270                                         continue;
00271                                 }
00272                                 else if (refA && !refB && intersectSub
00273                                         (refinedA [indA], morseDecB [indB]))
00274                                 {
00275                                         continue;
00276                                 }
00277                                 else if (!refA && refB && intersectSub
00278                                         (refinedB [indB], morseDecA [indA]))
00279                                 {
00280                                         continue;
00281                                 }
00282                                 else if (!refA && !refB)
00283                                         continue;
00284 
00285                                 // remove the link A <-> B
00286                                 BtoA [indB]. erase (std::find
00287                                         (BtoA [indB]. begin (),
00288                                         BtoA [indB]. end (), indA));
00289                                 AtoB [indA]. erase (begin + i);
00290                                 -- i;
00291                         }
00292                 }
00293 
00294                 // check the bijection of intersections for the second time
00295                 for (int i = 0; i < nSets; ++ i)
00296                 {
00297                         if (MtoN [i]. empty () || NtoM [i]. empty ())
00298                         {
00299                                 sbug << "WARNING: The intersection became "
00300                                         "empty!!!\n";
00301                                 return false;
00302                         }
00303                         if ((MtoN [i]. size () > 1) ||
00304                                 (NtoM [i]. size () > 1))
00305                         {
00306                                 sbug << "Note: No bijection in matching, "
00307                                         "even after refinements.\n";
00308                                 return false;
00309                         }
00310                 }
00311         }
00312 
00313         // check if the Morse sets with wrong indices match each other
00314         if (wrongIndM. size () != wrongIndN. size ())
00315                 return false;
00316         int wrongIndSize = wrongIndM. size ();
00317         for (int i = 0; i < wrongIndSize; ++ i)
00318         {
00319                 int number = MtoN [wrongIndM [i]] [0];
00320                 bool found = false;
00321                 for (int j = 0; j < wrongIndSize; ++ j)
00322                 {
00323                         if (wrongIndN [j] != number)
00324                                 continue;
00325                         found = true;
00326                         break;
00327                 }
00328                 if (!found)
00329                         return false;
00330         }
00331 
00332         // compare the graphs of the Morse decompositions
00333         if (matchOrdering)
00334         {
00335                 // create the arrays with connections for both Morse decomps
00336                 chomp::homology::flatMatrix<char> orderM (nSets);
00337                 chomp::homology::flatMatrix<char> orderN (nSets);
00338                 for (int i = 0; i < nSets; ++ i)
00339                 {
00340                         for (int j = 0; j < nSets; ++ j)
00341                         {
00342                                 orderM [i] [j] = morseDecM.
00343                                         connected (i, j) ? 1 : 0;
00344                                 orderN [i] [j] = morseDecN. connected
00345                                         (MtoN [i] [0], MtoN [j] [0]) ? 1 : 0;
00346                         }
00347                 }
00348 
00349                 // compute the transitive closure of the ordering
00350                 chomp::homology::transitiveClosure (orderM, nSets);
00351                 chomp::homology::transitiveClosure (orderN, nSets);
00352 
00353                 // compare the arrays if they are the same indeed
00354                 const char *memoryM = orderM. memory ();
00355                 const char *memoryN = orderN. memory ();
00356                 int memSize = nSets * nSets;
00357                 for (int i = 0; i < memSize; ++ i)
00358                 {
00359                         if (*(memoryM ++) != *(memoryN ++))
00360                         {
00361                                 sbug << "Note: Different Morse ordering.\n";
00362                                 return false;
00363                         }
00364                 }
00365         //      sbug << "Note: Morse order matched.\n";
00366         }
00367 
00368         return true;
00369 } /* matchMorseSets */
00370 
00371 
00372 // --------------------------------------------------
00373 // ---------- matching Morse decompositions ---------
00374 // --------------------------------------------------
00375 
00376 /// Matches Morse decompositions corresponding to parameter cubes
00377 /// in the entire range. The set of cubes is used to determine
00378 /// the numbers in the indexing of Morse decompositions.
00379 inline void matchMorseDecompositions (const parCubes &paramBoxes,
00380         const std::vector<theMorseDecompositionType *> &morseDec,
00381 //      const std::vector<theMapType *> &theMap,
00382 //      const double *offset, const double *width, int subdivDepth,
00383 //      const std::vector<theCubMapType *> &theCubMap0,
00384         const std::vector<theCubMapType *> &theCubMap1,
00385         const std::vector<std::vector<int> > &wrongIndices,
00386         const parCoord *parLeft, const parCoord *parRight,
00387         std::vector<std::vector<parCube> > &matchClasses)
00388 {
00389         using chomp::homology::sbug;
00390 
00391         // create an array for matching the set of Morse decompositions
00392         parCoord sizes [paramDim];
00393         for (int i = 0; i < paramDim; ++ i)
00394                 sizes [i] = parRight [i] - parLeft [i];
00395         MatchArray<parCoord,int> matchArray (paramDim, sizes, parLeft);
00396 
00397         // determine the total number of boxes to process
00398         int nBoxes = paramBoxes. size ();
00399 
00400         // prepare an array of refined Morse sets
00401         std::vector<std::vector<spcCubes> > refined (nBoxes);
00402 
00403         // process all the neighbors of each Morse set while avoiding
00404         // repetitive verification for the same pairs
00405         for (int boxNumber = 0; boxNumber < nBoxes; ++ boxNumber)
00406         {
00407                 // retrieve the coordinates of the box
00408                 parCoord coord [paramDim];
00409                 paramBoxes [boxNumber]. coord (coord);
00410 
00411                 // prepare the coordinates of the corners of the neighborhood
00412                 parCoord coordLeft [paramDim];
00413                 parCoord coordRight [paramDim];
00414                 for (int i = 0; i < paramDim; ++ i)
00415                 {
00416                         coordLeft [i] = coord [i] - 1;
00417                         if (coordLeft [i] < parLeft [i])
00418                                 coordLeft [i] = parLeft [i];
00419                         coordRight [i] = coord [i] + 2;
00420                         if (coordRight [i] > parRight [i])
00421                                 coordRight [i] = parRight [i];
00422                 }
00423 
00424                 // iterate the neighbors of the cube (including itself)
00425                 parRect neighbors (coordLeft, coordRight, paramDim);
00426                 const parCoord *neighborCoord;
00427                 while ((neighborCoord = neighbors. get ()) != 0)
00428                 {
00429                         // make sure that the neighbor precedes
00430                         // the current box in the lexicographical order
00431                         int compare = 0;
00432                         for (int i = 0; i < paramDim; ++ i)
00433                         {
00434                                 if (neighborCoord [i] < coord [i])
00435                                 {
00436                                         compare = -1;
00437                                         break;
00438                                 }
00439                                 else if (neighborCoord [i] > coord [i])
00440                                 {
00441                                         compare = 1;
00442                                         break;
00443                                 }
00444                         }
00445                         if (compare >= 0)
00446                                 continue;
00447 
00448                         // if the boxes have already been joined
00449                         // then skip the verification of continuation
00450                         if (matchArray. joined (coord, neighborCoord))
00451                                 continue;
00452 
00453                         // check matching between the corresponding
00454                         // Morse decompositions
00455                         int neighborNumber = paramBoxes. getnumber
00456                                 (parCube (neighborCoord, paramDim));
00457                         if (neighborNumber < 0)
00458                                 throw "Matching a non-existent neighbor.";
00459                         sbug << "Matching " << parCube (coord, paramDim) <<
00460                                 " & " << parCube (neighborCoord, paramDim) <<
00461                                 "...\n";
00462                         bool matchResult = matchMorseSets
00463                                 (*(morseDec [boxNumber]),
00464                                 wrongIndices [boxNumber],
00465                                 *(theCubMap1 [boxNumber]),
00466                                 refined [boxNumber],
00467                                 *(morseDec [neighborNumber]),
00468                                 wrongIndices [neighborNumber],
00469                                 *(theCubMap1 [neighborNumber]),
00470                                 refined [neighborNumber],
00471                                 compareMorseOrdering);
00472                         if (matchResult == true)
00473                         {
00474                                 sbug << "Success. :)\n";
00475                                 matchArray. join (coord, neighborCoord);
00476                         }
00477                         else
00478                         {
00479                                 sbug << "Failure. :(\n";
00480                         }
00481                 }
00482         }
00483 
00484         // retrieve classes larger than 1 from the array
00485         matchArray. saveClasses (matchClasses);
00486 
00487         return;
00488 } /* matchMorseDecompositions */
00489 
00490 
00491 #endif // _CMGRAPHS_MATCHDEC_H_
00492 

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