The GroupIndex Template Library
Main Page | Class Hierarchy | Class List | File List | Class Members

GroupIndex.h

00001 #ifndef DEF_GROUPINDEX
00002 #define DEF_GROUPINDEX
00003 #pragma warning( disable : 4786 )        
00004 #pragma message("Compiling the GroupIndex template library...")
00005 #include "util.h"
00006 #include <cstdio>
00007 #include <cstdlib>
00008 #include <vector>
00009 #include <map>
00010 #include <set>
00011 #include <string>
00012 #ifdef VISUALC_INCLUDES
00013 #include <direct.h>
00014 #else
00015 #include <unistd.h>
00016 #include <mingw/stdlib.h>
00017 #endif
00018 //#include "DefaultGListCompression.h"
00019 
00020 
00518 namespace groupindex
00519 {
00520 
00563 // Wie schön, dass es Präprozessor gibt:
00564 // Damit können wir nämlich unter VisualC UND gcc (->ANSI) kompilieren!
00565 #ifdef VISUALC_INCLUDES
00566  #ifndef ANSI_BRACES
00567   #define ANSI_BRACES
00568  #endif
00569  #ifndef ANSI_TYPENAME
00570   #define ANSI_TYPENAME
00571  #endif
00572 #else
00573  #ifndef ANSI_BRACES
00574   #define ANSI_BRACES <>
00575  #endif
00576  #ifndef ANSI_TYPENAME
00577   #define ANSI_TYPENAME typename
00578  #endif
00579 #endif
00580 
00581 #include <iostream>
00582 #include <fstream>
00583 #include "DefaultRepresentation.h"
00584 
00585 
00586 #ifndef TIME
00587 #include <time.h>
00588 #define TIME
00589 #endif
00590 
00591 #ifdef set
00592 #undef set
00593 #endif
00594 #include <set>
00595 
00596 //--------------------------------
00597 #ifndef MISMATCHLIST
00598 #include "MismatchList.h"
00599 #endif
00600 //--------------------------------
00601 
00602 
00603 typedef std::map<std::string, int> NameToIndexMap;
00604 typedef NameToIndexMap::value_type NameToIndexEntry;
00605 
00606 typedef std::map<int, std::string> IndexToNameMap;
00607 typedef IndexToNameMap::value_type IndexToNameEntry;
00608 
00609 //**********************************************************************************
00610 //  Igitt - Makros!
00611 //**********************************************************************************
00612 
00613 #define min(a, b)  (((a) < (b)) ? (a) : (b))
00614 
00615 //**********************************************************************************
00616 
00617 // Zunächst einige Worte zum Geleit für die doxygen-Doku:
00618 /*
00619 \mainpageOUT Die GroupIndex - Template-Library
00620 
00621 \section introduction I. Einführung
00622 
00623 Das Indexierungssystem \c GroupIndex ist eine generische Programmierbibliothek zum
00624 Erstellen von inhaltsbasierten Indexierungssystemen.
00625 \c GroupIndex nutzt an vielen Stellen das Konzept der Templates der Programmierprache C++.
00626 Um mit Hilfe von \c GroupIndex Indexierungsysteme zu
00627 erstellen, ist es unumgänglich, gewisse zugrundeliegende Ideen zu kennen, 
00628 die in den folgenden Abschnitten erläutert werden.
00629 
00630 \section group_and_set_classes II. Gruppen- und Mengenklassen
00631 
00632 Eine zentrale Rolle im \c GroupIndex - System spielen die sogenannten
00633 \em Gruppenklassen und \em Mengenklassen. Wie die Benennungen dieser Klassen nahelegen,
00634 übernehmen die Instanzen dieser Klassen die Rolle von Elementen einer \em Gruppe resp. einer
00635 \em Menge - und zwar im mathematischen Sinne. Für jeden Index, der die \c GroupIndex - Template-Library
00636 verwendet, muss jeweils eine Gruppen- und eine Mengenklasse
00637 implementiert werden. Worin Rolle dieser Klassen genau besteht und wie sich dies
00638 in den jeweiligen Klassendeklarationen wiederspiegelt, soll im folgenden Abschnitt erläutert werden.
00639 
00640 \subsection from_structures_to_classes II.1 Von mathematischen Strukturen zu C++-Klassen
00641 
00642 Die Grundidee des \c GroupIndex - Systems besteht darin, dass mathematische Strukturen 
00643 in Form von Klassen der Programmiersprache C++ implementiert werden. Die Implementierung
00644 einer mathematischen Struktur soll nun anhand einer relativ simplen Struktur, nämlich
00645 einer \em Gruppe demonstriert werden. Eine Gruppe ist eine Menge \em G mit einer Verknüpfung * 
00646 : \em G x G -> G, wobei \em G und * gewisse \em Axiome erfüllen; so gilt für alle 
00647 Elemente \em a, \em b und \em c aus \em G
00648 \li * ist assoziativ, d.h. (\em a * \em b) * \em c = \em a * (\em b * \em c)
00649 \li Es existiert ein neutrales Element 1, d.h. 1 * \em a = \em a
00650 \li Zu jedem \em a existiert ein Inverses \em d mit \em a * \em d = 1.
00651 
00652 Diese Axiome lassen sich nun übertragen auf C++-Klassen. An die Stelle der Gruppe \em G
00653 rückt nun eine \em Gruppenklasse \c Group. Eine \em Instanz von \c Group entspricht
00654 dann einem \em Element von \em G . An Stelle der aus der Mathematik gewohnten
00655 Sprechweise "g sei Element von \em G " kann also in C++ geschreiben werden als
00656 
00657 \code 
00658  Group g;
00659 \endcode
00660 
00661 An die Stelle der Verknüpfung * der Gruppe \em G rückt ein C++-Operator:
00662 
00663 \code 
00664  Group operator*(const Group& a, const Group& b);
00665 \endcode
00666 
00667 Das geforderte inverse Element zu einem Gruppenelement \em g - das üblicherweise als
00668 \c g^(-1) geschrieben wird - lässt sich ebenfalls in einen Operator übertragen. So erhält
00669 man das Inverse zu einer Instanz der Gruppenklasse \c Group durch den unären Operator
00670 
00671 \code 
00672  Group& operator!(Group& g);
00673 \endcode
00674 
00675 Das neutrale Element lässt sich implementieren durch einen Zuweisungsoperator der Gestalt 
00676  \code 
00677  Group& Group::operator=(int i)
00678  {
00679    if (i==1)
00680        ...;
00681  }
00682 \endcode
00683 Damit erhält man das neutrale Element der Gruppe (bzw. "die neutrale Instanz" der Gruppenklasse) durch
00684 die Zuweisung
00685 \code 
00686  Group g;
00687  g = 1;
00688 \endcode
00689 
00690 
00691 Die übrigen Gruppenaxiome werden implizit erfüllt - durch eine korrekte Implementierung 
00692 der Operatoren.
00693 
00694 \subsection groupindex_group_class II.2 Gruppenklassen
00695 
00696 Eine Gruppenklasse für die \c GroupIndex - Klassen wird in Anlehnung an das im vorigen Abschnitt
00697 beschriebene Konzept implementiert; in einigen Details weicht das Konzept der Gruppenklasse
00698 von der zuvor beschriebenen Idee ab:
00699 \li An Stelle des \c operator*() wird der Operator \c Group::operator*=(const \c Group& \c g) verwendet.
00700 \li Der Invertierungsoperator \c Group::operator!() invertiert das \c this - Objekt und liefert
00701     das \c this - Objekt als Ergebnis zurück. Es wird also \em kein neues Objekt erzeugt,
00702     welches das Inverse enthält. Beispielsweise haben die folgenden Codezeilen zur Folge,
00703     dass \c g und \c h dasselbe Gruppenelement beinhalten:
00704     \code 
00705  Group g,h;
00706  ...
00707  h = !g;
00708     \endcode
00709     Um die Wirkung zu erzielen, dass \c g das Inverse von \c h enthält, kann der folgende
00710     Programmcode verwendet werden:
00711     \code 
00712  Group g,h;
00713  ...
00714  h = g;
00715  !h;
00716     \endcode
00717 \li Die Operatoren
00718 
00719 Da zur Anwendung der \c GroupIndex - Klassen immer eine Gruppe benötigt wird, die auf einer Menge operiert,
00720 muss auch die Struktur einer \em Gruppenoperation implementiert werden. Dazu benötigt die
00721 Gruppenklasse ein Überladen des *= - Operators:
00722 \code 
00723  Set& Group::operator*=(Set& s) const;
00724 \endcode
00725 Die Codezeilen
00726 \code
00727  Group g;
00728  Set s_1, s_2;
00729  ...
00730  s_2 = s_1;
00731  g *= s_2;
00732 \endcode
00733 haben dann im mathematischen Sinne die Bedeutung \em s_2 = \em g*s_1 , d.h. das Gruppenelement \em g
00734 operiert auf dem Mengenelement \em s_1.
00735 
00736 In Zusammenhang mit der Gruppenoperation benötigen die \c GroupIndex - Klassen auch eine
00737 Funktion zur \em Repräsentantenberechnung. Diese muss durch eine (im globalen namespace sichtbare) Funktion
00738 \code
00739  void getRepresentation(const Set& m, Group& g_m, Set& r_m);
00740 \endcode
00741 implementiert werden. Diese Methode liefert zur Eingabe \c m jeweils ein Gruppen- und ein 
00742 Mengenelement \c g_m bzw. \c r_m, so dass 
00743 \code
00744  m == (g_m *= r_m)
00745 \endcode
00746 gilt. \c r_m muss dabei aus Element eines Repräsentantensystems \em R - einer 
00747 geeigneten Teilmenge der \em G - Menge \em M - sein. 
00748 Algebraisch gesehen berechnet \c getRepresentation also ein Gruppenelement, welches
00749 ein beliebiges Mengenelement auf seinen Repräsentanten abbildet sowie den zugehörigen
00750 Repräsentanten:
00751 
00752  \em m = \em g_m \em r_m
00753 
00754 Für die algebraischen Einzelheiten sei hier auf die entsprechende Literatur verwiesen.
00755 
00756 Zusätzlich zu den mathematisch relevanten Operatoren und Funktionen benötigt die Gruppenklasse noch einige
00757 programmiertechnisch notwendigen Funktionen:
00758 \li Konstruktoren und Destruktor
00759 \li Stream-Operatoren \c operator<<() und \c operator>>() zum Lesen und Schreiben in Dateien
00760 \li die Vergleichsoperatoren \c operator==() \c operator!=() (siehe dazu auch nachfolgende 
00761 Bemerkung zu Vergleichsoperatoren)
00762 \li durch den Operator 
00763 \code 
00764  bool operator<(const Group& g, const Group& h)
00765 \endcode
00766 muss eine totale Ordnung auf den Instanzen der Gruppenklasse implementiert sein.
00767 \li die Methode 
00768 \code 
00769  int Group::size(); \endcode
00770 gibt an, weiviele Bytes vom \c operator<<() in einen \c ofstream geschriben werden.
00771 Falls alle Instanzen der Klasse gleich viel Platz belegen, kann diese Methode
00772 auch als \c static implementiert werden.
00773 
00774 Eine vollständige Deklaration einer abstrakten Gruppenklasse folgt im übernächsten Abschnitt;
00775 zunächst werden die Funktionen der Mengenklasse näher beschrieben.
00776 
00777 \em Bemerkungen \em zu \em Vergleichsoperatoren \c operator==() \em und \c operator!=()
00778 
00779 Die Vergleichsoperatoren \c operator==() \c operator!=() müssen \em beide implementiert werden,
00780 da sie zu Vergleichen in unterschiedlichen Situationen verwendet werden:
00781 Der \c operator==() wird beim Indexaufbau verwendet und sollte die angegebenen Objekte auf exakte Gleichheit prüfen. Der
00782 \c operator!=() hingegen wird bei der Suche verwendet; bei Bedarf kann der Ungleich-Operator 
00783 auch dann ein \c false zurückliefern, wenn die beiden zu vergleichenden Objekte
00784 ähnlich -- aber nicht exakt gleich -- sind. Dadurch wird eine einfache Form der Fehlertoleranz erlaubt;
00785 allerdings verliert die Suche u.U. wichtige Eigenschaften, so z.B. die Assoziativität
00786 der Schnittmengenbildung. Die naheliegenste Form, den \c operator!=() zu implementieren ist
00787 natürlich ein 
00788 \code
00789 bool myGroup::operator!=(const myGroup& cmp)
00790 {
00791    return !((*this)==g2);
00792 }
00793 \endcode
00794 sofern nicht die oben erwähnte Form der Fehlertoleranz bei der Suche
00795 gewünscht ist.
00796 
00797 \subsection groupindex_set_class II.3 Mengenklassen
00798 
00799 Die Instanzen einer Menge benötigen in den \c GroupIndex - Klassen keine weiteren 
00800 Funktion im mathematischen Sinne - die Gruppenoperation und die Repräsentanenberechnung
00801 werden bereits ausserhalb der Mengenklasse implementiert.
00802 
00803 Es verbleiben die programmiertechnisch notwendigen Methoden, die in einer Mengenklasse zu
00804 implementieren sind. Dazu gehören - fast identisch mit den Funktionen der Gruppenklasse:
00805 \li Konstruktoren und Destruktor
00806 \li Stream-Operatoren \c operator<<() und \c operator>>() zum Lesen und Schreiben in Dateien
00807 \li ein Vergleichsoperator \c operator==()
00808 \li durch den Operator 
00809 \code 
00810  bool operator<(const Group& g, const Group& h)
00811 \endcode
00812 muss eine totale Ordnung auf den Instanzen der Gruppenklasse implementiert sein. Es sei angemerkt, dass
00813 es hinreichend ist, wenn die durch diesen Operator gegebene Ordnung auf den Repräsentanten, die von
00814 \c getRepresentation() berechnet werden, eine totale Ordnung ist.
00815 \li die Methode 
00816 \code 
00817  int Set::size(); \endcode
00818 gibt an, wieviele Bytes vom \c operator<<() in einen \c ofstream geschrieben werden.
00819 Falls alle Instanzen der Klasse gleich viel Platz belegen, kann diese Methode
00820 auch als \c static implementiert werden.
00821 
00822 In den meisten Fällen wird es sinnvoll sein, die zur Mengenklasse gehörige Gruppenklasse als \c friend
00823 zu deklarieren.
00824 
00825 \subsection abstract_goup_and_set_class II.4 Abstrakte Klassen für Gruppen- und Mengenklassen
00826 
00827 Die folgenden Klassendeklarationen sind abstrakte Musterklassen für Gruppen- und 
00828 Mengenklassen. Es ist theoretisch möglich, durch Ableiten von den Klassen \c AbstractGroup 
00829 und \c AbstractSet und Implementieren der virtuellen Methoden konkrete Gruppen- und 
00830 Mengenklassen zu erstellen. Es empfiehlt sich aber, \em nicht von diesen Klassen abzuleiten 
00831 und von der Verwendung virtueller Methoden abzusehen, da deren Verwendung mit 
00832 Effizienzeinbußen verbunden ist.
00833 
00834 Statt dessen können Gruppen- und Mengenklasse als Basisklassen implementiert werden, 
00835 und zwar so,
00836 dass alle hier beschriebenen Methoden und Operatoren in diesen Klassen 
00837 (möglichst nicht-virtuell) implementiert sind.
00838 Unter Umständen lohnt es sich sogar, die Verknüpfungen der Gruppe und der Gruppenoperation
00839 \c inline zu deklarieren.
00840 
00841 \code
00842  class AbstractGroup
00843  {
00844  public:
00845 
00846     virtual bool operator==(Group&);
00847     virtual bool operator!=(Group&);
00848     virtual bool operator<(Group&);
00849 
00850     friend std::ofstream& operator<<(std::ofstream&, const Group&);
00851     friend std::ifstream& operator>>(std::ifstream&, const Group&);
00852 
00853     virtual Group();
00854     virtual Group(const Group&);
00855     virtual ~Group();
00856 
00857     virtual int size();
00858         
00859     virtual Group& operator!();
00860     virtual Group& operator*=(Group&);
00861     virtual Set& operator*=(Set&);
00862       
00863  };
00864 
00865 \endcode
00866 
00867 \code
00868  class AbstractSet
00869  {
00870 
00871  friend class AbstractGroup;
00872 
00873  public:
00874 
00875     virtual bool operator==(Set&);
00876     virtual bool operator<(Set&);
00877 
00878     friend std::ofstream& operator<<(std::ofstream&, const Set&);
00879     friend std::ifstream& operator>>(std::ifstream&, const Set&);
00880 
00881     virtual Set();
00882     virtual Set(const Set&);
00883     virtual ~Set();
00884 
00885     virtual int size();
00886         
00887  };
00888 
00889 \endcode
00890 
00891 \section how_to_implement III. Vorgehensweise zum Implementieren eines Index
00892 
00893 Um ein Indexierungssystem mit der \c GroupIndex - Template-Library zu erstellen, sind
00894 i.A. vier Schritte notwendig:
00895 <ol>
00896 <li> Identifizieren der Gruppenoperation, die dem zu erstellenden Index zugrunde liegt,
00897 <li> Implementieren der entsprechenden Gruppen- und Mengenklasse,
00898 <li> Auswahl geeigneter Container-Klassen
00899 <li> Auswahl geeigneter Klassen für Repräsentantensystem und für invertierte Listen.
00900 </ol>
00901 
00902 \subsection index_impl_subsect1 III.1 Identifizieren der Gruppenoperation
00903 Eine Erläterung des erstgenannten Punktes liegt "beyond the scope" dieser Dokumentation
00904 (die sich auf programmiertechnische Aspekte beschränkt). 
00905 
00906 
00907 \subsection index_impl_subsect2 III.2 Implementieren von Gruppen- und Mengenklasse
00908 Ist die Menge mit der darauf operierenden Gruppe identifiziert, so sind für den
00909 entsprechenden Index genau zwei Klassen
00910 zu implementieren: eine Gruppen- und eine Mengenklasse, die wie im vorigen Abschnitt
00911 erläutert implementiert werden müssen. Ist die der Mengenklasse zugrundeliegende Menge
00912 nicht diskret, so ist evtl. eine geeignete Diskretisierung zu wählen; bei nicht-diskreten 
00913 Gruppen empfiehlt es sich u.U. unscharfe Schnittmengenbildung zu verwenden. Dies erfordert bei der 
00914 Implementierung zusätzlich einen Index-Operator für die Gruppenklasse (mehr dazu inder 
00915 Dokumentation der Klasse \c groupindex::IntervalIntersectionGList ). Bei der Implementierung
00916 von \c getRepresentation() gilt es zu beachten, dass ggf. Container mit den benötigten
00917 Eigenschaften zum Speichern von (Fuzzy-) Repräsentanten und Stabilisator verwendet werden; 
00918 Eine nähere Beschreibung dieser Container folgt im nächsten Abschnitt.
00919 
00920 \subsection index_impl_subsect3 III.3 Auswahl von Container-Klassen
00921 Die vom \c GroupIndex verwendeten Container werden in gesonderten Klassen deklariert:
00922 Alle Container, die Mengenelemente enthalten, werden in einer Mengen-Container-Klasse
00923 deklariert, und alle Container, die Gruppenelemente enthalten, werden in einer Gruppen-Container-Klasse
00924 deklariert. Diese beiden Klassen - Mengen-Container-Klasse und Gruppen-Container-Klasse - werden
00925 der Klasse \c groupindex::GroupIndex als Template-Parameter übergeben.
00926 Folgende Eigenschaften der zugrundeliegenden Gruppenoperation bzw. Anforderungen
00927 an den zu erstellenden Index erfordern spezielle Container-Klassen:
00928 
00929   \li Bei nicht-regulären Gruppenoperationen besteht der Stabilisator aus mehreren Elementen. 
00930   Deshalb muss ein Gruppen-Container verwendet werden, welcher mehrere Gruppenelemente verwaltet. Es empfiehlt sich, die
00931   Klasse
00932   \code
00933  groupindex::nonregular_group_container<Group, GList>
00934   \endcode
00935   zu verwenden.Die Methode \c getRepresentation muss dann folgende Parameter verwenden:
00936 \code
00937  void getRepresentation(const Set& m, std::list<Group>& g_m, Set& r_m);
00938 \endcode
00939 
00940   \li Zur Fuzzy-Suche wird nicht \em ein Repräsentant berechnet, sondern eine Menge von Repräsentanten.
00941   Dies erfordert einen Mengen-Container, welcher einen geeigneter Container zur Verfügung stellt. Dazu
00942   gibt es die Template Klasse
00943   \code
00944  groupindex::fuzzy_set_container<Group, GList>
00945   \endcode
00946 Auch die Fuzzy-Suche erfordert eine Anpassung der Parameter von \c getRepresentation :
00947 \code
00948  void getRepresentation(const Set& m, Group& g_m, std::list<Set>& r_m);
00949 \endcode
00950 
00951 \li Die Kombination aus Fuzzy-Suche und nicht-regulären Gruppenoperationen ist ebenfalls zulässig, indem
00952 sowohl \c fuzzy_set_container als auch \c nonregular_group_container verwendet werden.
00953 \c getRepresentation verwendet dann die Parameter
00954 \code
00955  void getRepresentation(const Set& m, std::list<Group>& g_m, std::list<Set>& r_m);
00956 \endcode
00957 
00958 \subsection index_impl_subsect4 III.4 Auswahl von Klassen für Repräsentantensystem und für invertierte Listen
00959 Abhängig von den Eigenschaften der Gruppenoperation sollten unterschiedliche Klassen
00960 zum Verwalten invertierter Listen verwendet werden (zur Verwaltung von Repräsentanten
00961 existiert z.Z. nur die Klasse \c groupindex::DefaultRepresentation). 
00962 Für invertierte Liste stehen folgende Klassen zur Verfügung:
00963 \li \c groupindex::GInvertedList<Group> für exakte Schnittmengenbildung,
00964 \li \c groupindex::IntervalIntersectionGList<Group, numeric, Dim> für unscharfe Schnittmengenbildung sowie
00965 \li \c groupindex::CompressedGInvertedList<Group> (für komprimierte Indexe bei Gruppen, deren Verknüpfung die zur Indexierung 
00966 verwendete Ordnung der Gruppenelemente erhält. In der aktuellen Version ist dieser Listentyp nicht funktionsfähig.)
00967 
00968 Alle Listentypen unterstützen Fuzzy- und Mismatch-Suche. Bei der \c groupindex::IntervalIntersectionGList müssen neben der 
00969 Gruppenklasse zusätzlich noch die Template-Parameter \c numeric und \c Dim angegeben werden. Deren Bedeutung liegt 
00970 darin, dass die Gruppenklasse den Index-Operator \c operator[] mit Rückgabetyp \c numeric überlädt, um die Gruppe in einen
00971 geeigneten (kontinuierlichen) Vektorraum einzubetten:
00972 \code
00973  numeric Group::operator[](int)
00974 \endcode
00975 Jedes Gruppenelement \c g liefert also für \c g[0],g[1],...g[Dim-1] einen Wert vom Typ numeric.
00976 Der Typ \c numeric muss volle Artihmetik unterstützen, d.h. Addition, Subtraktion, Multiplikation und Division.
00977 Oft genügt ein Typ vom Wert \c double oder \c float , denkbar ist aber auch, den Typ 
00978 \c real aus der Bibliothek Leda zu verwenden. Weitere Details und Bedingnungen an die Gruppenklasse finden sich in der 
00979 Dokumentation der \c IntervalIntersectionGList .
00980 
00981 \section intro_examples IV. Beispiele
00982 \warning Beispiele z.T. noch nicht getestet! -am 17.12.2001
00983 
00984 In diesem Abschnitt werden einige Beispiele für die Auswahl von Containern und Listenklassen zur Umsetzung
00985 eines Indexierungsystems gegeben. Es werden lediglich die C++-Typdeklarationen angegeben, keine detaillierten
00986 Implementierungen der Gruppen- und Mengenklassen. Gruppen- bzw. Mengenklasse werden stets als \c myGroup bzw.
00987 \c mySet angegeben.
00988 
00989 Alle \c typedefs bis auf die Deklaration des Typs \c myIndex sind lediglich Hilfsdeklarationen, um
00990 die Definitionen übersichtlicher zu gestalten. Zum weiteren Gebrauch im Indexierungssystem
00991 werden ausschließlich Instanzen der Klasse \c myIndex benötigt.
00992 
00993 \subsection example1 IV.1 Beispiel 1: Reguläre Gruppenoperation ohne Fuzzy-Suche mit exakter Schnittmengenberechnung
00994 
00995 \code
00996  typedef GInvertedList < myGroup  > myGList;
00997  typedef DefaultRepresentation < 
00998             mySet, 
00999             myGroup, 
01000             myGList 
01001          > myRepresentation;
01002  typedef GroupIndex <
01003             mySet, 
01004             myGroup, 
01005             myRepresentation, 
01006             myGList 
01007          > myIndex;
01008 \endcode
01009 
01010 \subsection example2 IV.2 Beispiel 2: Reguläre Gruppenoperation ohne Fuzzy-Suche mit unscharfer Schnittmengenberechnung
01011 
01012 \code
01013  typedef IntervalIntersectionGList < myGroup , 7 , double > myGList;
01014  typedef DefaultRepresentation <
01015             mySet, 
01016             myGroup, 
01017             myGList 
01018          > myRepresentation;
01019  typedef GroupIndex <
01020             mySet, 
01021             myGroup, 
01022             myRepresentation, 
01023             myGList 
01024          > myIndex;
01025 \endcode
01026 
01027 \subsection example3 IV.3 Beispiel 3: Nicht-reguläre Gruppenoperation ohne Fuzzy-Suche mit unscharfer Schnittmengenberechnung
01028 
01029 \code
01030  typedef nonregular_group_container < myGroup > my_group_container;
01031  typedef default_set_container < mySet > my_set_container;
01032  typedef IntervalIntersectionGList < myGroup , 7 , double > myGList;
01033  typedef DefaultRepresentation <
01034             mySet, 
01035             myGroup, 
01036             myGList, 
01037             my_group_container, 
01038             my_set_container 
01039          > myRepresentation;
01040  typedef GroupIndex < 
01041             mySet, 
01042             myGroup, 
01043             myRepresentation, 
01044             myGList,
01045             my_group_container, 
01046             my_set_container 
01047          > myIndex;
01048 \endcode
01049 
01050 \subsection example4 IV.4 Beispiel 4: Nicht-reguläre Gruppenoperation mit Fuzzy-Suche mit unscharfer Schnittmengenberechnung
01051 
01052 \code
01053  typedef nonregular_group_container < myGroup > my_group_container;
01054  typedef fuzzy_set_container < mySet > my_set_container;
01055  typedef IntervalIntersectionGList < myGroup , 7 , double > myGList;
01056  typedef DefaultRepresentation <
01057             mySet, 
01058             myGroup, 
01059             myGList, 
01060             my_group_container, 
01061             my_set_container 
01062          > myRepresentation;
01063  typedef GroupIndex < 
01064             mySet, 
01065             myGroup, 
01066             myRepresentation, 
01067             myGList,
01068             my_group_container, 
01069             my_set_container 
01070          > myIndex;
01071 \endcode
01072 
01073 \section intro_commandline V. Erzeugen simpler Benutzer-Schnittstellen mit Hilfe der Template-Klasse IndexCommandLine
01074 
01075 Die Template-Klassen für Repräasentantensystem, invertierte Listen und Indexe stellen
01076 lediglich ein Index-Objekt zur Verfügung, mit dem durch Aufruf der Methoden eines 
01077 Index-Objektes die Funktionen eines Indexierungssystems (Einfügen, Suchen und Löschen)
01078 ausgeführt werden können. Um diese Funktionen auch einem Benutzer zur Verfügung zu stellen,
01079 ohne die C++-Schnittstellen verwenden zu müssen, gibt es die Template-Klasse \c IndexCommandLine.
01080 Diese erzeugt für eine fertige Indexklasse aus einem anzugebenen Interface zum Einlesen
01081 von Daten ein kleines Kommandozeilen-Tool, mit dem die Funktionen eines Index per
01082 Tastatureingabe einiger primitiver Befehle (z.B. ADD, REMOVE oder SEARCH) gesteuert 
01083 werden können.
01084 
01085 Eine genaue Beschreibung liegt in der Dokumentation zur Klasse \c groupindex::IndexCommandLine vor.
01086 
01087 */
01088 
01092 namespace groupindex
01093 {
01094 
01134 template 
01135  <class Set,                  // Klasse für Elemente der Menge M'  
01136   class Group,                // Klasse für Elemente der Gruppe G  
01137   class Representation = DefaultRepresentation<Set, Group>,   // Klasse fuer Elemente aus dem Repraesentantensystem R'
01138   class GList = GInvertedList<Group>,
01139   class GroupContainers = default_group_container<Group, GList>,    // Diese Klasse enthält typedefs für Iteratoren, die für Gruppenelemente bzw. G-inverteirte Listen zu verwenden sind
01140   class SetContainers = default_set_container<Set>       // Diese Klasse enthält typedefs für Iteratoren, die für Mengenelemente zu verwenden sind
01141   >
01142 
01143 class GroupIndex
01144 {
01145 
01146 private:
01147 
01149     NameToIndexMap nameToIndexMap;              
01151     IndexToNameMap indexToNameMap;              
01152 
01156     int maxFileIndex;                                   
01157 
01159     clock_t insertion_time;
01160         
01161 public:
01162 
01163     typedef Group IndexGroup;
01164     typedef Set IndexSet;
01165     typedef Representation IndexRepresentation;
01166 
01168         Representation representation;
01169         
01171         time_t start;
01172 
01174         time_t finish;
01175 
01184     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01185     std::string getFileName(int fileindex)
01186     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01187         {
01188                 IndexToNameMap::iterator it;
01189                 it = indexToNameMap.find(fileindex);
01190                 if (it != indexToNameMap.end())
01191                         return indexToNameMap[fileindex];
01192                 else
01193                 {
01194                         throw IndexingException(IndexingException::UNKNOWN_FILEINDEX);
01195                         return std::string(); // leeren String zurückliefern.
01196                 }
01197         }
01198 
01203     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01204         std::string getUniqueFileName(std::string& filename)
01205     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01206         {
01207                 if (!hasFileIndex(filename))
01208                         return filename;
01209                 
01210                 int i=0;
01211                 char buffer[20];
01212 
01213                 while (true)
01214                 {
01215                         
01216                         std::string ufilename = filename;
01217                         my_itoa(i,buffer,10);
01218                         ufilename.append("_");
01219                         ufilename.append(buffer);
01220                         if (!hasFileIndex(ufilename))
01221                                 return ufilename;
01222 
01223                 }
01224         }
01225 
01227     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01228         bool hasFileIndex(const std::string& filename)
01229     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01230         {
01231                 NameToIndexMap::iterator it;
01232                 it = nameToIndexMap.find(filename);
01233                 if (it == nameToIndexMap.end())
01234                         return false;
01235                 else
01236                         return true;
01237         }
01238 
01239 
01248     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01249         int getFileIndex(std::string filename)
01250     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01251         // liefert den zu filename gemappten index zurück.
01252         // bestizt filename keinen index, so wird ein neuer angelegt.
01253         {
01254                 NameToIndexMap::iterator it;
01255                 it = nameToIndexMap.find(filename);
01256                 if (it != nameToIndexMap.end())
01257                         return nameToIndexMap[filename];
01258                 else
01259                         return createNewFileMapping(filename);
01260         }
01261 
01262 private:
01275     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01276         int createNewFileMapping(std::string filename)
01277     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01278         {
01279 
01280                 if (filename.empty())
01281                         return -1;
01282 
01283                 int fileindex = maxFileIndex;
01284                 maxFileIndex++;
01285 
01286                 nameToIndexMap.insert(NameToIndexEntry(filename, fileindex));
01287                 indexToNameMap.insert(IndexToNameEntry(fileindex, filename));
01288 
01289                 return fileindex;
01290         }
01291           
01292 public:
01297     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01298         GroupIndex(Representation sr)
01299     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01300         {
01301                 representation = sr;
01302         init();
01303         };
01304 
01306     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01307         GroupIndex()
01308     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01309         {
01310                 representation = Representation();
01311         init();
01312         };
01313   
01315     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01316         ~GroupIndex()
01317     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01318         {
01319 
01320                 clear();
01321         
01322         }
01323 
01328     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01329         void clear()
01330     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01331         {
01332                 indexToNameMap.clear();
01333                 nameToIndexMap.clear();
01334                 representation.clear();
01335         }
01336 
01337 private:
01338 
01345     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01346         virtual void initFileRead(char* filename)
01347     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01348         {
01349         std::cout<<"initFileRead\n";
01350                 std::/*i*/fstream ifs;
01351         ifs.open(filename,std::ios::binary);
01352                 
01353                 if (!ifs)
01354                 {
01355                         throw IndexingException(IndexingException::FILE_ERROR_OPEN);
01356                 }
01357 
01358                 initFileRead(ifs);
01359 
01360         }
01361 
01362 public:
01363 
01370     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01371         GroupIndex(Representation& rep, const char* filename)
01372     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01373         {
01374         std::/*i*/fstream ifs;
01375         ifs.open(filename,std::ios::in | std::ios::binary);
01376         representation = rep;
01377         initFileRead(ifs);
01378     }
01379 
01387     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01388     GroupIndex(Representation rep, std::/*i*/fstream& ifs) 
01389     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01390         {
01391         representation = rep;
01392         initFileRead(ifs);
01393     }
01394 
01402     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01403         //void initFileRead(ifstream ifs)
01404     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01405         //{
01406     //    initFileRead(fdopen(ifs.fd(),"rb"));
01407     //}
01408 
01409 private:    
01417     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01418         void initFileRead(std::/*i*/fstream& ifs)
01419     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01420         {
01421 
01422         ifs.seekg(0,std::ios::beg);
01423         ifs.seekp(0,std::ios::beg);
01424 
01425 
01426         // BEGIN DEBUG
01427         long ffpos = ifs.tellg();
01428         // END DEBUG
01429 
01430         if (!ifs || ifs.eof())
01431         {
01432             nameToIndexMap.clear();
01433             indexToNameMap.clear();
01434             return;
01435         }
01436 
01437 
01438                 char c_null = '\0';
01439                 char buffer[2048];
01440                 maxFileIndex = 0;
01441 
01442                 // Anzahl der Files lesen
01443                 int filecount;
01444         // BEGIN DEBUG
01445         ffpos = ifs.tellg();
01446         // END DEBUG
01447                 ifs.read((char*)&filecount, sizeof(int));
01448         // BEGIN DEBUG
01449         ffpos = ifs.tellg();
01450         // END DEBUG
01451         if (!ifs || ifs.eof())
01452         {
01453             nameToIndexMap.clear();
01454             indexToNameMap.clear();
01455             return;
01456         }
01457           
01458                 for (int i=0; i<filecount; i++)
01459                 {
01460                         // fileindex lesen
01461                         int fileindex;
01462             // BEGIN DEBUG
01463             ffpos = ifs.tellg();
01464             // END DEBUG
01465                         ifs.read((char*)&fileindex, sizeof(int));
01466             // BEGIN DEBUG
01467             ffpos = ifs.tellg();
01468             // END DEBUG
01469             int i=0;
01470             do ifs.read(&buffer[i],1); while (buffer[i++]!=0);
01471         
01472                         std::string filename = std::string(buffer);
01473 
01474                         // (fileindex, filename)-Tupel anlegen
01475                         nameToIndexMap.insert(NameToIndexEntry(filename, fileindex));
01476                         indexToNameMap.insert(IndexToNameEntry(fileindex, filename));
01477 
01478                         if (fileindex>maxFileIndex)
01479                                 maxFileIndex = fileindex;
01480                 }
01481 
01482         // BEGIN DEBUG
01483         ffpos = ifs.tellg();
01484         // END DEBUG
01485 
01486         // G-Listen zum Lesen vorbereiten
01487                 if (filecount>0)
01488                 {
01489                         ifs>>representation;
01490                         maxFileIndex++;
01491                 }
01492 
01493 
01494     }
01495 
01496 public:
01504     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01505         GroupIndex(std::/*i*/fstream& ifs)
01506     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01507         {
01508         initFileRead(ifs);
01509         };
01510 
01512     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01513         void init()
01514     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01515         {
01516                 
01517             insertion_time = 0;                 
01518                 maxFileIndex = 0;
01519                 representation.init();
01520                 
01521         };
01522 
01523     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01524         friend std::ofstream& operator<< (std::ofstream& o, GroupIndex& idx)
01525     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01526         {
01527                 
01528                 idx.writeToFile(o);
01529         return o;
01530         }
01531 
01532 private:        
01542     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01543         void writeToFile(std::ofstream& o)
01544     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01545         {
01546                 
01547                 char c_null = '\0';
01548                 // fileindex<->filename - Map in Datei schreiben
01549 
01550                 // Anzahl der Dateien schreiben
01551                 int filecount = nameToIndexMap.size();
01552 
01553                 o.write((char*)&filecount, sizeof(int));
01554 
01555                 NameToIndexMap::iterator it = nameToIndexMap.begin();
01556 
01557                 while (it!=nameToIndexMap.end())
01558                 {
01559                         std::string fname = (*it).first;
01560                         int findex = (*it).second;
01561 
01562                         // fname und findex in stream schreiben
01563                         o.write((char*)&findex, sizeof(int));
01564                         int flen = fname.size();
01565                         o.write((char*)fname.c_str(), flen+1);
01566 
01567                         ++it;
01568                 }
01569           
01570                 // G-Listen in Datei schreiben
01571                 o<<representation;
01572                 
01573                 finish = clock();
01574                 insertion_time += (finish-start);
01575                 
01576                 #ifndef CHURCHILL // wenn CHURCHILL definiert ist, wird keine Statistik erzeugt
01577                 FILE* stat_stream;
01578                 stat_stream = fopen("groupindex.log","w");
01579                 if (stat_stream!=NULL)
01580                 {
01581                         writeStatistics(stat_stream);
01582                         fclose(stat_stream);
01583                 }
01584 
01585                 #endif
01586 
01587         };
01588 
01589 public:
01593     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01594         void writeStatistics(FILE* stream)
01595     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01596         {
01597                 double total_time = ((double)(1000.0*insertion_time)) / CLOCKS_PER_SEC;
01598                 fprintf(stream,"Gesamtzeit zum Indexieren ohne Einlesen der Daten: %f secs\n",total_time/1000.0);
01599                 representation.writeStatistics(stream);
01600         }
01601         
01602 
01615     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01616         void renameFile(std::string old_filename, std::string new_filename)
01617     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01618         {
01619 
01620                 if (!hasFileIndex(old_filename)) 
01621                 {
01622                         throw IndexingException(IndexingException::NO_SUCH_FILE);
01623                 }
01624 
01625                 if (hasFileIndex(new_filename))
01626                 {
01627                         throw IndexingException(IndexingException::FILE_ALREADY_EXISTS);
01628                 }
01629 
01630                 int findex = getFileIndex(old_filename);
01631 
01632                 indexToNameMap.erase(findex);
01633                 nameToIndexMap.erase(old_filename);
01634 
01635                 nameToIndexMap[new_filename] = findex;
01636                 indexToNameMap[findex] = new_filename;  
01637                 
01638         }
01639 
01645     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01646         void remove(std::string& filename)
01647     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01648         {
01649                 // filename aus der Zuordnung filename <-> fileindex herausnehmen
01650                 
01651                 int fileindex = getFileIndex(filename);
01652                 
01653                 IndexToNameMap::iterator iit;
01654                 iit = indexToNameMap.find(fileindex);
01655                 if (iit != indexToNameMap.end())
01656                         indexToNameMap.erase(iit);
01657 
01658                 NameToIndexMap::iterator nit;
01659                 nit = nameToIndexMap.find(filename);
01660                 if (nit != nameToIndexMap.end())
01661                         nameToIndexMap.erase(nit);
01662 
01663                 // fileindex aus allen G-invertierten Listen herausnehmen
01664                 
01665                 representation.remove(fileindex);
01666                 
01667         }
01668         
01674     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01675         void remove(char* filename)
01676     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01677         {
01678                 std::string str_filename(filename);
01679                 remove(str_filename); 
01680         }
01681                 
01686     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01687         void insert(Set& m, const std::string& filename)
01688     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01689         {
01690                 clock_t start = clock();
01691 
01692                 int fileindex = getFileIndex(filename);
01693                 representation.insert(m,fileindex);
01694 
01695                 clock_t finish = clock();
01696                 insertion_time += (finish-start);
01697 
01698         }
01699   
01704     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01705         void insert(Set& m, char* filename)
01706     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01707         {
01708                 insert(m, std::string(filename));
01709         }
01710   
01737     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01738         int merge(char* indexfile2, int mode = MODE_MERGE_DELETE)
01739     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01740         {
01741 
01742                 std::/*i*/fstream idxstream2;
01743         idxstream2.open(indexfile2, std::ios::in | std::ios::binary);
01744 
01745                 // geändert für MultiDimGList (r.b. 31.01.2002)
01746 //              if (idxstream2 == NULL)
01747                 if (idxstream2.bad())
01748                         return -1;
01749                 
01750                 int succ = merge(idxstream2,mode);              
01751 
01752                 idxstream2.close();
01753 
01754                 return succ;
01755 
01756         }
01757 
01784     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01785         int merge(std::/*i*/fstream& idxstream2, int mode = MODE_MERGE_DELETE)
01786     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01787         {
01788                 
01789                 GroupIndex<Set,Group,Representation>* mergeIndex = new GroupIndex<Set,Group,Representation>(idxstream2);
01790 
01791                 std::set<std::string> deleteList;
01792 
01793                 // I. Schritt: Zuordnung zwischen Dateinummern und Dateinamen mergen
01794 
01795         NameToIndexMap::iterator it;
01796 
01797         std::pair<std::string,int> val;
01798         
01799         for (it = nameToIndexMap.begin(); it != nameToIndexMap.end(); it++)
01800         {
01801             
01802                         std::string fname = (*it).first;
01803                         if (mergeIndex->hasFileIndex(fname))
01804                         {
01805                                 // Da ham'mer den Salat: Namenskonflikt!
01806                                 if (mode==MODE_MERGE_MAKE_UNIQUE)
01807                                 {
01808                                         // eindeutigen Dateinamen besorgen
01809                                         std::string ufname = getUniqueFileName(fname);
01810                                         // und umbenennen
01811                                         mergeIndex->renameFile(fname,ufname);
01812                                 } else if (mode==MODE_MERGE_DELETE) {
01813                                         // MODE_MERGE_DELETE
01814                                         // Datei in die deleteList aufnehmen
01815                                         deleteList.insert(fname);
01816                 } // else : mode==MODE_MERGE_IGNORE -> nix tun
01817                         }
01818                 }
01819                 
01820                 // II. Schritt: ListTupel aus idx2 nachschlagen und in idx1 einfügen
01821         int i;
01822                 for (i=0; i<mergeIndex->representation.size(); i++)
01823                 {
01824                         GList* glist = mergeIndex->representation[i];
01825 
01826             // wer das folgende typename verstehen will, lese bitte im Stroustrup nach ;)
01827             typename GList::iterator it = glist->begin();
01828             typename GList::iterator last = glist->end();
01829 
01830                         for (; it!=last; it++)
01831                         {
01832                                 ListTupel<IndexGroup> lt = *it;
01833                                 std::string fname = mergeIndex->getFileName(lt.i);
01834                                 Set s = mergeIndex->representation.getRepresentative(i);
01835 
01836                                 // durch die folgenden beiden Zeilen ist sichergestellt,
01837                                 // dass die G-invertierte Liste zu s ggf. neu angelegt wird.
01838                                 GList* insertList = representation[s];
01839 
01840                                 std::set<std::string>::iterator ci = deleteList.find(fname);
01841                                 if (ci==deleteList.end() || mode==MODE_MERGE_MAKE_UNIQUE  || mode==MODE_MERGE_IGNORE)
01842                                 {
01843                                         int findex = getFileIndex(fname);
01844                                         insertList->insert(lt.g,findex);
01845                                 } else {
01846                                         // Namenskonflikt, mode==MODE_MERGE_DELETE
01847                                         // -> nix tun
01848                                 }
01849                         }
01850                 }
01851 
01852                 idxstream2.close();
01853 
01854                 delete mergeIndex;
01855 
01856                 return 0;
01857 
01858         }
01859         
01873     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01874         int getIndexNameConflicts(char* indexfile2, std::set<std::string>& conflicting_names)
01875     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01876         {
01877                 
01878                 int conflict_count = 0;
01879 
01880                 FILE* idxstream2 = fopen(indexfile2, "rb");
01881                 if (idxstream2 == NULL)
01882                         return -1;
01883 
01884                 GroupIndex<Set,Group,Representation> mergeIndex = GroupIndex<Set,Group,Representation>();
01885                 mergeIndex.initFileRead(std::/*i*/fstream(fileno(idxstream2)));
01886 
01887 
01888                 // Dateinamen aus idx1 in idx2 nachschlagen
01889 
01890                 for (int i=0; i<maxFileIndex; i++)
01891                 {
01892                         std::string fname = getFileName(i);
01893                         if (mergeIndex.hasFileIndex(fname))
01894                         {
01895                                 
01896                                 // Da ham'mer den Salat: Namenskonflikt!
01897                                 conflict_count++;
01898                                 conflicting_names.insert(conflicting_names.end(),fname);
01899 
01900                         }
01901                 }
01902 
01903                 fclose(idxstream2);
01904                 
01905                 return conflict_count;
01906 
01907         }
01908         
01921     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01922         int getFilenames(std::set<std::string>& filenames)
01923     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01924         {
01925                 
01926         NameToIndexMap::iterator it;
01927 
01928         std::pair<std::string,int> val;
01929         
01930         for (it = nameToIndexMap.begin(); it != nameToIndexMap.end(); it++)
01931             filenames.insert((*it).first);
01932 
01933         return filenames.size();
01934 
01935         }
01936         
01943     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01944         long search(Set* query, int query_size, ListTupel<IndexGroup>*& result)
01945     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01946     {
01947         return search(query, query_size, result, 0);
01948     }
01949 
01957     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01958         long search(Set* query, int query_size, ListTupel<IndexGroup>*& result, int mismatches)
01959     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////
01960     {
01961         typename SetContainers::query_container c_query;
01962         
01963         // query-Array in query_container übertragen
01964         for (int i=0; i<query_size; i++)
01965             c_query.insert(c_query.begin(), query[i]);
01966 
01967         typename GroupContainers::result_container c_result;
01968         long rsize;
01969 
01970         rsize = search(c_query, c_result, mismatches);
01971 
01972         result = new ListTupel<IndexGroup>[rsize];
01973         typename GroupContainers::result_container::iterator r_it = c_result.begin();
01974         typename GroupContainers::result_container::iterator r_end = c_result.end();
01975 
01976         int j=0;
01977                 rsize = 0;      // 3.7.02 r.b.
01978         for (; r_it!=r_end; r_it++)
01979         {
01980             result[j] = *r_it;
01981             j++;
01982                         rsize++;        // 3.7.02 r.b.
01983         }
01984         return rsize;
01985 
01986     }
01987 
01997     long search(const typename SetContainers::query_container& query, typename GroupContainers::result_container& result, int mismatches=0)
01998     {
01999 
02000         if (mismatches>=query.size())
02001             throw IndexingException(IndexingException::INVALID_QUERY);
02002 
02003             // Ermitteln der Ergebnislisten
02004 
02005             result.clear();
02006             if (query.size()<=0)
02007             {
02008                     return 0;
02009             }
02010 
02011             // result_lists und operator_list sind Arrays von Pointern, 
02012             // damit beim Sortieren niemand auf die Idee kommt, copy-Konstruktoren aufzurufen...
02013             GList** result_lists = new GList*[query.size()]; 
02014 
02015         typename SetContainers::query_container::const_iterator it = query.begin();
02016         typename SetContainers::query_container::const_iterator last = query.end();
02017     
02018         int rl_count = 0;
02019             for (;it!=last; it++)
02020             {
02021               
02022             // r_m besteht aus einer Menge von Fuzzy-Repräsentanten
02023             typename SetContainers::representation_container r_m;
02024         
02025             // g_m muss nicht den gesamten Stabilisator beinhalten, sondern nur ein Element aus diesem,
02026             // weil der Stabilisator bereits komplett in den invertierten Listen gespeichert ist.
02027             // C++-syntaktisch funktioniert das, weil der Stabilisator-Container
02028             // zuweisungskompatibel mit Group sein muss.
02029             Group g_m;
02030             typename GroupContainers::stabilizer_container stab;
02031             getRepresentation(*it, stab, r_m);
02032             g_m = stab;
02033 
02034 
02035             typename SetContainers::representation_container::iterator r_it = r_m.begin();
02036             typename SetContainers::representation_container::iterator r_last = r_m.end();
02037 
02038             // ermittle nun base_list als die erste NICHT LEERE (!) invertierte Liste der Fuzzy-Repräsentanten
02039             GList* base_list = representation[*(r_it)];
02040 
02041             r_it++;
02042             while (r_it != r_last && base_list==NULL)
02043             {
02044                 base_list = representation[*(r_it)];
02045                 r_it++;
02046             }
02047 
02048             // merge base_list mit allen weiteren nicht-leeren Listen der Fuzzy-Repräsentanten
02049             if (base_list!=NULL)
02050             {                
02051                 // Kopie der Basisliste anlegen!
02052                 base_list = new GList(*base_list);
02053 #ifndef DONT_MERGE_WHILE_SEARCHING
02054                 while (r_it!=r_last)
02055                 {
02056                     GList* merge_with_list;
02057                     merge_with_list = representation[*(r_it++)];
02058                     if (merge_with_list != NULL)
02059                         base_list->merge(*merge_with_list);
02060                 }
02061 #else
02062 #endif
02063 
02064                 *base_list *= (!g_m);
02065 
02066                 result_lists[rl_count++] = base_list;
02067             } else {
02068                 // Wenn alle Listen der Fuzzy-Repräsentanten leer waren, wird dafür für alle 
02069                 // Treffer-Kandidaten ein Mismatch benötigt.
02070                 mismatches--;
02071             }
02072 
02073         } 
02074 
02075         if (rl_count==0)
02076         {
02077             delete[] result_lists;
02078             return 0;
02079         }
02080 
02081             // mache das Array result_lists zu einem heap 
02082         // (z.B. bezüglich Größe der Listen; nach welchem Kriterium der heap
02083         // verwaltet wird, entscheidet GList::operator>()
02084             heapify< GList >(result_lists, rl_count);   
02085 
02086             // ... und jetzt *effizient* die Schnittmenge aller Listen ermitteln
02087 
02088             int count = rl_count;
02089 
02090             GList* current_list = removeTopFromHeap< GList >(result_lists, count);
02091             int sect_list_size = current_list->size();
02092             
02093             // die Ausgangsmenge dient auch als Ergebnismenge, deshalb arbeiten wir auf einer Kopie dieser Liste
02094             // (-> Aufruf des copy-Konstrukturs!)
02095 
02096             // Bei der Suche muss der nicht-reguläre Fall nicht weiter beachtet werden, wenn
02097         // die invertierten Listen bereits beim Einfügen mit dem gesamten Stabilisator 
02098         // gefüllt werden.
02099         //
02100         // Wie sich leicht zeigen lässt, genügt es unter dieser Voraussetzung, bei der
02101         // Suche mit einem beliebigen Element aus dem Stabilisator zu arbeiten.
02102         // Dass dieses Vorgehen i.A. auch effizienter ist, zeigt die folgende Überlegung:
02103         //
02104         // Es bezeichne t \in \N die Grösse des (endlichen) Stabilisators und N die
02105         // Anzahl der Einträge in der invertierten Liste L \em modulo \em Stabilisator.
02106         // Dann hat nach oben vorgeschlagenem Vorgehen (Einfügen des gesamten Stabilisators 
02107         // in die invertierten Listen) die invertierte Liste L t*N Einträge. Durchsuchen 
02108         // dieser Liste kostet 
02109         //   (*)    O(log (t*N)) = O(log t + log N) 
02110         // Zeit.
02111         //
02112         // Nach dem alternativen Vorgehen werden die invertierten Listen modulo dem Stabilisator
02113         // gespeichert, enthalten also nur N Einträge. Zum Nachschlagen in dieser Liste
02114         // muss allerdings t mal in dieser Liste mit einem Zeitbedarf von je O(log N) gesucht
02115         // werden, was zu einem Gesamtaufwand von
02116         //  (**)    O(t*log N)
02117         // führt, was weniger effizient als (*) ist.
02118 
02119             GList* merge_list = NULL;
02120 
02121         current_list->setCredit(mismatches);
02122 
02123                 // Eingefügt für MultiDimGList:
02124                 current_list->setHeapStream(representation.getHeapStream());
02125 
02126             while (count>0 && current_list->size()>0)
02127             {
02128                     // Beachte: count wird durch removeTopFromHeap um eins verringert!
02129                     merge_list = removeTopFromHeap< GList >(result_lists, count);
02130 
02131                         // Eingefügt für MultiDimGList:
02132                         merge_list->setHeapStream(representation.getHeapStream());
02133 
02134                     // Schnittmenge der Listen bilden
02135                     current_list->intersect(*merge_list, mismatches);
02136 
02137             }
02138                     
02139             int rsize = current_list->size();
02140 
02141         // Ergebnisse der Schnittmengenbildungen nach result übertragen
02142                 // kleine Änderung zwecks Test mit MultDimGList: (true)
02143         typename GList::iterator res_it = current_list->begin(true);
02144         typename GList::iterator res_last = current_list->end(true);
02145 
02146         while (res_it != res_last)
02147             {
02148                     result.insert(result.begin(),*res_it);
02149             res_it++;
02150             }
02151 
02152             // Speicher freigeben
02153             for (int i=0; i<rl_count; i++)
02154                     delete result_lists[i];
02155             delete[] result_lists;
02156 
02157             return rsize;
02158 
02159     }
02160 
02161 
02162 
02163 };
02164 
02165 
02166 
02167 
02168 }
02169 
02170 #endif
The GroupIndex-Template-Library
Universität Bonn, Institut für Informatik III, 2001