worker.h

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////////
00002 ///
00003 /// @file worker.h
00004 ///
00005 /// The worker class for the Conley-Morse graphs computation program.
00006 /// This file contains the definition of the worker class which processes
00007 /// a single chunk of the parameter range.
00008 ///
00009 /// @author Pawel Pilarczyk
00010 ///
00011 /////////////////////////////////////////////////////////////////////////////
00012 
00013 // Copyright (C) 1997-2008 by Pawel Pilarczyk.
00014 //
00015 // This file is part of my research software package.  This is free software;
00016 // you can redistribute it and/or modify it under the terms of the GNU
00017 // General Public License as published by the Free Software Foundation;
00018 // either version 2 of the License, or (at your option) any later version.
00019 //
00020 // This software is distributed in the hope that it will be useful,
00021 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 // GNU General Public License for more details.
00024 //
00025 // You should have received a copy of the GNU General Public License along
00026 // with this software; see the file "license.txt".  If not, write to the
00027 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00028 // MA 02111-1307, USA.
00029 
00030 // Started on February 11, 2008. Last revision: April 16, 2008.
00031 
00032 
00033 #ifndef _CMGRAPHS_WORKER_H_
00034 #define _CMGRAPHS_WORKER_H_
00035 
00036 
00037 // include some standard C++ header files
00038 #include <string>
00039 #include <sstream>
00040 #include <cstdio>
00041 
00042 // include selected header files from the CHomP library
00043 #include "chomp/system/config.h"
00044 #include "chomp/system/textfile.h"
00045 #include "chomp/system/timeused.h"
00046 #include "chomp/cubes/cube.h"
00047 #include "chomp/multiwork/mw.h"
00048 #include "chomp/struct/digraph.h"
00049 
00050 // include local header files
00051 #include "config.h"
00052 #include "typedefs.h"
00053 #include "utils.h"
00054 #include "compmdec.h"
00055 #include "plotmdec.h"
00056 #include "eigenval.h"
00057 #include "dataconv.h"
00058 #include "matchdec.h"
00059 
00060 
00061 // --------------------------------------------------
00062 // ---------------- the worker class -----------------
00063 // --------------------------------------------------
00064 
00065 /// The worker class that processes single chunks of data
00066 /// which contain the definition of a selected rectangular area
00067 /// in the set of parameters to process.
00068 class Worker: public chomp::multiwork::mwWorker
00069 {
00070 public:
00071         /// The default constructor
00072         Worker (bool _local = false);
00073 
00074 private:
00075         /// A function for the initialization of a worker.
00076         int Initialize (chomp::multiwork::mwData &data);
00077 
00078         /// A function for processing a piece of data by a worker.
00079         int Process (chomp::multiwork::mwData &data);
00080 
00081         /// The copy constructor is not allowed.
00082         Worker (const Worker &) {return;}
00083 
00084         /// The assignment operator is not allowed.
00085         Worker &operator = (const Worker &) {return *this;}
00086 
00087 private:
00088         /// Is the work being done locally? That is, in the same process
00089         /// as the coordinator? If so, then the global variables are not
00090         /// reset, such as pointbase, because this might affect the
00091         /// coordinator's data.
00092         bool local;
00093 
00094 }; /* class Worker */
00095 
00096 // --------------------------------------------------
00097 
00098 inline Worker::Worker (bool _local): local (_local)
00099 {
00100         return;
00101 } /* Worker::Worker */
00102 
00103 // --------------------------------------------------
00104 
00105 inline int Worker::Initialize (chomp::multiwork::mwData &data)
00106 {
00107         // ignore the received data and say it was Ok
00108         return chomp::multiwork::mwOk;
00109 } /* Worker::Initialize */
00110 
00111 inline int Worker::Process (chomp::multiwork::mwData &data)
00112 {
00113         using namespace chomp::homology;
00114         using namespace chomp::multiwork;
00115 
00116         // prepare a stopwatch to measure the time of processing
00117         timeused processingTime;
00118 
00119         // reset the variables for computing max image diameter and volume
00120         theCubMapType::maxImgDiam = 0;
00121         theCubMapType::maxImgVol = 0;
00122 
00123         // decode the number of the data pack to process
00124         int dataNumber = 0;
00125         data >> dataNumber;
00126 
00127         // the parameter space dimension
00128         int dim = 0;
00129         data >> dim;
00130         if (dim != paramDim)
00131         {
00132                 sout << "! Wrong parameter space dimension (" << dim <<
00133                         "). Rejecting the data.\n";
00134                 data. Reset ();
00135                 return mwReject;
00136         }
00137 
00138         // the ranges of the parameter boxes
00139         parCoord parLeft [paramDim];
00140         parCoord parRight [paramDim];
00141         for (int i = 0; i < paramDim; ++ i)
00142         {
00143                 int n = 0;
00144                 data >> n;
00145                 parLeft [i] = static_cast<parCoord> (n);
00146                 data >> n;
00147                 parRight [i] = static_cast<parCoord> (n);
00148         }
00149 
00150         // the size of Morse sets to skip the Conley index computation above
00151         int skipIndices = 0;
00152         data >> skipIndices;
00153 
00154         // read the file name prefix to which Morse decompositions are saved
00155         std::string sharePrefix;
00156         data >> sharePrefix;
00157 
00158         // read the file name prefix to which Morse decompositions are saved
00159         std::string phaseSpacePrefix;
00160         data >> phaseSpacePrefix;
00161 
00162         // should the full phase space be plotted in a PNG file?
00163         bool fullPhaseSpace (false);
00164         data >> fullPhaseSpace;
00165 
00166         // the ending control number
00167         int ctrl = 0;
00168         data >> ctrl;
00169         if (ctrl != controlNumber)
00170         {
00171                 data. Reset ();
00172                 sout << "! Data incomplete. Rejecting it.\n";
00173                 return mwReject;
00174         }
00175 
00176         // compute the number of parameter boxes to process
00177         int volume = 1;
00178         for (int i = 0; i < paramDim; ++ i)
00179         {
00180                 int prevVolume = volume;
00181                 volume *= parRight [i] - parLeft [i];
00182                 if (volume < prevVolume)
00183                         throw "Too many boxes for processing by a worker.";
00184         }
00185 
00186         // show a message on which boxes are going to be processed
00187         if (volume > 1)
00188         {
00189                 sout << "Processing " << dataNumber << ": " << volume <<
00190                         " boxes in ";
00191                 for (int i = 0; i < paramDim; ++ i)
00192                 {
00193                         sout << (i ? "x" : "") << "[" << parLeft [i] <<
00194                                 "," << parRight [i] << "]";
00195                 }
00196                 sout << "...\n";
00197         }
00198         // show a message about processing a single parameter box
00199         else
00200         {
00201                 sout << "Processing " << dataNumber << ": the box " <<
00202                         parCube (parLeft, paramDim) << "...\n";
00203         }
00204 
00205 
00206         // prepare the offset and the width of the phase space region
00207         double offset [spaceDim];
00208         for (int i = 0; i < spaceDim; ++ i)
00209                 offset [i] = spaceOffset [i];
00210         double width [spaceDim];
00211         for (int i = 0; i < spaceDim; ++ i)
00212                 width [i] = spaceWidth [i];
00213 
00214         // prepare arrays for storing the ranges of coordinates
00215         // in the Morse sets
00216         spcCoord coordLeftMin [spaceDim];
00217         spcCoord coordRightMax [spaceDim];
00218         for (int i = 0; i < spaceDim; ++ i)
00219         {
00220                 coordLeftMin [i] = 1 << finalDepth;
00221                 coordRightMax [i] = 0;
00222         }
00223 
00224         // prepare the data for storing results of computations
00225         // for individual boxes
00226         parCubes paramBoxes;
00227         std::vector<theMapType *> theMap (volume);
00228         std::vector<theCubMapType *> theCubMap0 (volume);
00229         std::vector<theCubMapType *> theCubMap1 (volume);
00230         std::vector<theMorseDecompositionType *> morseDec (volume);
00231         std::vector<bool> morseDecComputed (volume, false);
00232         std::vector<double> timeUsed (volume, 0);
00233         std::vector<std::vector<int> > wrongIndices (volume);
00234         std::vector<std::vector<int> > skippedIndices (volume);
00235         std::vector<std::vector<int> > attractors (volume);
00236 
00237         // run one set of computations
00238         int countRead = 0, countWritten = 0, countComputed = 0;
00239         parRect rect (parLeft, parRight, paramDim);
00240         const parCoord *curCoord;
00241         while ((curCoord = rect. get ()) != 0)
00242         {
00243                 // start measuring the time of processing this box
00244                 chomp::homology::timeused stopwatch;
00245 
00246                 // determine if this is an internal boundary point
00247                 bool intBoundaryPoint = internalBoundaryPoint
00248                         (curCoord, parLeft, parRight, paramSubdiv, paramDim);
00249 
00250                 // force reading/writing cached Conley indices
00251                 intBoundaryPoint = true;
00252 
00253                 // prepare filenames for cached indices and phase space PNG
00254                 std::string pictureFileName = phaseSpacePrefix +
00255                         coord2str (curCoord, paramDim) + ".png";
00256                 std::string cacheFileName ((intBoundaryPoint &&
00257                         !sharePrefix. empty ()) ? (sharePrefix +
00258                         coord2str (curCoord, paramDim) + ".ind") : "");
00259 
00260                 // skip this parameter box if the corresponding index cache
00261                 // file exists and the task was to generate this cache only
00262                 if ((volume == 1) &&
00263                         (cacheFileName. empty () ||
00264                         fileExists (cacheFileName. c_str ())) &&
00265                         (phaseSpacePrefix. empty () ||
00266                         fileExists (pictureFileName. c_str ())))
00267                 {
00268                         if (cacheFileName. empty ())
00269                                 sout << "No Conley index cache to compute.";
00270                         else if (fileExists (cacheFileName. c_str ()))
00271                                 sout << "Conley index cache already exists.";
00272                         sout << " Skipping the box.\n";
00273                         break;
00274                 }
00275 
00276                 // add the analyzed box to the set of parameter boxes
00277                 int curNumber = paramBoxes. size ();
00278                 parCube paramBox (curCoord, paramDim);
00279                 paramBoxes. add (paramBox);
00280                 if (paramBoxes. size () == curNumber)
00281                         throw "A repeated box found in the iterations.";
00282 
00283                 // prepare the actual parameters for the map
00284                 double leftMapParam [paramCount];
00285                 double rightMapParam [paramCount];
00286                 computeParam (curCoord, leftMapParam, rightMapParam);
00287                 sbug << "Box " << paramBox << ":";
00288                 for (int i = 0; i < paramCount; ++ i)
00289                 {
00290                         sbug << " [" << leftMapParam [i] << "," <<
00291                                 rightMapParam [i] << "]";
00292                 }
00293                 sbug << ".\n";
00294 
00295                 // create the map object and set its parameters
00296                 theMap [curNumber] = new theMapType ();
00297                 theMap [curNumber] -> setParam (leftMapParam, rightMapParam,
00298                         paramCount);
00299 
00300                 // prepare an object of the cubical map
00301                 // at the highest subdivision level to be used
00302                 // in the definition of the Morse decomposition
00303                 theCubMap0 [curNumber] = new theCubMapType (offset, width,
00304                         1 << finalDepth, *(theMap [curNumber]));
00305                 theCubMap0 [curNumber] -> cache = true;
00306                 theCubMap1 [curNumber] = new theCubMapType (offset, width,
00307                         1 << (finalDepth + 1), *(theMap [curNumber]));
00308                 theCubMap1 [curNumber] -> cache = true;
00309 
00310                 // compute the Morse decomposition
00311                 sbug << "Computing Morse decomposition for " <<
00312                         paramBox << "...\n";
00313                 bool computed = false;
00314                 morseDec [curNumber] = computeMorseDecomposition
00315                         (*(theMap [curNumber]),
00316                         *(theCubMap0 [curNumber]), *(theCubMap1 [curNumber]),
00317                         offset, width, skipIndices, cacheFileName,
00318                         computed, wrongIndices [curNumber],
00319                         skippedIndices [curNumber], attractors [curNumber],
00320                         false, leftMapParam, rightMapParam, paramCount);
00321                 morseDecComputed [curNumber] = computed;
00322 
00323                 // update a counter of computed Morse decompositions
00324                 if (computed)
00325                 {
00326                         ++ countComputed;
00327                         if (intBoundaryPoint)
00328                                 ++ countWritten;
00329                 }
00330                 else
00331                         ++ countRead;
00332 
00333                 // update the min and max coordinates of Morse sets
00334                 coordMinMax (*(morseDec [curNumber]),
00335                         coordLeftMin, coordRightMax);
00336 
00337                 // save a picture of the computed Morse decomposition
00338                 if ((spaceDim == 2) && !phaseSpacePrefix. empty () &&
00339                         !fileExists (pictureFileName. c_str ()))
00340                 {
00341                         sbug << "Saving '" << pictureFileName << "'...\n";
00342                         plotMorseDecompositionPNG (*(morseDec [curNumber]),
00343                                 pictureFileName. c_str (),
00344                                 fullPhaseSpace ? (1 << finalDepth) : 0);
00345                 }
00346 
00347                 // remember the time used for processing this cube
00348                 timeUsed [curNumber] = stopwatch;
00349 
00350                 // indicate the percentage of work completed
00351                 sbug << timeUsed [curNumber] << " sec, " <<
00352                         ((curNumber + 1) * 100 / volume) << "% done.\n";
00353                 sbug << "--------------------------------\n";
00354         }
00355 
00356         // show statistics of the computations
00357         if (volume > 1)
00358         {
00359                 sout << countRead << " sets of Conley indices read, " <<
00360                         countComputed << " computed (" <<
00361                         countWritten << " written).\n";
00362         }
00363 
00364         // process the computed Morse decompositions
00365         // to determine the continuation relations between them
00366         std::vector<std::vector<parCube> > matchClasses;
00367         if (volume > 1)
00368         {
00369                 sbug << "Matching " << volume <<
00370                         " Morse decompositions...\n";
00371                 std::vector<std::vector<int> > noWrongIndices (volume);
00372                 matchMorseDecompositions (paramBoxes, morseDec,
00373                 //      theMap, offset, width, finalDepth, theCubMap0,
00374                         theCubMap1,
00375                         ignoreIsolationForContinuation ? noWrongIndices :
00376                         wrongIndices, parLeft, parRight, matchClasses);
00377 
00378                 // show a summary of what has just been computed
00379                 int nClasses = matchClasses. size ();
00380                 if (nClasses == 1)
00381                         sbug << "There is only one nontrivial class";
00382                 else
00383                         sbug << "There are " <<  nClasses << " nontrivial classes";
00384                 sbug << " of equivalent Morse decompositions:\n";
00385                 if (nClasses == 0)
00386                         sbug << 0;
00387                 for (int n = 0; n < nClasses; ++ n)
00388                         sbug << (n ? "+" : "") << matchClasses [n]. size ();
00389                 sbug << " elements.\n";
00390         }
00391 
00392         // show computed max image diameter and volume
00393         sbug << "Max img diam = " << theCubMapType::maxImgDiam <<
00394                 ", max img vol = " << theCubMapType::maxImgVol << ".\n";
00395 
00396         // send back the data containing the result of the processing
00397         data. Reset ();
00398         data << dataNumber;
00399 
00400         // send the processing time
00401         data << static_cast<double> (processingTime);
00402         processingTime = 0;
00403 
00404         // send the lists of numbers of Morse sets with wrong indices
00405         data << wrongIndices;
00406 
00407         // send the lists of numbers of Morse sets whose indices were skipped
00408         data << skippedIndices;
00409 
00410         // send the lists of attractors
00411         data << attractors;
00412 
00413         // send the cubes with the coordinate ranges
00414         data << spcCube (coordLeftMin, spaceDim);
00415         data << spcCube (coordRightMax, spaceDim);
00416 
00417         // send the number of boxes in the data chunk
00418         int countBoxes = paramBoxes. size ();
00419         data << countBoxes;
00420 
00421         // send data for each box
00422         for (int curNumber = 0; curNumber < countBoxes; ++ curNumber)
00423         {
00424                 // send the coordinates of the box
00425                 data << paramBoxes [curNumber];
00426 
00427                 // send the time used for processing this box
00428                 data << timeUsed [curNumber];
00429 
00430                 // send the information on whether this Morse decomposition
00431                 // was computed or if it was known before
00432                 data << morseDecComputed [curNumber];
00433 
00434                 // send the transitive reduction of the Morse graph
00435                 diGraph<> connGraph;
00436                 morseDec [curNumber] -> makegraph (connGraph);
00437                 diGraph<> morseGraph;
00438                 transitiveReduction (connGraph, morseGraph);
00439                 data << morseGraph;
00440 
00441                 // send the sizes of each Morse set
00442                 int nSets = morseDec [curNumber] -> count ();
00443                 for (int n = 0; n < nSets; ++ n)
00444                         data << (*(morseDec [curNumber])) [n]. size ();
00445 
00446                 // send the Conley indices of the Morse sets
00447                 // and the nonzero eigenvalues of each index
00448                 if (nSets != morseGraph. countVertices ())
00449                         throw "Wrong number of Morse sets encountered.";
00450                 for (int n = 0; n < nSets; ++ n)
00451                 {
00452                         const theConleyIndexType &index =
00453                                 morseDec [curNumber] -> index (n);
00454                         data << index;
00455                         IndexEigenValues eigenValues (index);
00456                         data << eigenValues;
00457                 }
00458         }
00459 
00460         // send data regarding the continuation relation between the boxes
00461         data << matchClasses;
00462 
00463         // send computed max image diameter and volume
00464         data << theCubMapType::maxImgDiam;
00465         data << theCubMapType::maxImgVol;
00466 
00467         // delete the allocated Morse decompositions
00468         for (int i = 0; i < countBoxes; ++ i)
00469         {
00470                 delete morseDec [i];
00471                 delete theCubMap1 [i];
00472                 delete theCubMap0 [i];
00473                 delete theMap [i];
00474         }
00475 
00476         // reset the environment of computations
00477         // unless the work is being done locally
00478         if (!local)
00479         {
00480                 sbug << "(Resetting the pointset data.)\n";
00481                 parCube::PointBase::reset ();
00482                 spcCube::PointBase::reset ();
00483                 Cube::PointBase::reset ();
00484         }
00485 
00486         // add a data chunk separator
00487         sout << "================================\n";
00488 
00489         // return the result
00490         return mwOk;
00491 } /* Worker::Process */
00492 
00493 
00494 #endif // _CMGRAPHS_WORKER_H_
00495 

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