hashsets.h

Go to the documentation of this file.
00001 
00002 
00003 
00019 
00020 // Copyright (C) 1997-2010 by Pawel Pilarczyk.
00021 //
00022 // This file is part of the Homology Library.  This library is free software;
00023 // you can redistribute it and/or modify it under the terms of the GNU
00024 // General Public License as published by the Free Software Foundation;
00025 // either version 2 of the License, or (at your option) any later version.
00026 //
00027 // This library is distributed in the hope that it will be useful,
00028 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00029 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00030 // GNU General Public License for more details.
00031 //
00032 // You should have received a copy of the GNU General Public License along
00033 // with this software; see the file "license.txt".  If not, write to the
00034 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00035 // MA 02111-1307, USA.
00036 
00037 // Started in January 2002. Last revision: May 24, 2010.
00038 
00039 
00040 #ifndef _CHOMP_STRUCT_HASHSETS_H_
00041 #define _CHOMP_STRUCT_HASHSETS_H_
00042 
00043 #include "chomp/system/config.h"
00044 #include "chomp/system/textfile.h"
00045 #include "chomp/struct/multitab.h"
00046 
00047 #include <cstdlib>
00048 #include <ctime>
00049 #include <iostream>
00050 
00051 namespace chomp {
00052 namespace homology {
00053 
00054 
00055 // class templates defined within this header file (in this order):
00056 template <class element>
00057 class hashedset;
00058 template <class domelement, class imgelement>
00059 class mvmap;
00060 
00061 
00062 // --------------------------------------------------
00063 // ------------------- hash stat --------------------
00064 // --------------------------------------------------
00065 
00068 class hashstat
00069 {
00070 public:
00072         hashstat ();
00073 
00075         std::time_t creationtime;
00076 
00079         unsigned long hashhits;
00080 
00083         unsigned long hashmisses;
00084 
00087         unsigned long rehashcount;
00088 
00089 }; /* class hashstat */
00090 
00091 // --------------------------------------------------
00092 
00093 inline hashstat::hashstat ()
00094 {
00095         std::time (&creationtime);
00096         hashhits = 0;
00097         hashmisses = 0;
00098         rehashcount = 0;
00099         return;
00100 } /* hashstat::hashstat */
00101 
00102 // --------------------------------------------------
00103 
00106 inline std::ostream &operator << (std::ostream &out, const hashstat &s)
00107 {
00108         if (!s. hashhits)
00109                 return out;
00110         out << "hashing: " << s. hashhits << " hits, avg " <<
00111                 ((s. hashhits + s. hashmisses) / s. hashhits) << "." <<
00112                 ((s. hashhits + s. hashmisses) * 10 / s. hashhits) % 10 <<
00113                 " attempts (" << s. rehashcount << " times rehashed)";
00114         return out;
00115 } /* operator << */
00116 
00117 
00118 // --------------------------------------------------
00119 // ------------------- hashed set -------------------
00120 // --------------------------------------------------
00121 
00129 template <class element>
00130 class hashedset
00131 {
00132 public:
00134         typedef element value_type;
00135 
00139         explicit hashedset (int_t initialsize = 0, int bequiet = 1);
00140 
00142         hashedset (const hashedset<element> &s);
00143 
00145         hashedset &operator = (const hashedset<element> &s);
00146 
00148         ~hashedset (void);
00149 
00152         int_t getnumber (const element &e) const;
00153 
00158         bool checknum (int_t n) const;
00159 
00162         bool check (const element &e) const;
00163 
00165         const element &operator [] (int_t n) const;
00166 
00168         const element &get (int_t n) const;
00169 
00171         const element &front () const;
00172 
00174         const element &top () const;
00175 
00179         int_t add (const element &e);
00180 
00182         int_t push (const element &e);
00183 
00185         int_t push_back (const element &e);
00186 
00189         int remove (const element &e);
00190 
00193         int removenum (int_t n);
00194 
00197         int_t pop ();
00198 
00200         hashedset<element> &add (const hashedset<element> &s);
00201 
00203         hashedset<element> &remove (const hashedset<element> &s);
00204 
00206         int_t size () const;
00207 
00209         bool empty () const;
00210 
00212         void swap (hashedset<element> &other);
00213 
00216         bool operator == (const hashedset<element> &other) const;
00217 
00220         void intersection (const hashedset<element> &s1,
00221                 const hashedset<element> &s2);
00222 
00226         hashstat *stat;
00227 
00228 private:
00230         static const int_t InitHashSize;
00231 
00233         static const int_t InitTabSize;
00234 
00240         static const int_t StartHashingSize;
00241 
00243         int_t nelem;
00244 
00246         multitable<element> tab;
00247 
00249         int hashing;
00250 
00252         int_t hashsize;
00253 
00255         int_t hashcleared;
00256 
00259         multitable<int_t> hashtable;
00260 
00266         int_t hashfind (const element &e, int_t *addpos = NULL) const;
00267 
00271         void rehash (int_t newsize = 0);
00272 
00275         static bool numberisprime (const int_t &n);
00276 
00278         static int_t rounduptoprime (int_t n);
00279 
00280 }; /* class hashedset */
00281 
00282 // --------------------------------------------------
00283 
00284 template <class element>
00285 const int_t hashedset<element>::InitHashSize (137);
00286 
00287 template <class element>
00288 const int_t hashedset<element>::InitTabSize (30);
00289 
00290 template <class element>
00291 const int_t hashedset<element>::StartHashingSize (30);
00292 
00293 // --------------------------------------------------
00294 
00295 template <class element>
00296 hashedset<element>::hashedset (int_t initialsize, int bequiet):
00297         nelem (0), tab ((initialsize > 0) ? initialsize :
00298                 int_t (InitTabSize)),
00299         hashing (0),
00300         hashsize (initialsize + (initialsize >> 2) + InitHashSize),
00301         hashcleared (0), hashtable (hashsize)
00302 {
00303         hashedset<element>::rounduptoprime (hashsize);
00304         if (bequiet)
00305                 stat = NULL;
00306         else
00307                 stat = new hashstat;
00308         return;
00309 } /* hashedset<element>::hashedset */
00310 
00311 template <class element>
00312 hashedset<element>::hashedset (const hashedset<element> &s):
00313         nelem (s. nelem), tab (s. tab),
00314         hashing (s. hashing), hashsize (s. hashsize),
00315         hashcleared (s. hashcleared), hashtable (s. hashtable)
00316 {
00317         if (s. stat)
00318                 stat = new hashstat;
00319         else
00320                 stat = NULL;
00321         return;
00322 } /* hashedset<element>::hashedset */
00323 
00324 template <class element>
00325 hashedset<element> &hashedset<element>::operator =
00326         (const hashedset<element> &s)
00327 {
00328         if (this == &s)
00329                 return *this;
00330 
00331         if (s. stat)
00332                 stat = new hashstat (*stat);
00333         nelem = s. nelem;
00334         tab = s. tab;
00335         hashing = s. hashing;
00336         hashsize = s. hashsize;
00337         hashcleared = s. hashcleared;
00338         hashtable = s. hashtable;
00339 
00340         return *this;
00341 } /* multitable<element>::operator = */
00342 
00343 template <class element>
00344 hashedset<element>::~hashedset ()
00345 {
00346         if (!stat)
00347                 return;
00348         sout << "  " << *stat << '\n';
00349         delete stat;
00350         stat = NULL;
00351         return;
00352 } /* hashedset<element>::~hashedset */
00353 
00354 template <class element>
00355 int_t hashedset<element>::getnumber (const element &e) const
00356 {
00357         if (hashing)
00358         {
00359                 int_t pos = hashfind (e);
00360                 return (hashtable (pos));
00361         }
00362         else
00363         {
00364                 for (int_t i = 0; i < nelem; ++ i)
00365                 {
00366                         if (tab (i) == e)
00367                                 return i;
00368                 }
00369                 return -1;
00370         }
00371 } /* hashedset<element>::getnumber */
00372 
00373 template <class element>
00374 inline bool hashedset<element>::checknum (int_t n) const
00375 {
00376         return ((n >= 0) && (n < nelem));
00377 } /* hashedset<element>::checknum */
00378 
00379 template <class element>
00380 inline bool hashedset<element>::check (const element &e) const
00381 {
00382         return (getnumber (e) >= 0);
00383 } /* hashedset<element>::check */
00384 
00385 
00386 template <class element>
00387 inline const element &hashedset<element>::get (int_t n) const
00388 {
00389         if ((n < 0) || (n >= nelem))
00390                 throw "Trying to get an element out of range.";
00391         return tab (n);
00392 } /* hashedset<element>::get */
00393 
00394 template <class element>
00395 inline const element &hashedset<element>::operator [] (int_t n) const
00396 {
00397         return get (n);
00398 } /* hashedset<element>::operator [] */
00399 
00400 template <class element>
00401 inline const element &hashedset<element>::front () const
00402 {
00403         return get (nelem - 1);
00404 } /* hashedset<element>::front */
00405 
00406 template <class element>
00407 inline const element &hashedset<element>::top () const
00408 {
00409         return get (nelem - 1);
00410 } /* hashedset<element>::top */
00411 
00412 template <class element>
00413 int_t hashedset<element>::add (const element &e)
00414 {
00415         if (!hashing)
00416         {
00417                 for (int_t i = 0; i < nelem; ++ i)
00418                 {
00419                         if (tab (i) == e)
00420                                 return i;
00421                 }
00422                 tab [nelem ++] = e;
00423                 if (nelem >= StartHashingSize)
00424                 {
00425                         hashing = 1;
00426                         rehash ();
00427                 }
00428                 return (nelem - 1);
00429         }
00430 
00431         // rehash if there is very little free space in the hashing table
00432         if (hashsize - hashcleared < nelem + (nelem >> 1) + 19)
00433                 rehash ();
00434 
00435         // find the position of the element's number in the hashing table
00436         int_t addpos = -1;
00437         int_t pos = hashfind (e, &addpos);
00438 
00439         // if it alread was in the set, then just return its number
00440         if (hashtable (pos) >= 0)
00441                 return hashtable (pos);
00442 
00443         // add this element to the set and return its new number
00444         if (addpos >= 0)
00445                 pos = addpos;
00446         hashtable [pos] = nelem;
00447         tab [nelem] = e;
00448         return nelem ++;
00449 } /* hashedset<element>::add */
00450 
00451 template <class element>
00452 inline int_t hashedset<element>::push (const element &e)
00453 {
00454         return add (e);
00455 } /* hashedset<element>::push */
00456 
00457 template <class element>
00458 inline int_t hashedset<element>::push_back (const element &e)
00459 {
00460         return add (e);
00461 } /* hashedset<element>::push_back */
00462 
00463 template <class element>
00464 int hashedset<element>::remove (const element &e)
00465 {
00466         if (!hashing)
00467         {
00468                 for (int_t i = 0; i < nelem; ++ i)
00469                 {
00470                         if (tab (i) == e)
00471                         {
00472                                 tab [i] = tab (-- nelem);
00473                                 return 0;
00474                         }
00475                 }
00476                 return -1;
00477         }
00478 
00479         // find the position in the hashing table with this element's number
00480         int_t pos = hashfind (e);
00481 
00482         // if it was not there, then finish
00483         if (hashtable (pos) < 0)
00484                 return -1;
00485         int_t n = hashtable (pos);
00486 
00487         // update the hashing table and the number of elements in the set
00488         hashtable [pos] = -2;
00489         -- nelem;
00490         ++ hashcleared;
00491 
00492         // if it was not the last element in the set, move the last one
00493         // to the vacated place
00494         if (n != nelem)
00495         {
00496                 pos = hashfind (tab (nelem));
00497                 hashtable [pos] = n;
00498                 tab [n] = tab (nelem);
00499         }
00500 
00501         // if there are very few elements in the table, turn off hashing
00502         if (nelem < StartHashingSize / 2)
00503         {
00504                 hashing = 0;
00505         }
00506 
00507         // if there are very many cleared entries, then rehash
00508         else if (hashcleared > nelem + 19)
00509                 rehash ();
00510 
00511         return 0;
00512 } /* hashedset<element>::remove */
00513 
00514 template <class element>
00515 inline int hashedset<element>::removenum (int_t n)
00516 {
00517         if ((n < 0) || (n >= nelem))
00518                 return -1;
00519         if (!hashing)
00520         {
00521                 -- nelem;
00522                 if (n != nelem)
00523                         tab [n] = tab (nelem);
00524                 return 0;
00525         }
00526         return remove (tab (n));
00527 } /* hashedset<element>::removenum */
00528 
00529 template <class element>
00530 inline int_t hashedset<element>::pop ()
00531 {
00532         if (!nelem)
00533                 throw "Trying to remove an element from an empty set.";
00534         return removenum (nelem - 1);
00535 } /* hashedset<element>::pop */
00536 
00537 template <class element>
00538 hashedset<element> &hashedset<element>::add (const hashedset<element> &s)
00539 {
00540         int_t n = s. size ();
00541         for (int_t i = 0; i < n; ++ i)
00542                 add (s [i]);
00543         return *this;
00544 } /* hashedset<element>::add */
00545 
00546 template <class element>
00547 hashedset<element> &hashedset<element>::remove (const hashedset<element> &s)
00548 {
00549         if (this -> size () < s. size ())
00550         {
00551                 for (int_t i = 0; i < this -> size (); ++ i)
00552                 {
00553                         if (s. check ((*this) [i]))
00554                                 this -> removenum (i --);
00555                 }
00556         }
00557         else
00558         {
00559                 int_t n = s. size ();
00560                 for (int_t i = 0; i < n; ++ i)
00561                         remove (s [i]);
00562         }
00563         return *this;
00564 } /* hashedset<element>::remove */
00565 
00566 template <class element>
00567 inline bool hashedset<element>::empty () const
00568 {
00569         return !nelem;
00570 } /* hashedset<element>::empty */
00571 
00572 template <class element>
00573 inline int_t hashedset<element>::size () const
00574 {
00575         return nelem;
00576 } /* hashedset<element>::size */
00577 
00578 template <class element>
00579 inline void hashedset<element>::swap (hashedset<element> &other)
00580 {
00581         my_swap (stat, other. stat);
00582         my_swap (nelem, other. nelem);
00583         tab. swap (other. tab);
00584         my_swap (hashing, other. hashing);
00585         my_swap (hashsize, other. hashsize);
00586         my_swap (hashcleared, other. hashcleared);
00587         hashtable. swap (other. hashtable);
00588         return;
00589 } /* hashedset<element>::swap */
00590 
00591 template <class element>
00592 inline bool hashedset<element>::operator ==
00593         (const hashedset<element> &other) const
00594 {
00595         if (this -> nelem != other. nelem)
00596                 return false;
00597         for (int_t i = 0; i < nelem; ++ i)
00598         {
00599                 if (!other. check (this -> tab [i]))
00600                         return false;
00601         }
00602         return true;
00603 } /* hashedset<element>::swap */
00604 
00605 template <class element>
00606 inline void hashedset<element>::intersection (const hashedset<element> &s1,
00607         const hashedset<element> &s2)
00608 {
00609         int_t size1 = s1. size ();
00610         int_t size2 = s2. size ();
00611 
00612         if (size1 <= size2)
00613         {
00614                 for (int_t i = 0; i < size1; ++ i)
00615                 {
00616                         const element &elem = s1. tab [i];
00617                         if (s2. check (elem))
00618                                 this -> add (elem);
00619                 }
00620         }
00621         else
00622         {
00623                 for (int_t i = 0; i < size2; ++ i)
00624                 {
00625                         const element &elem = s2. tab [i];
00626                         if (s1. check (elem))
00627                                 this -> add (elem);
00628                 }
00629         }
00630         return;
00631 } /* hashedset<element>::intersection */
00632 
00633 template <class element>
00634 int_t hashedset<element>::hashfind (const element &e, int_t *addpos) const
00635 {
00636         if (!hashing)
00637                 throw "Hashing is turned off.";
00638 
00639         int_t key = hashkey1 (e);
00640         if (key < 0)
00641                 key = -(key + 1);
00642         int_t pos = key % hashsize;
00643         if (addpos)
00644                 *addpos = -1;
00645 
00646         // start updating hashing statistics
00647         if (stat)
00648                 ++ (stat -> hashhits);
00649 
00650         // find the position of the element in the hashing table
00651         int_t number;
00652         int_t add = 0;
00653         while ((number = hashtable (pos)) != -1)
00654         {
00655                 if ((number >= 0) && (e == tab (number)))
00656                         return (pos);
00657                 if (addpos && (*addpos < 0) && (number == -2))
00658                         *addpos = pos;
00659                 if (!add)
00660                 {
00661                         int_t key = hashkey2 (e);
00662                         if (key < 0)
00663                                 key = -(key + 1);
00664                         add = key % (hashsize - 1) + 1;
00665                 }
00666                 pos += add;
00667                 if (pos >= hashsize)
00668                         pos -= hashsize;
00669                 if (stat)
00670                         ++ (stat -> hashmisses);
00671         }
00672 
00673         // return the position located in the hashing table
00674         return (pos);
00675 
00676 } /* hashedset<element>::hashfind */
00677 
00678 template <class element>
00679 void hashedset<element>::rehash (int_t newsize)
00680 {
00681         if (stat)
00682                 ++ (stat -> rehashcount);
00683 
00684         // adjust the new size of the hashing table
00685         if ((newsize < (nelem << 1) + InitHashSize) ||
00686                 (newsize > (nelem << 2) + InitHashSize))
00687                 newsize = (nelem << 1) + nelem + InitHashSize;
00688 
00689         // DEBUG
00690 //      sbug << "(rehash: nelem=" << nelem <<
00691 //              ", hashsize=" << hashsize << ", newsize=" << newsize << ")\n";
00692 
00693         // check if it is not too large for 16-bit programs
00694         int_t x = 0xFFFF;
00695         if ((x < 0) && (newsize >= 16384))
00696                 throw "Set too large for this 16-bit program.";
00697 
00698         // free unused memory if desired
00699         if (newsize < hashsize)
00700         {
00701                 multitable<int_t> empty;
00702                 hashtable = empty;
00703         }
00704         
00705         // set the new value of the hashing table and re-buid it
00706         hashsize = hashedset<element>::rounduptoprime (newsize);
00707         hashcleared = 0;
00708 
00709         // build the entire hash table from the beginning
00710         hashtable. fill (-1, hashsize);
00711         for (int_t i = 0; i < nelem; ++ i)
00712         {
00713                 int_t pos = hashfind (tab (i));
00714                 if (hashtable (pos) != -1)
00715                         throw "A repeated element in a set!";
00716                 hashtable [pos] = i;
00717         }
00718 
00719         return;
00720 } /* hashedset<element>::rehash */
00721 
00722 template <class element>
00723 inline bool hashedset<element>::numberisprime (const int_t &n)
00724 {
00725         if (n < 2)
00726                 return 0;
00727 
00728         int_t i = 2;
00729         while (i * i <= n)
00730         {
00731                 if (!(n % i))
00732                         return false;
00733                 ++ i;
00734         }
00735 
00736         return true;
00737 } /* hashedset<element>::numberisprime */
00738 
00739 template <class element>
00740 int_t hashedset<element>::rounduptoprime (int_t n)
00741 {
00742         while (!hashedset<element>::numberisprime (n))
00743                 ++ n;
00744 
00745         return n;
00746 } /* hashedset<element>::rounduptoprime */
00747 
00748 
00749 // --------------------------------------------------
00750 
00755 #define SMALL_SIZE true
00756 
00762 #define LARGE_SIZE false
00763 
00767 template <class stream, class element>
00768 stream &write (stream &out, const hashedset<element> &s, bool size)
00769 {
00770         if (size == SMALL_SIZE)
00771         {
00772                 out << '{';
00773                 int_t n = s. size ();
00774                 for (int_t i = 0; i < n; ++ i)
00775                         out << (i ? " " : "") << s [i];
00776                 out << '}';
00777         }
00778         else
00779         {
00780                 int_t n = s. size ();
00781                 if (!s. empty ())
00782                 {
00783                         out << "; " << n << ((n == 1) ? " element." :
00784                                 " elements.") << '\n';
00785                 }
00786                 if (s. stat && s. stat -> hashhits)
00787                         out << ';' << *(s. stat) << '\n';
00788                 for (int_t i = 0; i < n; ++ i)
00789                         out << s [i] << '\n';
00790         }
00791         return out;
00792 } /* write */
00793 
00796 template <class element>
00797 std::ostream &operator << (std::ostream &out, const hashedset<element> &s)
00798 {
00799         return write (out, s, LARGE_SIZE);
00800 } /* operator << */
00801 
00804 template <class stream, class element>
00805 stream &read (stream &in, hashedset<element> &s, bool size)
00806 {
00807         // ignore all the comments at the beginning of the input stream
00808         ignorecomments (in);
00809 
00810         // determine the closing parenthesis
00811         // and read the opening one if applicable
00812         int closing = EOF;
00813         if (size == SMALL_SIZE)
00814         {
00815                 closing = readparenthesis (in);
00816                 if (closing == EOF)
00817                         throw "An opening parenthesis expected in a set.";
00818                 ignorecomments (in);
00819         }
00820 
00821         // read the elements until the closing parenthesis is found
00822         while (in. peek () != closing)
00823         {
00824                 element e;
00825                 in >> e;
00826         //      if (!in)
00827         //              throw "Failed to read an element of a set.";
00828                 s. add (e);
00829                 ignorecomments (in);
00830 
00831                 // read a comma between the elements if it is there
00832                 if (in. peek () == ',')
00833                 {
00834                         in. get ();
00835                         ignorecomments (in);
00836                 }
00837         }
00838 
00839         // read the closing parenthesis if any
00840         if (closing != EOF)
00841                 in. get ();
00842 
00843         return in;
00844 } /* read */
00845 
00848 template <class element>
00849 std::istream &operator >> (std::istream &in, hashedset<element> &s)
00850 {
00851         return read (in, s, LARGE_SIZE);
00852 } /* operator >> */
00853 
00855 template <class element>
00856 inline hashedset<element> &operator += (hashedset<element> &s,
00857         const hashedset<element> &u)
00858 {
00859         s. add (u);
00860         return s;
00861 } /* operator += */
00862 
00864 template <class element>
00865 inline hashedset<element> &operator -= (hashedset<element> &s,
00866         const hashedset<element> &u)
00867 {
00868         s. remove (u);
00869         return s;
00870 } /* operator -= */
00871 
00872 // --------------------------------------------------
00873 
00875 inline int_t hashkey1 (const unsigned long &number)
00876 {
00877         return static_cast<int_t> (number);
00878 } /* hashkey1 */
00879 
00881 inline int_t hashkey2 (const unsigned long &number)
00882 {
00883         return static_cast<int_t> (number ^ 0xFA5A75A7ul) << 8;
00884 } /* hashkey2 */
00885 
00890 #define DEFHASHKEYS(type) \
00891 inline int_t hashkey1 (const type &number) \
00892 { return hashkey1 (static_cast<const unsigned long> (number)); } \
00893 inline int_t hashkey2 (const type &number) \
00894 { return hashkey2 (static_cast<const unsigned long> (number)); }
00895 
00896 DEFHASHKEYS(unsigned int)
00897 DEFHASHKEYS(signed int)
00898 //DEFHASHKEYS(unsigned long)
00899 DEFHASHKEYS(signed long)
00900 DEFHASHKEYS(unsigned short)
00901 DEFHASHKEYS(signed short)
00902 DEFHASHKEYS(unsigned char)
00903 DEFHASHKEYS(signed char)
00904 
00905 #undef DEFHASHKEYS
00906 
00910 template <class T>
00911 inline int_t hashkey1 (const T &x)
00912 {
00913         return x. hashkey1 ();
00914 }
00915 
00919 template <class T>
00920 inline int_t hashkey2 (const T &x)
00921 {
00922         return x. hashkey2 ();
00923 }
00924 
00925 
00926 // --------------------------------------------------
00927 // ---------------- multivalued map -----------------
00928 // --------------------------------------------------
00929 
00937 template <class domelement, class imgelement>
00938 class mvmap
00939 {
00940 public:
00945         explicit mvmap (int bequiet = 1);
00946 
00948         ~mvmap ();
00949 
00951         const domelement &get (int_t n) const;
00952 
00954         const hashedset<domelement> &getdomain () const;
00955 
00958         const hashedset<imgelement> &operator () (int_t n) const;
00959 
00962         const hashedset<imgelement> &operator ()
00963                 (const domelement &x) const;
00964 
00966         hashedset<imgelement> &operator [] (int_t n);
00967 
00971         hashedset<imgelement> &operator [] (const domelement &x);
00972 
00974         int_t size () const;
00975 
00978         bool remove (const domelement &x);
00979 
00981         bool removenum (int_t n);
00982 
00984         void remove (const hashedset<domelement> &x);
00985 
00987         void swap (mvmap<domelement,imgelement> &other);
00988 
00992         int quiet;
00993 
00994 private:
00996         hashedset<domelement> domain;
00997 
01000         multitable<hashedset<imgelement> > images;
01001 
01002 }; /* class mvmap */
01003 
01004 // --------------------------------------------------
01005 
01006 template <class domelement, class imgelement>
01007 inline mvmap<domelement,imgelement>::mvmap (int bequiet):
01008         domain (0, bequiet), images ()
01009 {
01010         return;
01011 } /* mvmap::mvmap */
01012 
01013 template <class domelement, class imgelement>
01014 inline mvmap<domelement,imgelement>::~mvmap ()
01015 {
01016         return;
01017 } /* mvmap::~mvmap */
01018 
01019 template <class domelement, class imgelement>
01020 inline const domelement &mvmap<domelement,imgelement>::get (int_t n) const
01021 {
01022         if ((n < 0) || (n >= domain. size ()))
01023                 throw "Domain element number out of range.";
01024         return domain [n];
01025 } /* mvmap::get */
01026 
01027 template <class domelement, class imgelement>
01028 inline const hashedset<domelement> &
01029         mvmap<domelement,imgelement>::getdomain () const
01030 {
01031         return domain;
01032 } /* mvmap::getdomain */
01033 
01034 template <class domelement, class imgelement>
01035 inline const hashedset<imgelement>
01036         &mvmap<domelement,imgelement>::operator () (int_t n) const
01037 {
01038         if ((n < 0) || (n >= domain. size ()))
01039                 throw "Domain element number out of range.";
01040         return images (n);
01041 } /* mvmap::operator () */
01042 
01043 template <class domelement, class imgelement>
01044 inline const hashedset<imgelement>
01045         &mvmap<domelement,imgelement>::operator ()
01046         (const domelement &q) const
01047 {
01048         int_t n = domain. getnumber (q);
01049         if (n < 0)
01050                 throw "Element not in the domain.";
01051         return images (n);
01052 } /* mvmap::operator () */
01053 
01054 template <class domelement, class imgelement>
01055 inline hashedset<imgelement>
01056         &mvmap<domelement,imgelement>::operator [] (int_t n)
01057 {
01058         if ((n < 0) || (n >= domain. size ()))
01059                 throw "Domain element number out of range.";
01060         return images [n];
01061 } /* mvmap::operator [] */
01062 
01063 template <class domelement, class imgelement>
01064 inline hashedset<imgelement>
01065         &mvmap<domelement,imgelement>::operator []
01066         (const domelement &q)
01067 {
01068         int_t n = domain. add (q);
01069         return images [n];
01070 } /* mvmap::operator [] */
01071 
01072 template <class domelement, class imgelement>
01073 inline int_t mvmap<domelement,imgelement>::size () const
01074 {
01075         return domain. size ();
01076 } /* mvmap::size */
01077 
01078 template <class domelement, class imgelement>
01079 inline bool mvmap<domelement,imgelement>::removenum (int_t n)
01080 // WARNING: This procedure uses the specific way elements are removed from
01081 // a hashed set. If that way is changed, this procedure may not work anymore.
01082 {
01083         if ((n < 0) || (n >= domain. size ()))
01084                 return false;
01085         domain. removenum (n);
01086         if (n != domain. size ())
01087                 images [n] = images [domain. size ()];
01088         hashedset<imgelement> empty;
01089         images [domain. size ()] = empty;
01090         return true;
01091 } /* mvmap::removenum */
01092 
01093 template <class domelement, class imgelement>
01094 inline bool mvmap<domelement,imgelement>::remove (const domelement &x)
01095 {
01096         return removenum (domain. getnumber (x));
01097 } /* mvmap::remove */
01098 
01099 template <class domelement, class imgelement>
01100 inline void mvmap<domelement,imgelement>::remove
01101         (const hashedset<domelement> &x)
01102 {
01103         int_t n = x. size ();
01104         for (int_t i = 0; i < n; ++ i)
01105                 remove (x [i]);
01106         return;
01107 } /* mvmap::remove */
01108 
01109 template <class domelement, class imgelement>
01110 inline void mvmap<domelement,imgelement>::swap
01111         (mvmap<domelement,imgelement> &other)
01112 {
01113         domain. swap (other. domain);
01114         images. swap (other. images);
01115         return;
01116 } /* mvmap::swap */
01117 
01118 // --------------------------------------------------
01119 
01121 template <class domelement, class imgelement>
01122 hashedset<imgelement> &retrieveimage (const mvmap<domelement,imgelement> &m,
01123         hashedset<imgelement> &img)
01124 {
01125         int_t n = m. getdomain (). size ();
01126         for (int_t i = 0; i < n; ++ i)
01127                 img. add (m (i));
01128         return img;
01129 } /* retrieveimage */
01130 
01134 template <class domelement, class imgelement>
01135 hashedset<imgelement> &creategraph (const mvmap<domelement,imgelement> &m,
01136         hashedset<imgelement> &graph)
01137 {
01138         for (int_t i = 0; i < m. getdomain (). size (); ++ i)
01139         {
01140                 const domelement &e = m. get (i);
01141                 const hashedset<imgelement> &f = m (i);
01142                 int_t n = f. size ();
01143                 for (int_t j = 0; j < n; ++ j)
01144                         graph. add (e * f [j]);
01145         }
01146         return graph;
01147 } /* creategraph */
01148 
01149 // --------------------------------------------------
01150 
01152 template <class domelement, class imgelement>
01153 std::istream &readdomain (std::istream &in, hashedset<domelement> &dom,
01154         const mvmap<domelement,imgelement> &)
01155 {
01156         ignorecomments (in);
01157         while (in. peek () != EOF)
01158         {
01159                 domelement e;
01160                 in >> e;
01161         //      if (!in)
01162         //              throw "Failed to read a domain element of a map.";
01163                 dom. add (e);
01164 
01165                 // read the map's arrow
01166                 ignorecomments (in);
01167                 while (in. peek () == '-')
01168                         in. get ();
01169                 if (in. peek () == '>')
01170                         in. get ();
01171 
01172                 ignorecomments (in);
01173                 int closing = readparenthesis (in);
01174 
01175                 ignorecomments (in);
01176                 while (in. peek () != closing)
01177                 {
01178                         imgelement junk;
01179                         in >> junk;
01180                 //      if (!in)
01181                 //              throw "Failed to read an image element.";
01182                         ignorecomments (in);
01183                         if (in. peek () == ',')
01184                         {
01185                                 in. get ();
01186                                 ignorecomments (in);
01187                         }
01188                 }
01189 
01190                 if (closing != EOF)
01191                         in. get ();
01192                 ignorecomments (in);
01193         }
01194         return in;
01195 } /* readdomain */
01196 
01198 template <class domelement, class imgelement>
01199 std::istream &readimage (std::istream &in, hashedset<imgelement> &img,
01200         const mvmap<domelement,imgelement> &)
01201 {
01202         ignorecomments (in);
01203         while (in. peek () != EOF)
01204         {
01205                 domelement e;
01206                 in >> e;
01207         //      if (!in)
01208         //              throw "Failed to read a domain element of a map.";
01209 
01210                 // read the map's arrow
01211                 ignorecomments (in);
01212                 while (in. peek () == '-')
01213                         in. get ();
01214                 if (in. peek () == '>')
01215                         in. get ();
01216 
01217                 ignorecomments (in);
01218                 read (in, img, SMALL_SIZE);
01219 
01220                 ignorecomments (in);
01221         }
01222         return in;
01223 } /* readimage */
01224 
01226 template <class domelement, class imgelement>
01227 std::istream &readselective (std::istream &in, mvmap<domelement,imgelement> &m,
01228         const hashedset<domelement> &dom1, const hashedset<domelement> &dom2)
01229 {
01230         if (dom1. empty () && dom2. empty ())
01231         {
01232                 sout << "Warning: The domain of the map is empty.\n";
01233                 return in;
01234         }
01235 
01236         ignorecomments (in);
01237         while (in. peek () != EOF)
01238         {
01239                 domelement e;
01240                 in >> e;
01241         //      if (!in)
01242         //              throw "Failed to read a domain element of a map.";
01243 
01244                 // read the map's arrow
01245                 ignorecomments (in);
01246                 while (in. peek () == '-')
01247                         in. get ();
01248                 if (in. peek () == '>')
01249                         in. get ();
01250 
01251                 ignorecomments (in);
01252                 if (dom1. check (e) || dom2. check (e))
01253                         read (in, m [e], SMALL_SIZE);
01254                 else
01255                 {
01256                         int closing = readparenthesis (in);
01257         
01258                         ignorecomments (in);
01259                         while (in. peek () != closing)
01260                         {
01261                                 imgelement junk;
01262                                 in >> junk;
01263                         //      if (!in)
01264                         //              throw "Failed to read an img elem.";
01265                                 ignorecomments (in);
01266                                 if (in. peek () == ',')
01267                                 {
01268                                         in. get ();
01269                                         ignorecomments (in);
01270                                 }
01271                         }
01272         
01273                         if (closing != EOF)
01274                                 in. get ();
01275                 }
01276                 ignorecomments (in);
01277         }
01278         return in;
01279 } /* readselective */
01280 
01282 template <class domelement, class imgelement>
01283 std::istream &readrestriction (std::istream &in,
01284         mvmap<domelement,imgelement> &m, const hashedset<domelement> &dom,
01285         const hashedset<imgelement> &img)
01286 {
01287         if (dom. empty ())
01288         {
01289                 sout << "Warning: The domain of the map is empty.\n";
01290                 return in;
01291         }
01292 
01293         ignorecomments (in);
01294         while (in. peek () != EOF)
01295         {
01296                 domelement e;
01297                 in >> e;
01298         //      if (!in)
01299         //              throw "Failed to read a domain element of a map.";
01300 
01301                 // read the map's arrow
01302                 ignorecomments (in);
01303                 while (in. peek () == '-')
01304                         in. get ();
01305                 if (in. peek () == '>')
01306                         in. get ();
01307 
01308                 ignorecomments (in);
01309                 if (dom. check (e))
01310                 {
01311                         hashedset<imgelement> &y = m [e];
01312                         hashedset<domelement> x;
01313                         read (in, x, SMALL_SIZE);
01314                         int_t n = x. size ();
01315                         for (int_t i = 0; i < n; ++ i)
01316                         {
01317                                 if (img. check (x [i]))
01318                                         y. add (x [i]);
01319                         }
01320                 }
01321                 else
01322                 {
01323                         int closing = readparenthesis (in);
01324         
01325                         ignorecomments (in);
01326                         while (in. peek () != closing)
01327                         {
01328                                 imgelement junk;
01329                                 in >> junk;
01330                         //      if (!in)
01331                         //              throw "Failed to read an img elem.";
01332                                 ignorecomments (in);
01333                                 if (in. peek () == ',')
01334                                 {
01335                                         in. get ();
01336                                         ignorecomments (in);
01337                                 }
01338                         }
01339         
01340                         if (closing != EOF)
01341                                 in. get ();
01342                 }
01343                 ignorecomments (in);
01344         }
01345         return in;
01346 } /* readrestriction */
01347 
01349 template <class domelement, class imgelement>
01350 inline std::istream &readselective (std::istream &in,
01351         mvmap<domelement,imgelement> &m, const hashedset<domelement> &dom)
01352 {
01353         hashedset<domelement> empty;
01354         return readselective (in, m, dom, empty);
01355 } /* readselective */
01356 
01357 
01358 // --------------------------------------------------
01359 
01364 template <class domelement, class imgelement>
01365 std::ostream &operator << (std::ostream &out,
01366         const mvmap<domelement,imgelement> &m)
01367 {
01368         int_t n = m. getdomain (). size ();
01369         for (int_t i = 0; i < n; ++ i)
01370         {
01371                 out << m. get (i) << " -> ";
01372                 write (out, m (i), SMALL_SIZE) << '\n';
01373         }
01374         return out;
01375 } /* operator << */
01376 
01378 template <class domelement, class imgelement>
01379 std::istream &operator >> (std::istream &in, mvmap<domelement,imgelement> &m)
01380 {
01381         ignorecomments (in);
01382         while (in. peek () != EOF)
01383         {
01384                 domelement e;
01385                 in >> e;
01386         //      if (!in)
01387         //              throw "Failed to read a domain element of a map.";
01388 
01389                 // read the map's arrow
01390                 ignorecomments (in);
01391                 while (in. peek () == '-')
01392                         in. get ();
01393                 if (in. peek () == '>')
01394                         in. get ();
01395 
01396                 ignorecomments (in);
01397                 read (in, m [e], SMALL_SIZE);
01398 
01399                 ignorecomments (in);
01400         }
01401         return in;
01402 } /* operator >> */
01403 
01404 
01405 } // namespace homology
01406 } // namespace chomp
01407 
01408 #endif // _CHOMP_STRUCT_HASHSETS_H_
01409 
01411