pointset.h

Go to the documentation of this file.
00001 
00002 
00003 
00025 
00026 // Copyright (C) 1997-2010 by Pawel Pilarczyk.
00027 //
00028 // This file is part of the Homology Library.  This library is free software;
00029 // you can redistribute it and/or modify it under the terms of the GNU
00030 // General Public License as published by the Free Software Foundation;
00031 // either version 2 of the License, or (at your option) any later version.
00032 //
00033 // This library is distributed in the hope that it will be useful,
00034 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00035 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00036 // GNU General Public License for more details.
00037 //
00038 // You should have received a copy of the GNU General Public License along
00039 // with this software; see the file "license.txt".  If not, write to the
00040 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00041 // MA 02111-1307, USA.
00042 
00043 // Started in December 1997. Last revision: May 24, 2010.
00044 
00045 
00046 #ifndef _CHOMP_CUBES_POINTSET_H_
00047 #define _CHOMP_CUBES_POINTSET_H_
00048 
00049 #include "chomp/system/config.h"
00050 #include "chomp/system/textfile.h"
00051 
00052 #include <iostream>
00053 #include <fstream>
00054 #include <ctime>
00055 #include <cstdlib>
00056 #include <cctype>
00057 
00058 namespace chomp {
00059 namespace homology {
00060 
00061 
00063 typedef short int coordinate;
00064 
00065 // a class for gathering hashing statistics in a set of points
00066 class psethashstat;
00067 
00068 // a template for a set of points with 'integer' coordinates
00069 template <class coordtype>
00070 class tPointset;
00071 
00072 // a template for a class used to list all the neighbors of a given point
00073 template <class coordtype>
00074 class tNeighbors;
00075 
00076 // a template for a class used to list all the points in a given scope
00077 template <class coordtype>
00078 class tRectangle;
00079 
00081 typedef tPointset<coordinate> pointset;
00082 
00084 typedef tNeighbors<coordinate> neighbors;
00085 
00087 typedef tRectangle<coordinate> rectangle;
00088 
00089 
00090 // --------------------------------------------------
00091 // ---------------- various functions ---------------
00092 // --------------------------------------------------
00093 // Various small or large functions used by
00094 // or manipulating with the class 'pointset'.
00095 
00097 template <class coordtype>
00098 inline int thesame (const coordtype *c1, const coordtype *c2, int dim)
00099 {
00100         for (int i = 0; i < dim; ++ i)
00101                 if (c1 [i] != c2 [i])
00102                         return 0;
00103         return 1;
00104 } /* thesame */
00105 
00107 template <class coordtype>
00108 inline void copycoord (coordtype *destination, const coordtype *source,
00109         int dim)
00110 {
00111         for (int i = 0; i < dim; ++ i)
00112                 destination [i] = source [i];
00113         return;
00114 } /* copycoord */
00115 
00118 template <class coordtype>
00119 inline void wrapcoord (coordtype *destination, const coordtype *source,
00120         const coordtype *wrap, int dim)
00121 {
00122         if (!destination || !source)
00123                 throw "Trying to wrap NULL coordinates.";
00124 
00125         for (int i = 0; i < dim; ++ i)
00126                 if (wrap [i])
00127                 {
00128                         destination [i] =
00129                                 (coordtype) (source [i] % wrap [i]);
00130                         if (destination [i] < 0)
00131                                 destination [i] += wrap [i];
00132                 }
00133                 else
00134                         destination [i] = source [i];
00135 
00136         return;
00137 } /* wrapcoord */
00138 
00141 inline bool numberisprime (unsigned n)
00142 {
00143         if (n < 2)
00144                 return false;
00145 
00146         unsigned i = 2;
00147         while (i * i <= n)
00148                 if (!(n % i ++))
00149                         return false;
00150 
00151         return true;
00152 } /* numberisprime */
00153 
00156 inline unsigned ceilprimenumber (unsigned n)
00157 {
00158         while (!numberisprime (n))
00159                 ++ n;
00160 
00161         return n;
00162 } /* prime number */
00163 
00165 template <class coordtype>
00166 int_t pointhashkey (const coordtype *c, int dim, int_t hashsize)
00167 {
00168         int_t key = 13;
00169         for (int i = 0; i < dim; ++ i)
00170         {
00171                 key ^= static_cast<int_t> ((c [i] > 0) ? c [i] : -c [i]) <<
00172                         ((i << 3) % 19);
00173         }
00174         if (key < 0)
00175                 key = -(key + 1);
00176 
00177         // return the key reduced to the given size
00178         return (key % hashsize);
00179 
00180 } /* pointhashkey */
00181 
00183 template <class coordtype>
00184 int_t pointhashadd (const coordtype *c, int dim, int_t hashsize)
00185 {
00186         int_t add = 1313;
00187         for (int i = 0; i < dim; ++ i)
00188                 add ^= static_cast<int_t> ((c [i] > 0) ? c [i] : -c [i]) <<
00189                         (((i << 4) + 3) % 21);
00190         if (add < 0)
00191                 add = -(add + 1);
00192 
00193         // return the key reduced to the given size
00194         return (add % (hashsize - 1) + 1);
00195 
00196 } /* pointhashadd */
00197 
00199 template <class coordtype>
00200 inline coordtype rounddown (double x)
00201 {
00202         if ((x >= 0) || ((double) (coordtype) x == x))
00203                 return (coordtype) x;
00204         else
00205                 return -(coordtype) (-x) - 1;
00206 } /* rounddown */
00207 
00211 template <class coordtype>
00212 inline void roundpoint (const double *p, coordtype *c, const double *grid,
00213         int dim)
00214 {
00215         if (grid)
00216         {
00217                 for (int i = 0; i < dim; ++ i)
00218                         c [i] = rounddown<coordtype> (p [i] / grid [i]);
00219         }
00220         else
00221         {
00222                 for (int i = 0; i < dim; ++ i)
00223                         c [i] = rounddown<coordtype> (p [i]);
00224         }
00225         return;
00226 } /* roundpoint */
00227 
00230 template <class coordtype>
00231 inline void cubemiddle (coordtype *c, double *p, double *grid, int dim)
00232 {
00233         if (grid)
00234         {
00235                 for (int i = 0; i < dim; ++ i)
00236                         p [i] = (c [i] + 0.5) * grid [i];
00237         }
00238         else
00239         {
00240                 for (int i = 0; i < dim; ++ i)
00241                         p [i] = c [i] + 0.5;
00242         }
00243         return;
00244 } /* cubemiddle */
00245 
00247 template <class coordtype>
00248 inline coordtype *allocatepoint (int dim, char *errormessage = NULL)
00249 {
00250         coordtype *temp = new coordtype [dim];
00251         if (!temp)
00252         {
00253                 throw (errormessage ? errormessage :
00254                         "Can't allocate memory for a temporary point.");
00255         }
00256         return temp;
00257 } /* allocatepoint */
00258 
00259 #define INSIDE 1
00260 #define OUTSIDE 0
00261 
00267 template <class coordtype>
00268 int countneighbors (const tPointset<coordtype> &p, const coordtype *c,
00269         int which = INSIDE, int maxcount = 0);
00270 
00272 template <class coordtype>
00273 int countneighbors (const tPointset<coordtype> &p,
00274         const tPointset<coordtype> &q, const coordtype *c,
00275         int which = INSIDE, int maxcount = 0);
00276 
00278 template <class coordtype>
00279 int attheborder (const tPointset<coordtype> &p, const coordtype *c);
00280 
00285 template <class coordtype>
00286 int_t findboundarypoint (tPointset<coordtype> &p, int_t n,
00287         int direction = 1);
00288 
00290 template <class coordtype>
00291 int_t findboundarypoint (tPointset<coordtype> &p,
00292         tPointset<coordtype> &q, int_t n, int direction = 1);
00293 
00295 template <class coordtype>
00296 tPointset<coordtype> *computeboundary (tPointset<coordtype> &p);
00297 
00300 template <class coordtype>
00301 void computeboundary (tPointset<coordtype> &p, tPointset<coordtype> &b);
00302 
00305 template <class coordtype>
00306 void enhancepoint (tPointset<coordtype> &p, coordtype *c);
00307 
00310 template <class coordtype>
00311 void enhancepoint (tPointset<coordtype> &p, int_t n);
00312 
00315 template <class coordtype>
00316 void enhance (tPointset<coordtype> &p);
00317 
00318 
00324 template <class coordtype>
00325 int read (textfile &f, coordtype *c, int maxdim);
00326 
00332 template <class coordtype>
00333 int read (std::istream &in, coordtype *c, int maxdim);
00334 
00335 // write a point to a text file; the coordinates are separated with commas,
00336 // and a pair of parentheses, braces or brackets is added (use 0 for none);
00337 // no end-of-line character is added after the point has been written
00338 template <class coordtype>
00339 int write (std::ostream &out, const coordtype *c, int dim,
00340         char parenthesis = 40, char closing = 0);
00341 
00342 #define CELL 0
00343 #define CUBE 1
00344 
00350 template <class coordtype>
00351 int readcubeorcell (std::istream &in, coordtype *left, coordtype *right,
00352         int maxdim, int *type = NULL);
00353 
00354 
00357 template <class coordtype>
00358 int_t read (textfile &f, tPointset<coordtype> &p,
00359         int_t first = 0, int_t howmany = -1,
00360         coordtype *wrap = NULL, int maxdim = 0, int quiet = 0,
00361         tPointset<coordtype> *notthese = NULL);
00362 
00365 template <class coordtype>
00366 int_t read (std::istream &in, tPointset<coordtype> &p,
00367         int_t first = 0, int_t howmany = -1,
00368         coordtype *wrap = NULL, int maxdim = 0, int quiet = 0,
00369         tPointset<coordtype> *notthese = NULL);
00370 
00373 template <class coordtype>
00374 int_t read (textfile &f, tPointset<coordtype> &p,
00375         coordtype *wrap, int maxdim,
00376         int quiet = 0, tPointset<coordtype> *notthese = NULL);
00377 
00380 template <class coordtype>
00381 int_t read (std::istream &in, tPointset<coordtype> &p,
00382         coordtype *wrap, int maxdim,
00383         int quiet = 0, tPointset<coordtype> *notthese = NULL);
00384 
00386 template <class coordtype>
00387 textfile &operator >> (textfile &f, tPointset<coordtype> &p);
00388 
00390 template <class coordtype>
00391 std::istream &operator >> (std::istream &in, tPointset<coordtype> &p);
00392 
00396 template <class coordtype>
00397 int_t write (std::ostream &out, tPointset<coordtype> &p,
00398         int_t first = 0, int_t howmany = -1, int quiet = 0);
00399 
00401 template <class coordtype>
00402 std::ostream &operator << (std::ostream &out, tPointset<coordtype> &p);
00403 
00404 
00405 // --------------------------------------------------
00406 // ----------------- pset hash stat -----------------
00407 // --------------------------------------------------
00408 
00411 class psethashstat
00412 {
00413 public:
00415         psethashstat ();
00416 
00418         std::time_t creationtime;
00419 
00422         unsigned long hashhits;
00423 
00426         unsigned long hashmisses;
00427 
00430         unsigned long rehashcount;
00431 
00432 }; /* class psethashstat */
00433 
00434 // --------------------------------------------------
00435 
00436 inline psethashstat::psethashstat ()
00437 {
00438         std::time (&creationtime);
00439         hashhits = 0;
00440         hashmisses = 0;
00441         rehashcount = 0;
00442         return;
00443 } /* psethashstat::psethashstat */
00444 
00445 // --------------------------------------------------
00446 
00449 inline std::ostream &operator << (std::ostream &out, const psethashstat &s)
00450 {
00451         if (!s. hashhits)
00452                 return out;
00453         out << "hashing: " << s. hashhits << " hits, avg " <<
00454                 ((s. hashhits + s. hashmisses) / s. hashhits) << "." <<
00455                 ((s. hashhits + s. hashmisses) * 10 / s. hashhits) % 10 <<
00456                 " attempts (" << s. rehashcount << " times rehashed)";
00457         return out;
00458 } /* operator << */
00459 
00460 
00461 // --------------------------------------------------
00462 // -------------------- POINTSET --------------------
00463 // --------------------------------------------------
00464 
00466 template <class coordtype>
00467 class tPointset
00468 {
00469 public:
00470 
00471         // CONSTRUCTORS AND DESTRUCTORS OF THE SET OF POINTS
00472 
00480         tPointset (int_t initialsize = 0, int bequiet = 1);
00481 
00483         tPointset (const tPointset<coordtype> &p);
00484 
00486         tPointset &operator = (const tPointset<coordtype> &p);
00487 
00489         ~tPointset ();
00490 
00491 
00492         // METHODS FOR SETTING BASIC PROPERTIES OF THE SET OF POINTS
00493 
00495         int dimension (int d);
00496 
00498         int dimension () const;
00499 
00501         static int defaultdimension (int d = 0);
00502 
00504         double *gridsize (double *g = 0);
00505 
00507         double *gridsize (double g);
00508 
00510         double *gridsize (int direction, double g);
00511 
00512         // get or set space wrapping;
00513         // use '0' for no space wrapping in a particular direction
00514         const coordtype *wrapspace (const coordtype *w = NULL);
00515         // set space wrapping (if the same in all the directions)
00516         const coordtype *wrapspace (coordtype w);
00517         // set space wrapping in one particular direction
00518         const coordtype *wrapspace (int direction, coordtype w);
00519 
00520 
00521         // METHODS FOR ADDING, FINDING, CHECKING AND REMOVING POINTS
00522 
00523         // Note: Real coordinates are rounded down with 'floor'.
00524         // Integer coordinates are internally wrapped if needed.
00525 
00526         // check if a point is in the set; return: 1 = Yes, 0 = No
00527         int check (int_t n) const;
00528         int check (const coordtype *c) const;
00529         int check (const double *c) const;
00530 
00531         // find a point in the set;
00532         // return its number or -1 if not found
00533         int_t getnumber (const coordtype *c) const;
00534         int_t getnumber (const double *c) const;
00535 
00536         // get a pointer to the coordinates (stored in internal
00537         // tables) of the point which has the number or the
00538         // coordinates given; if the last case, fill in the coords
00539         coordtype *operator [] (int_t n) const;
00540         coordtype *getpoint (int_t n) const;
00541         coordtype *getpoint (coordtype *c) const;
00542         coordtype *getpoint (double *c) const;
00543         coordtype *getpoint (int_t n, double *c) const;
00544 
00545         // add a point (if not in the set, yet); return its number
00546         int_t add (const coordtype *c);
00547         int_t add (double *c);
00548         // add an entire set
00549         tPointset &add (const tPointset<coordtype> &p);
00550 
00551         // remove the point with the given number or coordinates;
00552         // return 0 if removed or -1 if does not belong to the set;
00553         // warning: the order of the points in the set changes if
00554         // a point other than the last one in the set is removed
00555         int remove (int_t n);
00556         int remove (const coordtype *c);
00557         int remove (const double *c);
00558         // remove an entire set
00559         int remove (const tPointset<coordtype> &p);
00560 
00561 
00562         // OTHER
00563 
00565         int_t size () const;
00566 
00568         bool empty () const;
00569 
00574 //      operator int () const;
00575 
00576         // run quietly (or show many unnecessary messages otherwise)
00577         int quiet;
00578 
00579         // get the size of the hashing table (you may need this
00580         // if you are curious about memory usage or so)
00581         int_t gethashsize () const;
00582 
00583 
00584         // OPTIONAL STATISTICS (entirely public for easy access)
00585 
00586         // hash statistics
00587         psethashstat *stat;
00588 
00589         // point scope statistics
00590         coordtype *minimal, *maximal;
00591 
00592         // were there any points removed from the set?
00593         // note: this variable is used only for generate an output
00594         // warning and to modify statistics notice, that's why
00595         // it may be public for instant access
00596         int wereremoved;
00597 
00598 
00599 protected:
00600 
00601         // INTERNAL DATA OF THE SET OF POINTS
00602 
00603         // dimension of the points; '0' if not set yet
00604         int dim;
00605 
00606         // the number of points in the set
00607         int_t npoints;
00608 
00609         // the number of tables containing points' coordinates
00610         int_t ntables;
00611 
00612         // the number of points stored in a single table
00613         int tablepoints;
00614 
00615         // the table of tables for points' coordinates;
00616         // note: some tables may not be allocated (these are NULLs)
00617         coordtype **tables;
00618 
00619         // the size of the grid in R^n (a pointer to a table)
00620         double *grid;
00621         
00622         // space wrapping
00623         coordtype *wrap;
00624 
00625         // a point for temporary usage while adding or checking:
00626         // its coordinates are wrapped if needed
00627         coordtype *temp;
00628 
00629         // the default parameters used for new pointsets
00630         static int defaultdim;
00631         static double *defaultgrid;
00632         static coordtype *defaultwrap;
00633 
00634         // protected functions for initialization and deallocation
00635         void initialize (int_t initialsize, int bequiet);
00636         void deallocate ();
00637 
00638 
00639         // HASHING
00640 
00641         // the size of the hashing table
00642         int_t hashsize;
00643 
00644         // the number of cleared entries in the hashing table
00645         int_t hashcleared;
00646 
00647         // hashing table (if any): -1 = free entry, -2 = cleared
00648         int_t *hashtable;
00649 
00650         // the expected number of points in the set (0 if unknown)
00651         unsigned initsize;
00652 
00653         // find an entry corresponding to the point in the hashing
00654         // table; may fill in a position at which a new point should
00655         // be added; 'wrapped' says if the coordinates have already
00656         // been wrapped
00657         int_t hashfindpoint (const coordtype *c,
00658                 int_t *addposition = NULL, int wrapped = 0) const;
00659 
00660         // replace the old hashing table with a new one;
00661         // a desired size may be given, otherwise an optimal size
00662         // is determined and the new table is made bigger or smaller
00663         void rehash (int_t newsize = 0);
00664 
00665 }; /* class tPointset */
00666 
00667 // --------------------------------------------------
00668 
00669 template <class coordtype>
00670 int tPointset<coordtype>::defaultdim = 0;
00671 
00672 template <class coordtype>
00673 double *tPointset<coordtype>::defaultgrid = NULL;
00674 
00675 template <class coordtype>
00676 coordtype *tPointset<coordtype>::defaultwrap = NULL;
00677 
00678 // --------------------------------------------------
00679 
00680 template <class coordtype>
00681 inline int tPointset<coordtype>::defaultdimension (int d)
00682 {
00683         // set the default dimension if needed
00684         if (d > 0)
00685         {
00686                 // remove the two tables if the new dimension is higher
00687                 if (d > defaultdim)
00688                 {
00689                         if (defaultgrid)
00690                                 delete [] defaultgrid;
00691                         defaultgrid = NULL;
00692                         if (defaultwrap)
00693                                 delete [] defaultwrap;
00694                         defaultwrap = NULL;
00695                 }
00696 
00697                 // store the default dimension in the global variable
00698                 defaultdim = d;
00699         }
00700 
00701         // return the default dimension of points
00702         return defaultdim;
00703 } /* tPointset::defaultdimension */
00704 
00705 template <class coordtype>
00706 inline double *tPointset<coordtype>::gridsize (int direction, double g)
00707 {
00708         // if this is a question or wrong parameters are given,
00709         // return the grid
00710         if ((direction < 0) || (direction >= dim) || !dim || (g <= 0))
00711                 return grid;
00712 
00713         // allocate memory for a new grid table if needed
00714         if (!grid)
00715         {
00716                 grid = new double [dim];
00717                 if (!grid)
00718                         throw "Can't allocate memory for the grid.";
00719                 for (int i = 0; i < dim; ++ i)
00720                         grid [i] = 1.0;
00721         }
00722 
00723         // update the dimension if it was different
00724         if (dim != defaultdim)
00725                 defaultdimension (dim);
00726 
00727         // create a new default grid table if needed
00728         if (!defaultgrid)
00729         {
00730                 defaultgrid = new double [dim];
00731                 if (!defaultgrid)
00732                         throw "Can't alloc mem for the default grid.";
00733                 for (int i = 0; i < dim; ++ i)
00734                         defaultgrid [i] = grid [i];
00735         }
00736 
00737         // set the grid and the default grid coordinates
00738         grid [direction] = g;
00739         defaultgrid [direction] = g;
00740 
00741         // return the new grid
00742         return grid;
00743 } /* point::gridsize */
00744 
00745 template <class coordtype>
00746 inline double *tPointset<coordtype>::gridsize (double g)
00747 {
00748         // set all the directions of the grid
00749         for (int i = 0; i < dim; ++ i)
00750                 gridsize (i, g);
00751 
00752         // return the new grid
00753         return grid;
00754 } /* point::gridsize */
00755 
00756 template <class coordtype>
00757 inline double *tPointset<coordtype>::gridsize (double *g)
00758 {
00759         // if this is only a question, return the current grid
00760         if (!g)
00761                 return grid;
00762 
00763         // set all the directions of the grid
00764         for (int i = 0; i < dim; ++ i)
00765                 gridsize (i, g [i]);
00766 
00767         // return the new grid
00768         return grid;
00769 } /* point::gridsize */
00770 
00771 template <class coordtype>
00772 inline const coordtype *tPointset<coordtype>::wrapspace
00773         (int direction, coordtype w)
00774 {
00775         // if this is a question or wrong parameters are given,
00776         // return the wrap table
00777         if ((direction < 0) || (direction >= dim) || !dim || (w < 0))
00778                 return wrap;
00779 
00780         // allocate memory for a new wrap table if needed
00781         if (!wrap)
00782         {
00783                 wrap = new coordtype [dim];
00784                 if (!wrap)
00785                         throw "Can't alloc mem for the wrap table.";
00786                 for (int i = 0; i < dim; ++ i)
00787                         wrap [i] = 0;
00788         }
00789 
00790         // update the dimension if it was different
00791         if (dim != defaultdim)
00792                 defaultdimension (dim);
00793 
00794         // create a new default wrap table if needed
00795         if (!defaultwrap)
00796         {
00797                 defaultwrap = new coordtype [dim];
00798                 if (!defaultwrap)
00799                         throw "Can't alloc mem for the def. WrapTab.";
00800                 for (int i = 0; i < dim; ++ i)
00801                         defaultwrap [i] = wrap [i];
00802         }
00803 
00804         // set the wrap and the default wrap coordinates
00805         wrap [direction] = w;
00806         defaultwrap [direction] = w;
00807 
00808         // return the new wrap table
00809         return wrap;
00810 } /* point::wrapspace */
00811 
00812 template <class coordtype>
00813 inline const coordtype *tPointset<coordtype>::wrapspace (coordtype w)
00814 {
00815         // set all the directions of the wrap table
00816         for (int i = 0; i < dim; ++ i)
00817                 wrapspace (i, w);
00818 
00819         // return the new wrap table
00820         return wrap;
00821 } /* point::wrapspace */
00822 
00823 template <class coordtype>
00824 inline const coordtype *tPointset<coordtype>::wrapspace (const coordtype *w)
00825 {
00826         // if this is only a question, return the current wrap
00827         if (!w)
00828                 return wrap;
00829 
00830         // set all the directions of the wrap table
00831         for (int i = 0; i < dim; ++ i)
00832                 wrapspace (i, w [i]);
00833 
00834         // return the new wrap table
00835         return wrap;
00836 } /* point::wrapspace */
00837 
00838 template <class coordtype>
00839 inline int tPointset<coordtype>::dimension (int d)
00840 {
00841         // set the default dimension if needed
00842         if (d > 0)
00843                 defaultdimension (d);
00844 
00845         // change the dimension if the set is empty and not a subset
00846         if (!npoints && (d > 0))
00847         {
00848                 // remove allocated tables if the new dimension is higher
00849                 if (d > dim)
00850                 {
00851                         if (grid)
00852                                 delete [] grid;
00853                         grid = NULL;
00854                         gridsize (defaultgrid);
00855                         if (wrap)
00856                                 delete [] wrap;
00857                         wrap = NULL;
00858                         wrapspace (defaultwrap);
00859                         if (temp)
00860                                 delete [] temp;
00861                         temp = NULL;
00862                 }
00863 
00864                 // store the dimension in the structure
00865                 dim = d;
00866         }
00867 
00868         // return the dimension of points
00869         return dim;
00870 } /* tPointset::dimension */
00871 
00872 template <class coordtype>
00873 inline int tPointset<coordtype>::dimension () const
00874 {
00875         return dim;
00876 } /* tPointset::dimension */
00877 
00878 template <class coordtype>
00879 inline int_t tPointset<coordtype>::size () const
00880 {
00881         return npoints;
00882 } /* tPointset::size */
00883 
00884 template <class coordtype>
00885 inline bool tPointset<coordtype>::empty () const
00886 {
00887         return !npoints;
00888 } /* tPointset::empty */
00889 
00890 //template <class coordtype>
00891 //inline tPointset<coordtype>::operator int () const
00892 //{
00893 //      return npoints;
00894 //} /* tPointset::operator int */
00895 
00896 template <class coordtype>
00897 inline coordtype *tPointset<coordtype>::operator [] (int_t n) const
00898 {
00899         if ((n < 0) || (n >= npoints))
00900                 return NULL;
00901 
00902         return (tables [n / tablepoints] + (n % tablepoints) * dim);
00903 } /* tPointset::operator [] */
00904 
00905 template <class coordtype>
00906 inline int_t tPointset<coordtype>::hashfindpoint (const coordtype *c,
00907         int_t *addpos, int wrapped) const
00908 {
00909         // if there are no points or there is no hashing table, return NULL
00910         if (!hashsize)
00911                 return -1;
00912 
00913         // wrap coordinates if needed
00914         if (!wrapped && wrap)
00915         {
00916                 if (!temp)
00917                         throw "Unable to wrap point's coordinates.";
00918                 wrapcoord (temp, c, wrap, dim);
00919                 c = temp;
00920         }
00921 
00922         // prepare hashing keys
00923         int_t pos = pointhashkey (c, dim, hashsize);
00924         int_t add = 0;
00925 
00926         // start updating hashing statistics
00927         ++ (stat -> hashhits);
00928 
00929         // find the position of the point in the hashing table
00930         int_t number;
00931         while ((number = hashtable [pos]) != -1)
00932         {
00933                 if ((number >= 0) && thesame ((*this) [number], c, dim))
00934                         return (pos);
00935                 if (addpos && (*addpos < 0) && (number == -2))
00936                         *addpos = pos;
00937                 if (!add)
00938                         add = pointhashadd (c, dim, hashsize);
00939                 pos = (pos + add) % hashsize;
00940                 ++ (stat -> hashmisses);
00941         }
00942 
00943         // return the position in the hashing table
00944         return (pos);
00945 } /* hashfindpoint */
00946 
00947 template <class coordtype>
00948 inline void tPointset<coordtype>::rehash (int_t newsize)
00949 {
00950         // adjust the size of the hashing table if needed
00951         if (newsize)
00952                 newsize = ceilprimenumber (newsize);
00953         else if (!npoints && initsize && !hashsize)
00954                 newsize = ceilprimenumber (initsize);
00955 
00956         // if the new size is too small, make it bigger
00957         if (newsize <= npoints + npoints / 5)
00958         {
00959                 // compute an optimal new size for adding points
00960                 newsize = ceilprimenumber ((npoints << 1) + 131);
00961 
00962                 // check if it is not too large for 16-bit programs
00963                 int x = 0xFFFF;
00964                 if ((x < 0) && (newsize >= 16384))
00965                         throw "Pointset too large for a 16-bit prog.";
00966         }
00967 
00968         // show a message if needed
00969         if (hashsize && !quiet)
00970                 sout << "(Changing the hashing table from " << hashsize <<
00971                         " to " << newsize << " at " << npoints << " points) ";
00972         else if (!quiet)
00973                 sout << "(Using a hashing table for " << newsize << " ";
00974 
00975         // remove the old hashing table and allocate a new one
00976         hashsize = newsize;
00977         if (hashtable)
00978                 delete [] hashtable;
00979         hashtable = new int_t [hashsize];
00980         if (!hashtable)
00981                 throw "Can't allocate memory for a hashing table.";
00982         for (int_t i = 0; i < hashsize; ++ i)
00983                 hashtable [i] = -1;
00984         hashcleared = 0;
00985 
00986         // build a new hashing table
00987         for (int_t j = 0; j < npoints; ++ j)
00988         {
00989                 int_t n = hashfindpoint ((*this) [j], NULL, 1);
00990                 if (hashtable [n] != -1)
00991                         throw "A repeated point found in the hashing table.";
00992                 hashtable [n] = j;
00993         }
00994 
00995         ++ (stat -> rehashcount);
00996 
00997         if (!quiet)
00998                 sout << "points.)\n";
00999 
01000         return;
01001 } /* tPointset::rehash */
01002 
01003 template <class coordtype>
01004 inline int_t tPointset<coordtype>::add (const coordtype *c)
01005 {
01006         // prevent from adding a 'NULL' point
01007         if (!c)
01008                 return -1;
01009 
01010         // check if the dimension of the point is known
01011         if (!dim)
01012                 throw "Trying to add a point of unknown dimension.";
01013 
01014         // wrap the point's coordinates if needed
01015         if (wrap)
01016         {
01017                 if (!temp)
01018                         temp = allocatepoint<coordtype> (dim);
01019                 wrapcoord (temp, c, wrap, dim);
01020                 c = temp;
01021         }
01022 
01023         // increase the size of the hashing table if needed
01024         if (hashsize - hashcleared <= npoints + npoints / 5)
01025                 rehash ();
01026 
01027         // find a place for the new point
01028         int_t addpos = -1;
01029         int_t pos = hashfindpoint (c, &addpos, 1);
01030 
01031         // if the point is already in the set, return its number
01032         if (hashtable [pos] >= 0)
01033                 return hashtable [pos];
01034 
01035         // update the range of coordinates for statistical purposes
01036         if (minimal)
01037         {
01038                 for (int i = 0; i < dim; ++ i)
01039                         if (minimal [i] > c [i])
01040                                 minimal [i] = c [i];
01041         }
01042         else
01043         {
01044                 minimal = allocatepoint<coordtype> (dim);
01045                 copycoord (minimal, c, dim);
01046         }
01047 
01048         if (maximal)
01049         {
01050                 for (int i = 0; i < dim; ++ i)
01051                         if (maximal [i] < c [i])
01052                                 maximal [i] = c [i];
01053         }
01054         else
01055         {
01056                 maximal = allocatepoint<coordtype> (dim);
01057                 copycoord (maximal, c, dim);
01058         }
01059 
01060         // write the point's number into the hashing table
01061         if (addpos >= 0)
01062         {
01063                 pos = addpos;
01064                 if (hashtable [pos] == -2)
01065                         -- hashcleared;
01066         }
01067         hashtable [pos] = npoints;
01068 
01069         // compute the number of the table in which the point's coordinates
01070         // should be stored
01071         int_t tablenumber = npoints / tablepoints;
01072 
01073         // if there are not enough tables, add some
01074         if (tablenumber >= ntables)
01075         {
01076                 int_t moretables = (ntables << 1) + 13;
01077                 coordtype **newtables = new coordtype * [moretables];
01078                 if (!newtables)
01079                         throw "Unable to alloc a table for tables.";
01080                 for (int_t i = 0; i < moretables; ++ i)
01081                         newtables [i] = (i < ntables) ? (tables [i]) :
01082                                 (coordtype *) NULL;
01083                 if (tables)
01084                         delete [] tables;
01085                 tables = newtables;
01086                 ntables = moretables;
01087         }
01088 
01089         // if the appropriate table has not been allocate yet, allocate it
01090         if (tables [tablenumber] == NULL)
01091         {
01092                 tables [tablenumber] = new coordtype [tablepoints * dim];
01093                 if (!tables [tablenumber])
01094                         throw "Unable to alloc a table for coords.";
01095         }
01096 
01097         // copy the point's coordinates into the table
01098         copycoord (tables [tablenumber] +
01099                 ((npoints % tablepoints) * dim), c, dim);
01100 
01101         // return the point's number and increase the number of points
01102         // in the set
01103         return (npoints ++);
01104 } /* tPointset::add */
01105 
01106 template <class coordtype>
01107 inline int_t tPointset<coordtype>::add (double *c)
01108 {
01109         // prevent from adding a 'NULL' point
01110         if (!c)
01111                 return -1;
01112 
01113         if (!dim)
01114                 throw "Trying to add a point of unknown dimension.";
01115         if (!temp)
01116                 temp = allocatepoint<coordtype> (dim);
01117         roundpoint (c, temp, grid, dim);
01118         return add (temp);
01119 } /* tPointset::add */
01120 
01121 template <class coordtype>
01122 inline tPointset<coordtype> &tPointset<coordtype>::add
01123         (const tPointset<coordtype> &p)
01124 {
01125         int_t size = p. size ();
01126         for (int_t i = 0; i < size; ++ i)
01127                 this -> add (p [i]);
01128         return *this;
01129 } /* tPointset::add */
01130 
01131 template <class coordtype>
01132 inline void tPointset<coordtype>::initialize (int_t initialsize, int bequiet)
01133 {
01134         // set the 'quiet' variable
01135         quiet = bequiet;
01136 
01137         // correct the initial size if wrong
01138         if (initialsize < 0)
01139                 initialsize = 0;
01140 
01141         // initialize the point tables
01142         npoints = 0;
01143         ntables = 0;
01144         if (initialsize <= 0)
01145                 tablepoints = 3000;
01146         else if (initialsize > 10000)
01147                 tablepoints = 10000;
01148         else
01149                 tablepoints = static_cast<int> (initialsize);
01150         tables = NULL;
01151 
01152         // initialize default parameters
01153         dim = 0;
01154         grid = NULL;
01155         wrap = NULL;
01156         temp = NULL;
01157         wereremoved = 0;
01158         dimension (defaultdimension ());
01159         gridsize (defaultgrid);
01160         wrapspace (defaultwrap);
01161 
01162         // initialize hashing
01163         hashsize = 0;
01164         hashcleared = 0;
01165         hashtable = NULL;
01166         if (initialsize)
01167                 initsize = initialsize + initialsize / 5 + 3;
01168         else
01169                 initsize = 0;
01170 
01171         // optional statistic data
01172         stat = new psethashstat;
01173         minimal = NULL;
01174         maximal = NULL;
01175 
01176         return;
01177 } /* tPointset::initialize */
01178 
01179 template <class coordtype>
01180 inline tPointset<coordtype>::tPointset (int_t initialsize, int bequiet)
01181 {
01182         initialize (initialsize, bequiet);
01183         return;
01184 } /* tPointset::tPointset */
01185 
01186 template <class coordtype>
01187 inline tPointset<coordtype>::tPointset (const tPointset<coordtype> &p)
01188 {
01189         initialize (p. size (), p. quiet);
01190         add (p);
01191         return;
01192 } /* tPointset::tPointset */
01193 
01194 template <class coordtype>
01195 inline void tPointset<coordtype>::deallocate ()
01196 {
01197         // free the point tables
01198         for (int_t i = 0; i < ntables; ++ i)
01199         {
01200                 if (tables [i])
01201                         delete [] (tables [i]);
01202         }
01203         if (tables)
01204                 delete [] tables;
01205 
01206         // remove the grid and wrap tables
01207         if (grid)
01208                 delete [] grid;
01209         if (wrap)
01210                 delete [] wrap;
01211 
01212         // remove the temporary point table
01213         if (temp)
01214                 delete [] temp;
01215 
01216         // remove the minimal and maximal coordinates
01217         if (minimal)
01218                 delete [] minimal;
01219         if (maximal)
01220                 delete [] maximal;
01221 
01222         // turn off hashing
01223         if (hashtable)
01224                 delete [] hashtable;
01225 
01226         if (stat)
01227                 delete stat;
01228 
01229         return;
01230 } /* tPointset::deallocate */
01231 
01232 template <class coordtype>
01233 inline tPointset<coordtype> &tPointset<coordtype>::operator =
01234         (const tPointset<coordtype> &p)
01235 {
01236         deallocate ();
01237         initialize (p. size (), p. quiet);
01238         add (p);
01239         return *this;
01240 } /* tPointset::operator = */
01241 
01242 template <class coordtype>
01243 inline tPointset<coordtype>::~tPointset<coordtype> ()
01244 {
01245         deallocate ();
01246         return;
01247 } /* tPointset::~tPointset */
01248 
01249 template <class coordtype>
01250 inline int_t tPointset<coordtype>::getnumber (const coordtype *c) const
01251 {
01252         // prevent from looking for a 'NULL' point
01253         if (!c)
01254                 return -1;
01255 
01256         // find the position corresponding to this point in the hashing table
01257         int_t pos = hashfindpoint (c);
01258 
01259         // return the point's number found in the table
01260         return ((pos >= 0) ? hashtable [pos] : static_cast<int_t> (-1));
01261 } /* tPointset::getnumber */
01262 
01263 template <class coordtype>
01264 inline int_t tPointset<coordtype>::getnumber (const double *c) const
01265 {
01266         if (!npoints)
01267                 return -1;
01268         if (!temp)
01269                 throw "Cannot round point's coordinates.";
01270         roundpoint (c, temp, grid, dim);
01271         int_t pos = hashfindpoint (temp);
01272         return ((pos >= 0) ? hashtable [pos] : static_cast<int_t> (-1));
01273 } /* tPointset::getnumber */
01274 
01275 template <class coordtype>
01276 inline int tPointset<coordtype>::check (int_t n) const
01277 {
01278         return ((n >= 0) && (n < npoints));
01279 } /* tPointset::check */
01280 
01281 template <class coordtype>
01282 inline int tPointset<coordtype>::check (const coordtype *c) const
01283 {
01284         return (getnumber (c) != -1);
01285 } /* tPointset::check */
01286 
01287 template <class coordtype>
01288 inline int tPointset<coordtype>::check (const double *c) const
01289 {
01290         return (getnumber (c) != -1);
01291 } /* tPointset::check */
01292 
01293 template <class coordtype>
01294 inline coordtype *tPointset<coordtype>::getpoint (int_t n) const
01295 {
01296         return (*this) [n];
01297 } /* tPointset::getpoint */
01298 
01299 template <class coordtype>
01300 inline coordtype *tPointset<coordtype>::getpoint (coordtype *c) const
01301 {
01302         return (*this) [getnumber (c)];
01303 } /* tPointset::getpoint */
01304 
01305 template <class coordtype>
01306 inline coordtype *tPointset<coordtype>::getpoint (double *c) const
01307 {
01308         return (*this) [getnumber (c)];
01309 } /* tPointset::getpoint */
01310 
01311 template <class coordtype>
01312 inline coordtype *tPointset<coordtype>::getpoint (int_t n, double *c) const
01313 {
01314         coordtype *coord = (*this) [n];
01315         if (coord && c)
01316         {
01317                 for (int i = 0; i < dim; ++ i)
01318                         c [i] = (grid ? grid [i] : 1.0) * (0.5 + coord [i]);
01319         }
01320 
01321         return coord;
01322 } /* tPointset::getpoint */
01323 
01324 template <class coordtype>
01325 inline int tPointset<coordtype>::remove (int_t n)
01326 {
01327         if ((n < 0) || (n >= npoints))
01328                 return -1;
01329         wereremoved = 1;
01330 
01331         // find the point's place in the hashing table
01332         coordtype *coord = (*this) [n];
01333         int_t pos = hashfindpoint (coord);
01334 
01335         // fill in this entry in the hashing table with -2 (cleared)
01336         hashtable [pos] = -2;
01337 
01338         // copy the last point in the set to replace the point being removed
01339         if (n != npoints - 1)
01340         {
01341                 coordtype *lastcoord = (*this) [npoints - 1];
01342                 int_t lastpos = hashfindpoint (lastcoord);
01343                 hashtable [lastpos] = n;
01344                 copycoord (coord, lastcoord, dim);
01345         }
01346 
01347         // free an unused table with points' coordinates if it is sensible
01348         int_t tablenumber = npoints / tablepoints;
01349         if ((tablenumber + 2 < ntables) && tables [tablenumber + 2])
01350         {
01351                 delete [] (tables [tablenumber + 2]);
01352                 tables [tablenumber + 2] = NULL;
01353         }
01354 
01355         // decrease the number of points in the set
01356         -- npoints;
01357 
01358         // update the number of cleared entries in the hashing table
01359         ++ hashcleared;
01360 
01361         // rehash if recommended
01362         if (hashcleared > npoints + 13)
01363                 rehash (13);
01364 
01365         return (0);
01366 } /* tPointset::remove */
01367 
01368 template <class coordtype>
01369 inline int tPointset<coordtype>::remove (const coordtype *c)
01370 {
01371         return remove (getnumber (c));
01372 } /* tPointset::remove */
01373 
01374 template <class coordtype>
01375 inline int tPointset<coordtype>::remove (const double *c)
01376 {
01377         return remove (getnumber (c));
01378 } /* tPointset::remove */
01379 
01380 template <class coordtype>
01381 inline int tPointset<coordtype>::remove (const tPointset<coordtype> &p)
01382 {
01383         int_t size = p. size ();
01384         for (int_t i = 0; i < size; ++ i)
01385                 remove (p [i]);
01386         return 0;
01387 } /* tPointset::remove */
01388 
01389 template <class coordtype>
01390 inline int_t tPointset<coordtype>::gethashsize () const
01391 {
01392         return hashsize;
01393 } /* tPointset::gethashsize */
01394 
01395 
01396 // --------------------------------------------------
01397 // ------------------- NEIGHBORS --------------------
01398 // --------------------------------------------------
01399 
01403 template <class coordtype>
01404 class tNeighbors
01405 {
01406 public:
01408         tNeighbors (const coordtype *_source = NULL, int _dim = 0,
01409                 const coordtype *_wrap = NULL);
01410 
01412         tNeighbors (const tNeighbors<coordtype> &r);
01413 
01415         tNeighbors &operator = (const tNeighbors<coordtype> &r);
01416 
01418         ~tNeighbors ();
01419 
01422         coordtype *get ();
01423 
01425         void reset ();
01426 
01428         void set (coordtype *_source);
01429 
01430 private:
01432         int dim;
01433 
01435         const coordtype *source;
01436 
01438         coordtype *neighbor;
01439 
01441         signed char *counters;
01442 
01444         const coordtype *wrap;
01445 
01447         void initialize (const coordtype *_source = NULL,
01448                 int _dim = 0, const coordtype *_wrap = NULL);
01449 
01451         void deallocate ();
01452 
01453 }; /* class tNeighbors */
01454 
01455 // --------------------------------------------------
01456 
01457 template <class coordtype>
01458 void tNeighbors<coordtype>::initialize (const coordtype *_source, int _dim,
01459         const coordtype *_wrap)
01460 {
01461         source = _source;
01462         wrap = _wrap;
01463         dim = _dim;
01464         if (dim <= 0)
01465         {
01466                 dim = 0;
01467                 neighbor = NULL;
01468                 counters = NULL;
01469                 return;
01470         }
01471         neighbor = new coordtype [dim];
01472         counters = new signed char [dim];
01473         if (!neighbor || !counters)
01474                 throw "Can't allocate memory for neighbors.";
01475         reset ();
01476         return;
01477 } /* tNeighbors::initialize */
01478 
01479 template <class coordtype>
01480 tNeighbors<coordtype>::tNeighbors (const coordtype *_source, int _dim,
01481         const coordtype *_wrap)
01482 {
01483         initialize (_source, _dim, _wrap);
01484         return;
01485 } /* tNeighbors::tNeighbors */
01486 
01487 template <class coordtype>
01488 tNeighbors<coordtype>::tNeighbors (const tNeighbors<coordtype> &n)
01489 {
01490         initialize (n. source, n. dim, n. wrap);
01491         return;
01492 } /* tNeighbors::tNeighbors */
01493 
01494 template <class coordtype>
01495 tNeighbors<coordtype> &tNeighbors<coordtype>::operator =
01496         (const tNeighbors<coordtype> &n)
01497 {
01498         deallocate ();
01499         initialize (n. source, n. dim, n. wrap);
01500         return *this;
01501 } /* tNeighbors::operator = */
01502 
01503 template <class coordtype>
01504 void tNeighbors<coordtype>::deallocate ()
01505 {
01506         if (neighbor)
01507                 delete [] neighbor;
01508         if (counters)
01509                 delete [] counters;
01510         return;
01511 } /* tNeighbors::deallocate */
01512 
01513 template <class coordtype>
01514 tNeighbors<coordtype>::~tNeighbors<coordtype> ()
01515 {
01516         deallocate ();
01517         return;
01518 } /* tNeighbors::~tNeighbors */
01519 
01520 template <class coordtype>
01521 void tNeighbors<coordtype>::reset ()
01522 {
01523         if (counters)
01524         {
01525                 for (int i = 0; i < dim; ++ i)
01526                         counters [i] = 0;
01527         }
01528         return;
01529 } /* tNeighbors::reset */
01530 
01531 template <class coordtype>
01532 void tNeighbors<coordtype>::set (coordtype *_source)
01533 {
01534         source = _source;
01535         return;
01536 } /* tNeighbors::set */
01537 
01538 template <class coordtype>
01539 coordtype *tNeighbors<coordtype>::get ()
01540 {
01541         // if the initialization was incorrect, return NULL
01542         if (!dim || !counters || !neighbor || !source)
01543                 return NULL;
01544 
01545         // compute the next set of counters
01546         // and return NULL if this is the end
01547         int cur = 0;
01548         while ((cur < dim) && (counters [cur] == -1))
01549                 counters [cur ++] = 0;
01550         if (cur >= dim)
01551                 return NULL;
01552         counters [cur] = counters [cur] ?
01553                 (signed char) -1 : (signed char) 1;
01554 
01555         // compute the neighbor corresponding to these counters
01556         for (int i = 0; i < dim; ++ i)
01557                 neighbor [i] = (coordtype) (source [i] + counters [i]);
01558 
01559         // wrap the neighbor's coordinates if required
01560         if (wrap)
01561                 wrapcoord (neighbor, neighbor, wrap, dim);
01562 
01563         // return the neighbor's coordinates
01564         return neighbor;
01565 
01566 } /* tNeighbors::get */
01567 
01568 
01569 // --------------------------------------------------
01570 // ------------------- RECTANGLE --------------------
01571 // --------------------------------------------------
01572 
01580 template <class coordtype>
01581 class tRectangle
01582 {
01583 public:
01585         tRectangle (const coordtype *_left = NULL,
01586                 const coordtype *_right = NULL, int _dim = 0);
01587 
01589         tRectangle (const tRectangle<coordtype> &r);
01590 
01592         tRectangle &operator = (const tRectangle<coordtype> &r);
01593 
01595         ~tRectangle ();
01596 
01599         const coordtype *get ();
01600 
01602         void reset ();
01603 
01604 private:
01606         int dim;
01607 
01609         const coordtype *left;
01610 
01612         const coordtype *right;
01613 
01615         coordtype *point;
01616 
01618         int firstpoint;
01619 
01621         void initialize (const coordtype *_left = NULL,
01622                 const coordtype *_right = NULL, int _dim = 0);
01623 
01625         void deallocate ();
01626 
01627 }; /* class tRectangle */
01628 
01629 // --------------------------------------------------
01630 
01631 template <class coordtype>
01632 void tRectangle<coordtype>::initialize (const coordtype *_left,
01633         const coordtype *_right, int _dim)
01634 {
01635         firstpoint = 0;
01636         left = _left;
01637         right = _right;
01638         dim = _dim;
01639         if (dim <= 0)
01640         {
01641                 dim = 0;
01642                 point = NULL;
01643                 return;
01644         }
01645         point = new coordtype [dim];
01646         if (!point)
01647                 throw "Can't allocate memory for a rectangle.";
01648         reset ();
01649 
01650         return;
01651 } /* tRectangle::initialize */
01652 
01653 template <class coordtype>
01654 tRectangle<coordtype>::tRectangle (const coordtype *_left, const coordtype *_right,
01655         int _dim)
01656 {
01657         initialize (_left, _right, _dim);
01658         return;
01659 } /* tRectangle::tRectangle */
01660 
01661 template <class coordtype>
01662 tRectangle<coordtype>::tRectangle (const tRectangle<coordtype> &r)
01663 {
01664         initialize (r. left, r. right, r. dim);
01665         return;
01666 } /* tRectangle::tRectangle */
01667 
01668 template <class coordtype>
01669 tRectangle<coordtype> &tRectangle<coordtype>::operator = (const tRectangle<coordtype> &r)
01670 {
01671         deallocate ();
01672         initialize (r. left, r. right, r. dim);
01673         return *this;
01674 } /* tRectangle::operator = */
01675 
01676 template <class coordtype>
01677 void tRectangle<coordtype>::deallocate ()
01678 {
01679         if (point)
01680                 delete [] point;
01681         return;
01682 } /* tRectangle::deallocate */
01683 
01684 template <class coordtype>
01685 tRectangle<coordtype>::~tRectangle<coordtype> ()
01686 {
01687         deallocate ();
01688         return;
01689 } /* tRectangle::~tRectangle */
01690 
01691 template <class coordtype>
01692 void tRectangle<coordtype>::reset ()
01693 {
01694         for (int i = 0; i < dim; ++ i)
01695                 point [i] = left [i];
01696         firstpoint = 1;
01697         return;
01698 } /* tRectangle::reset */
01699 
01700 template <class coordtype>
01701 const coordtype *tRectangle<coordtype>::get ()
01702 {
01703         // if this is the first point, check if the rectangle is nonempty
01704         if (firstpoint)
01705         {
01706                 firstpoint = 0;
01707                 for (int i = 0; i < dim; ++ i)
01708                         if (left [i] >= right [i])
01709                                 return NULL;
01710                 return point;
01711         }
01712 
01713         // compute the next point of the rectangle
01714         int cur = 0;
01715         while ((cur < dim) && (++ (point [cur]) >= right [cur]))
01716         {
01717                 point [cur] = left [cur];
01718                 ++ cur;
01719         }
01720 
01721         // if the iterator has run out of points, return NULL
01722         if (cur >= dim)
01723         {
01724                 firstpoint = 1;
01725                 return NULL;
01726         }
01727 
01728         // return the point's coordinates
01729         return point;
01730 
01731 } /* tRectangle::get */
01732 
01733 
01734 // --------------------------------------------------
01735 // ---------------- various functions ---------------
01736 // --------------------------------------------------
01737 
01739 template <class coordtype>
01740 int countneighbors (const tPointset<coordtype> &p, const coordtype *c,
01741         int which, int maxcount)
01742 {
01743         if (p. empty ())
01744         {
01745                 if (which == INSIDE)
01746                         return 0;
01747                 else
01748                         return maxcount;
01749         }
01750 
01751         int count = 0;
01752         tNeighbors<coordtype> neigh (c, p. dimension ());
01753         while ((c = neigh. get ()) != NULL)
01754         {
01755                 if (which == INSIDE)
01756                 {
01757                         if (p. check (c))
01758                                 ++ count;
01759                 }
01760                 else if (which == OUTSIDE)
01761                 {
01762                         if (!p. check (c))
01763                                 ++ count;
01764                 }
01765 
01766                 if (maxcount && (count >= maxcount))
01767                         return count;
01768         }
01769 
01770         return count;
01771 } /* countneighbors */
01772 
01773 template <class coordtype>
01774 int countneighbors (const tPointset<coordtype> &p,
01775         const tPointset<coordtype> &q, coordtype *c,
01776         int which, int maxcount)
01777 {
01778         if ((q. empty ()) || (p. dimension () != q. dimension ()))
01779                 return countneighbors (p, c, which, maxcount);
01780         else if (p. empty ())
01781                 return countneighbors (q, c, which, maxcount);
01782 
01783         int count = 0;
01784         tNeighbors<coordtype> neigh (c, p. dimension ());
01785         while ((c = neigh. get ()) != NULL)
01786         {
01787                 if (which == INSIDE)
01788                 {
01789                         if (p. check (c) || q. check (c))
01790                                 ++ count;
01791                 }
01792                 else if (which == OUTSIDE)
01793                 {
01794                         if (!p. check (c) && !q. check (c))
01795                                 ++ count;
01796                 }
01797 
01798                 if (maxcount && (count >= maxcount))
01799                         return count;
01800         }
01801 
01802         return count;
01803 } /* countneighbors */
01804 
01805 template <class coordtype>
01806 int attheborder (const tPointset<coordtype> &p, const coordtype *c)
01807 {
01808         return (countneighbors (p, c, OUTSIDE, 1));
01809 
01810 } /* attheborder */
01811 
01812 template <class coordtype>
01813 int_t findboundarypoint (tPointset<coordtype> &p, int_t n, int direction)
01814 {
01815         if (direction >= 0)
01816         {
01817                 if (n >= p. size ())
01818                         return -1;
01819                 if (n < 0)
01820                         n = 0;
01821                 int_t size = p. size ();
01822                 while (n < size)
01823                 {
01824                         if (attheborder (p, p [n]))
01825                                 return n;
01826                         else
01827                                 ++ n;
01828                 }
01829                 return -1;
01830         }
01831         else
01832         {
01833                 if (n < 0)
01834                         return -1;
01835                 if (n >= p. size ())
01836                         n = p. size () - 1;
01837                 while (n >= 0)
01838                 {
01839                         if (attheborder (p, p [n]))
01840                                 return n;
01841                         else
01842                                 -- n;
01843                 }
01844                 return -1;
01845         }
01846 } /* findboundarypoint */
01847 
01848 template <class coordtype>
01849 int_t findboundarypoint (tPointset<coordtype> &p, tPointset<coordtype> &q,
01850         int_t n, int direction)
01851 {
01852         if (direction >= 0)
01853         {
01854                 if (n >= p. size ())
01855                         return -1;
01856                 if (n < 0)
01857                         n = 0;
01858                 while (n < p. size ())
01859                 {
01860                         if (countneighbors (p, q, p [n], OUTSIDE, 1))
01861                                 return n;
01862                         else
01863                                 ++ n;
01864                 }
01865                 return -1;
01866         }
01867         else
01868         {
01869                 if (n < 0)
01870                         return -1;
01871                 if (n >= p. size ())
01872                         n = p. size () - 1;
01873                 while (n >= 0)
01874                 {
01875                         if (countneighbors (p, q, p [n], OUTSIDE, 1))
01876                                 return n;
01877                         else
01878                                 -- n;
01879                 }
01880                 return -1;
01881         }
01882 } /* findboundarypoint */
01883 
01884 template <class coordtype>
01885 void computeboundary (const tPointset<coordtype> &p, tPointset<coordtype> &b)
01886 {
01887         // add all the points which are at the border
01888         int_t size = p. size ();
01889         for (int_t i = 0; i < size; ++ i)
01890         {
01891                 coordtype *c = p [i];
01892                 if (attheborder (p, c))
01893                         b. add (c);
01894         }
01895         return;
01896 } /* computeboundary */
01897 
01898 template <class coordtype>
01899 tPointset<coordtype> *computeboundary (tPointset<coordtype> &p)
01900 {
01901         // create a new set of points
01902         tPointset<coordtype> *boundary = new tPointset<coordtype>;
01903 
01904         // if cannot allocate memory for it, return nothing
01905         if (!boundary)
01906                 return NULL;
01907 
01908         // copy the global parameters (the defaults may be different)
01909         boundary -> dimension (p. dimension ());
01910         boundary -> gridsize (p. gridsize ());
01911         boundary -> wrapspace (p. wrapspace ());
01912 
01913         // compute the boundary
01914         computeboundary (p, *boundary);
01915 
01916         return boundary;
01917 } /* computeboundary */
01918 
01919 template <class coordtype>
01920 void enhancepoint (tPointset<coordtype> &p, coordtype *c)
01921 {
01922         tNeighbors<coordtype> neigh (c, p. dimension ());
01923 
01924         while ((c = neigh. get ()) != NULL)
01925                 p. add (c);
01926 
01927         return;
01928 } /* enhancepoint */
01929 
01930 template <class coordtype>
01931 void enhancepoint (tPointset<coordtype> &p, int_t n)
01932 {
01933         enhancepoint (p, p [n]);
01934 
01935         return;
01936 } /* enhancepoint */
01937 
01938 template <class coordtype>
01939 void enhance (tPointset<coordtype> &p)
01940 {
01941         int_t size = p. size ();
01942         for (int_t i = 0; i < size; ++ i)
01943                 enhancepoint (p, p [i]);
01944 
01945         return;
01946 } /* enhance */
01947 
01948 template <class coordtype>
01949 int read (textfile &f, coordtype *c, int maxdim)
01950 {
01951         // ignore lines until you can find an opening parenthesis,
01952         // brace or bracket and read this character
01953         int ready = 0;
01954         while (!ready)
01955         {
01956                 switch (f. checkchar ())
01957                 {
01958                         case '(':
01959                         case '[':
01960                         case '{':
01961                         case '"':
01962                         case '\'':
01963                                 f. readchar ();
01964                                 ready = 1;
01965                                 break;
01966                         case '+':
01967                         case '-':
01968                                 break;
01969                         case EOF:
01970                                 return 0;
01971                         default:
01972                                 f. ignoreline ();
01973                                 break;
01974                 }
01975         }
01976 
01977         // read the coordinates
01978         int n = 0;
01979         while (1)
01980         {
01981                 // read the current coordinate of the point
01982                 c [n ++] = (coordtype) f. readnumber ();
01983 
01984                 // read a comma between the coordinates
01985                 // or the closing parenthesis, brace or bracket if any
01986                 switch (f. checkchar ())
01987                 {
01988                         case ')':
01989                         case ']':
01990                         case '}':
01991                         case '"':
01992                         case '\'':
01993                                 f. readchar ();
01994                                 return n;
01995                         case ',':
01996                                 f. readchar ();
01997                                 break;
01998                         case '-':
01999                         case '+':
02000                                 break;
02001                         default:
02002                                 if ((f. checkchar () < '0') ||
02003                                         (f. checkchar () > '9'))
02004                                         return n;
02005                 }
02006 
02007                 // check if the maximal dimension allowed has been reached
02008                 if (n >= maxdim)
02009                         return n;
02010         }
02011 } /* read */
02012 
02013 template <class coordtype>
02014 int read (std::istream &in, coordtype *c, int maxdim)
02015 {
02016         textfile f (in);
02017         return read (f, c, maxdim);
02018 } /* read */
02019 
02027 template <class coordtype>
02028 inline int readcoordinates (std::istream &in, coordtype *coord, int maxdim,
02029         int closing)
02030 {
02031         // read the opening parenthesis
02032         if (closing == EOF)
02033                 closing = readparenthesis (in);
02034         if (closing == EOF)
02035                 return -1;
02036 
02037         int cur = 0;
02038 
02039         ignorecomments (in);
02040         while ((in. peek () != closing) && (cur < maxdim))
02041         {
02042                 // ignore a plus before the number if necessary
02043                 if (in. peek () == '+')
02044                         in. get ();
02045 
02046                 // finish if there is no number at the input
02047                 if ((in. peek () != '-') && !std::isdigit (in. peek ()))
02048                         break;
02049 
02050                 // read the number as 'long' (just in case)
02051                 long number;
02052                 in >> number;
02053         //      if (!in)
02054         //              return -1;
02055 
02056                 // transform this number to a coordtype
02057                 coord [cur] = (coordtype) number;
02058                 if (coord [cur] != number)
02059                         return -1;
02060 
02061                 // move to the next coordtype position
02062                 ++ cur;
02063                 if (closing == '\n')
02064                 {
02065                         while ((in. peek () == ' ') ||
02066                                 (in. peek () == '\t') ||
02067                                 (in. peek () == '\r'))
02068                                 in. get ();
02069                 }
02070                 else
02071                         ignorecomments (in);
02072 
02073                 // one more thing: read the following comma if any
02074                 if (in. peek () == ',')
02075                 {
02076                         in. get ();
02077                         ignorecomments (in);
02078                 }
02079         }
02080 
02081         // verify that the coordinates were read successfully
02082 //      if (!in)
02083 //              return -1;
02084 
02085         // read the closing parenthesis
02086         if (in. peek () == closing)
02087                 in. get ();
02088         else if ((closing == '\n') && (in. peek () == EOF))
02089                 ;
02090         else
02091                 return -1;
02092 
02093         return cur;
02094 } /* readcoordinates */
02095 
02096 template <class coordtype>
02097 inline int readcoordinates (std::istream &in, coordtype *coord, int maxdim)
02098 {
02099         return readcoordinates (in, coord, maxdim, EOF);
02100 } /* readcoordinates */
02101 
02102 template <class coordtype>
02103 int write (std::ostream &out, const coordtype *c, int dim, char parenthesis,
02104         char closing)
02105 {
02106         // write the opening parenthesis, brace or bracket
02107         if (parenthesis != 0)
02108                 out << parenthesis;
02109 
02110         // output the point's coordinates
02111         for (int i = 0; i < dim; ++ i)
02112         {
02113                 if (i)
02114                         out << ",";
02115                 out << c [i];
02116         }
02117 
02118         // write an appropriate closing parenthesis, brace or bracket
02119         if (closing)
02120                 out << closing;
02121         else if (parenthesis)
02122         {
02123                 int ch = closingparenthesis (parenthesis);
02124                 if (ch == EOF)
02125                         closing = parenthesis;
02126                 else
02127                         closing = (char) ch;
02128                 out << closing;
02129         }
02130 
02131         return dim;
02132 } /* write */
02133 
02134 template <class coordtype>
02135 int readcubeorcell (std::istream &in, coordtype *left, coordtype *right,
02136         int maxdim, int *type)
02137 {
02138         // ignore all the texts that appear before the actual cell or cube
02139         int closing;
02140         while ((closing = closingparenthesis (in. peek ())) == EOF)
02141         {
02142                 ignoreline (in);
02143                 ignorecomments (in);
02144                 if (!in)
02145                         return 0;
02146         }
02147 
02148         // try reading the coordinates of the cube
02149         int dim = readcoordinates (in, left, maxdim);
02150 
02151         // if successful, then both parentheses are read
02152         if (dim > 0)
02153         {
02154                 // check if this is not a product of intervals
02155                 ignorecomments (in);
02156                 if (((in. peek () != 'x') && (in. peek () != 'X')) ||
02157                         (dim > 2))
02158                 {
02159                         // set the right coordinates accordingly
02160                         for (int i = 0; i < dim; ++ i)
02161                                 right [i] = (coordtype) (left [i] + 1);
02162                         if (type)
02163                                 *type = CUBE;
02164                         return dim;
02165                 }
02166 
02167                 // read the remaining intervals
02168                 right [0] = (dim < 2) ? left [0] : left [1];
02169                 dim = 1;
02170                 coordtype temp [2];
02171                 while ((in. peek () == 'x') || (in. peek () == 'X'))
02172                 {
02173                         if (dim >= maxdim)
02174                                 throw "Too many intervals in a product.";
02175                         in. get ();
02176                         ignorecomments (in);
02177                         int d = readcoordinates (in, temp, 2);
02178                         if ((d <= 0) || !in)
02179                                 throw "Can't read a product of intervals.";
02180                         left [dim] = temp [0];
02181                         right [dim] = (d < 2) ? temp [0] : temp [1];
02182                         ++ dim;
02183                         ignorecomments (in);
02184                 }
02185                 if (type)
02186                         *type = CELL;
02187                 return dim;
02188         }
02189 
02190         // otherwise, this is a cubical cell
02191         else
02192         {
02193                 // if an error is set for the input stream, clear it
02194                 in. clear (in. rdstate () & ~std::ios::failbit);
02195                 ignorecomments (in);
02196 
02197                 // read two points for the cell
02198                 int leftdim = readcoordinates (in, left, maxdim);
02199                 ignorecomments (in);
02200                 int rightdim = readcoordinates (in, right, maxdim);
02201                 ignorecomments (in);
02202 
02203                 // compare the dimensions
02204                 if (!leftdim || !rightdim)
02205                         throw "Can't read a cell.";
02206                 else if (leftdim != rightdim)
02207                         throw "Different dim of left & right point.";
02208                 else
02209                         dim = leftdim;
02210 
02211                 // read the closing bracket of the cell
02212                 if (in. get () != closing)
02213                         throw "Can't read the closing bracket of a cell.";
02214                 ignorecomments (in);
02215                 if (type)
02216                         *type = CELL;
02217         }
02218         return dim;
02219 } /* readcubeorcell */
02220 
02221 template <class coordtype>
02222 int_t read (textfile &f, tPointset<coordtype> &p,
02223         int_t first, int_t howmany,
02224         coordtype *wrap, int maxdim, int quiet,
02225         tPointset<coordtype> *notthese)
02226 {
02227         // prepare a temporary point of maximal dimension
02228         if (maxdim <= 0)
02229         {
02230                 if (wrap)
02231                         wrap = NULL;
02232                 maxdim = 100;
02233         }
02234         coordtype *temp = allocatepoint<coordtype> (maxdim + 1);
02235 
02236         int_t count = 0;
02237         int dim = p. empty () ? 0 : p. dimension ();
02238 
02239         if (notthese && !notthese -> empty ())
02240         {
02241                 if (!dim)
02242                         dim = notthese -> dimension ();
02243                 else if (dim != notthese -> dimension ())
02244                 {
02245                         if (!quiet)
02246                                 sout << "Error: Dimensions not the same.\n";
02247                         return -1;
02248                 }
02249         }
02250 
02251         while (1)
02252         {
02253                 // stop reading if it is already enough
02254                 if ((howmany >= 0) && (count >= howmany))
02255                 {
02256                         delete [] temp;
02257                         return count;
02258                 }
02259 
02260                 // ignore all the lines which do not start
02261                 // with an opening parenthesis
02262                 while ((f. checkchar () != 40) && (f. checkchar () != 91) &&
02263                         (f. checkchar () != 123) && (f. checkchar () != EOF))
02264                         f. ignoreline ();
02265 
02266                 // if this is the end of the file, finish successfully
02267                 if (f. checkchar () == EOF)
02268                 {
02269                         delete [] temp;
02270                         return count;
02271                 }
02272 
02273                 // read a point
02274                 int n = read (f, temp, maxdim + 1);
02275                 if (n > maxdim)
02276                 {
02277                         if (!quiet)
02278                                 sout << "Line " << f. linenumber () <<
02279                                         ": The point has too many " <<
02280                                         "coordinates.\n";
02281                         delete [] temp;
02282                         return -1;
02283                 }
02284 
02285                 // check if the number of coordinates is the same
02286                 // as the dimension of the points in the set
02287                 if (!first && dim && n && (n != dim))
02288                 {
02289                         if (!quiet)
02290                                 sout << "Line " << f. linenumber () <<
02291                                         ": Incorrect point dimension.\n";
02292                         delete [] temp;
02293                         return -1;
02294                 }
02295 
02296                 // set the dimension to be the number of coordinates
02297                 if (!first && !dim)
02298                 {
02299                         dim = n;
02300                         if (p. dimension () != dim)
02301                                 p. dimension (dim);
02302                 }
02303 
02304                 // add the read point to the set
02305                 if (first)
02306                         -- first;
02307                 else
02308                 {
02309                         if (wrap)
02310                         {
02311                                 p. wrapspace (wrap);
02312                                 wrap = NULL;
02313                         }
02314                         if (!notthese || !notthese -> check (temp))
02315                                 p. add (temp);
02316                         ++ count;
02317                 }
02318         }
02319 } /* read */
02320 
02321 template <class coordtype>
02322 int_t read (std::istream &in, tPointset<coordtype> &p,
02323         int_t first, int_t howmany, coordtype *wrap, int maxdim,
02324         int quiet, tPointset<coordtype> *notthese)
02325 {
02326         textfile f (in);
02327         return read (f, p, first, howmany, wrap, maxdim, quiet, notthese);
02328 } /* read */
02329 
02330 template <class coordtype>
02331 int_t read (textfile &f, tPointset<coordtype> &p,
02332         coordtype *wrap, int maxdim,
02333         int quiet, tPointset<coordtype> *notthese)
02334 {
02335         return read (f, p, 0, -1, wrap, maxdim, quiet, notthese);
02336 } /* read */
02337 
02338 template <class coordtype>
02339 int_t read (std::istream &in, tPointset<coordtype> &p, coordtype *wrap,
02340         int maxdim, int quiet, tPointset<coordtype> *notthese)
02341 {
02342         textfile f (in);
02343         return read (f, p, wrap, maxdim, quiet, notthese);
02344 } /* read */
02345 
02346 template <class coordtype>
02347 textfile &operator >> (textfile &f, tPointset<coordtype> &p)
02348 {
02349         read (f, p);
02350         return f;
02351 } /* operator >> */
02352 
02353 template <class coordtype>
02354 std::istream &operator >> (std::istream &in, tPointset<coordtype> &p)
02355 {
02356         textfile f (in);
02357         read (f, p);
02358         return in;
02359 } /* operator >> */
02360 
02361 template <class coordtype>
02362 int_t write (std::ostream &out, tPointset<coordtype> &p,
02363         int_t first, int_t howmany, int)
02364 {
02365         int_t count = 0;
02366         int dim = p. dimension ();
02367 
02368         // write the number of points in the set
02369         out << "; The set contains " << p. size () << " points.\n";
02370         if (first)
02371                 out << "; Not writing first " << first << " points.\n";
02372         if (howmany >= 0)
02373                 out << "; Writing at most " << howmany << " points.\n";
02374 
02375         // write the size of the grid
02376         if (dim && p. gridsize ())
02377         {
02378                 for (int i = 0; i < dim; ++ i)
02379                         out << (i ? ", " : "; Grid size: ") <<
02380                                 p. gridsize () [i];
02381                 out << '\n';
02382         }
02383 
02384         // write statistical information if it has been gathered
02385         if (p. gethashsize ())
02386                 out << "; Hashing table size: " <<
02387                         p. gethashsize () << " entries.\n";
02388 
02389         if (p. stat -> hashhits)
02390                 out << "; Hashing statistics: " <<
02391                         ((p. stat -> hashhits + p. stat -> hashmisses) /
02392                         p. stat -> hashhits) << '.' <<
02393                         ((p. stat -> hashhits + p. stat -> hashmisses) * 10 /
02394                         p. stat -> hashhits) % 10 << " trials per point, " <<
02395                         p. stat -> rehashcount << " times rehashed.\n";
02396 
02397         if (p. minimal && p. maximal)
02398         {
02399                 out << "; The coordinates " <<
02400                         (p. wereremoved ? "varied" : "vary") << " from ";
02401                 write (out, p. minimal, dim);
02402                 out << " to ";
02403                 write (out, p. maximal, dim);
02404                 out << ".\n";
02405         }
02406 
02407         std::time_t tm;
02408         std::time (&tm);
02409         out << "; Work time: " << (tm - p. stat -> creationtime) <<
02410                 " seconds.\n";
02411 
02412         // add a warning if any points were removed
02413         if (p. wereremoved)
02414                 out << "; Warning: Points were removed, " <<
02415                         "so their original order may be distorted.\n";
02416 
02417         // write out the dimension of the points (for compatibility
02418         // with the older versions of 'pointset')
02419         out << "dimension " << p. dimension () << '\n';
02420 
02421         // output all the points
02422         int_t size = p. size ();
02423         for (int_t i = first; i < size; ++ i)
02424         {
02425                 if ((howmany >= 0) && (count >= howmany))
02426                         return count;
02427                 write (out, p [i], dim);
02428                 out << '\n';
02429                 ++ count;
02430         }
02431 
02432         return count;
02433 } /* write */
02434 
02435 template <class coordtype>
02436 std::ostream &operator << (std::ostream &out, tPointset<coordtype> &p)
02437 {
02438         write (out, p);
02439         return out;
02440 } /* operator << */
02441 
02442 
02443 } // namespace homology
02444 } // namespace chomp
02445 
02446 #endif // _CHOMP_CUBES_POINTSET_H_
02447 
02449