autoDoc/HTML/---libBayesian-include-CPSetOfPSets-h

    /* -*- mode: c++ -*-
    */
    /*

        GIFT, a flexible content based image retrieval system.
        Copyright (C) 1998, 1999, 2000 CUI, University of Geneva

        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    */
    #ifndef _CPSETOFPSETS
    #define _CPSETOFPSETS

    #include <list>
    #include <vector>
    #include "CProbabilisticSet.h"
    #include "CSelfDestroyPointer.h"
    #include "helpers.h"

    /**@Doc
        In order to judge the consistency of comparisons performed
        by the user we have to keep for each comparison (or each group of
        comparisons, as remains to be tested) a set of elements with their
        degree of conistency with the comparison. This part (for a single set)
        is fulfilled by the CProbabilistic Set.

        In this structure we keep now a set of such sets,
        along with functions which
        judge their consistency.

        In fact this is a set of probabilistic sets together with
        helper functions for hunting pictures.

        todo:
        We can add a set of PSets to the set (these are the different comparisons)
        out of this set is calculated a list of iterator-lists

    */
    template<class T>
    class CPSetOfPSets{

      /*@name Type definitions */
      //@{
      ///An element of the content of this set
      typedef CProbabilisticSet<T> CSet;
      ///An element of the content of this set
      typedef pair<double,CSet* > CContentElement;
      ///The content of this set
      typedef vector<CContentElement> CContent;
      ///
      typedef CSet::CSequence CIDSequence;

      /** We give the user the possibility to give assumptions.
          An assumption is a set of contentelements.

          is, that each of the following sets  might be
          added to this.

          We will provide functions to associate a value to an assumption,
          making it possible to pick the best one

      */
      typedef CContentElement CAssumptionElement;

      typedef vector<CAssumptionElement> CAssumption;
      //@}

      ///
      CContent mContent;
      ///
      CAssumption* mAssumption;
      /// In order to be able to give back a set
      /// with the same properties as all other elements
      /// in this set of set.
      CSelfDestroyPointer<CSet> mSetPrototype;
      ///The current best guess of this structure.
      CSelfDestroyPointer<CSet> mCurrentBest;
      ///
      int mMaximumSize;
      ///
      int mForgetAfterNthInconsistency;
      ///This is needed for some calculations
      int mNumberOfImages;
    public:
      ///
      CPSetOfPSets(int inMaximumSize=10);
      ///
      ~CPSetOfPSets();
      ///
      CPSetOfPSets(int inMaximumSize,
    	       CSet* inSetPrototype);
      ///
      void addElement(const CContentElement& inSet);
      ///
      double evaluateAssumption(CAssumption* inAssumption);
      ///
      double updateWeights(CContent& inContent)const;
      ///
      double evaluateContent(const CContent& inContent,
    			 bool inWithOutput=false,
    			 string inOutputName="when_adding")const;
      ///
      const T* getCurrentBest()const;
      ///
      int getCurrentBestSize()const;
      ///
      CIDSequence* drawSequenceFromCurrentBest(long inSize)const;
      ///
      CSet* drawSetFromCurrentBest(long inSize)const;
      ///
      void setPrototype(CSet* inPrototype);
      ///
      CSet* getPrototypeClone()const;
      ///
      double combine(CContentElement& inoutChanged,
    		 const CContentElement& inChanger);
      ///reducing the size, if there are too many sets stored
      void reduceToTheMax(CContent& inContent);
      ///
      void setMaximumSize(int inMaximumSize);
      ///
      void setForgetAfterNthInconsistency (int inN);
      ///
      int size()const;
      ///
      void clear();
      ///
      void setNumberOfImages(const int& inNumberOfImages);
      ///
      int getNumberOfImages()const;
    };

    ///
    template<class T>
    void CPSetOfPSets<T>::setMaximumSize(int inMaximumSize){
      mMaximumSize=inMaximumSize;
      reduceToTheMax(mContent);
    };
    ///
    template<class T>
    int CPSetOfPSets<T>::getCurrentBestSize()const{
      return mCurrentBest->size();
    };
    ///
    template<class T>
    const T* CPSetOfPSets<T>::getCurrentBest()const{
      return mCurrentBest;
    };
    ///
    template<class T>
    int CPSetOfPSets<T>::size()const{
      return mContent.size();
    };
    ///
    template<class T>
    void CPSetOfPSets<T>::clear(){
      mContent.clear();
      mCurrentBest=0;
    };

    ///
    template<class T>
    CPSetOfPSets<T>::CIDSequence* CPSetOfPSets<T>::drawSequenceFromCurrentBest(long inSize)const{

      cout << "EDO-1" << endl;

      if(mCurrentBest){
        CIDSequence* l=mCurrentBest->drawSequence(inSize);
        return l;
      }
      else
        return 0;
    };

    ///
    template<class T>
    CPSetOfPSets<T>::CSet* CPSetOfPSets<T>::drawSetFromCurrentBest(long inSize)const{

      cout << "EDO-1" << endl;

      if(mCurrentBest)
        return mCurrentBest->drawSet(inSize);
      else
        return 0;
    };

    template<class T>
    CPSetOfPSets<T>::~CPSetOfPSets(){

    };

    template<class T>
    CPSetOfPSets<T>::CPSetOfPSets(int inMaximumSize):
      mAssumption(0),
      mSetPrototype(new CSet()),
      mCurrentBest(),
      mMaximumSize(inMaximumSize)
    {
    };

    template<class T>
    CPSetOfPSets<T>::CPSetOfPSets(int inMaximumSize,
    			      CSet* inSetPrototype):
      mAssumption(0),
      mSetPrototype(inSetPrototype),
      mMaximumSize(inMaximumSize)
    {

    };

    template<class T>
    void CPSetOfPSets<T>::setPrototype(CSet* inPrototype){
      mSetPrototype=inPrototype;
    }

    template<class T>
    CPSetOfPSets<T>::CSet* CPSetOfPSets<T>::getPrototypeClone()const{
      return mSetPrototype ? mSetPrototype->clone():0;
    }

    template<class T>
    double CPSetOfPSets<T>::combine(CContentElement& inoutChanged,
    				const CContentElement& inChanger){
      if(inChanger.first>0.5){
        return inoutChanged.second->intersect(*inChanger.second);
      }else{
        return 0;
      }
    }

    template<class T>
    void CPSetOfPSets<T>::addElement(const CContentElement& inSet){
      cout << "BEFADD:"
           << mContent.end()-mContent.begin()
           << endl;

      cout << "A" << flush;

      mContent.push_back(inSet);
      cout << "BEFADD2:"
           << mContent.end()-mContent.begin()
           << endl;
      {
        CProbabilisticSet<int>::CElementVector lDiagnosis;
        mContent.back().second->getContent(lDiagnosis);
        show_ProbabilisticSetElements(lDiagnosis.begin(),
    				  lDiagnosis.end(),
    				  "Added");
      }

      cout << "B" << flush;

      if(mContent.size()>1){

        updateWeights(mContent);
        evaluateContent(mContent,
    		    true,
    		    "NewState");
        mCurrentBest=mContent.back().second;
        mContent.pop_back();
        cout << endl
    	 << "---Checking Consistency---"
    	 << endl;

        //pruning: How to get rid of too old elements:
        //combine them to one element
        if(mContent.end()-mContent.begin()>mMaximumSize){

          cout << "+++++flattening+++++"
    	   << endl;

          // Either combine the knowledge of the element
          // which has to be compressed with existing
          // older and presently believed knowledge

          reduceToTheMax(mContent);

        }
      }else{
        cout << "TAKING"
    	 << endl;
        mCurrentBest=mContent.back().second->clone();
      }

      cout << endl
           << "--------------------a new best choice found, size: "
           << mCurrentBest->size()
           << "Total size"
           << size()
           << endl;

      cout << "AFTADD: Number of Distributions: "
           << mContent.end()-mContent.begin()
           << ", Number of elements in current back/best distribution:"
           << mContent.back().second->size()
           << "/"
           << mCurrentBest->size()
           << endl;

    };

    template<class T>
    double CPSetOfPSets<T>::updateWeights(CContent& inContent)const{
      assert(inContent.size());

      if(inContent.size()==1){
        inContent.front().first=1.0;
        return 1;
      }

      CContent::iterator lLast=inContent.end();
      lLast--;

      CSelfDestroyPointer<CSet> lLastIntersection=
        inContent.back().second->clone();
      CSet* lCurrentIntersection=inContent.back().second->clone();

      cout << "UPDATE" << endl;

      double lProbabilityThatFeedback=1;
      if(mCurrentBest && inContent.size()){
        CSelfDestroyPointer<CSet> lCurrentBest(mCurrentBest->clone());
        cout << "HERE"
    	 << lCurrentIntersection->size()
    	 <<endl;
        lProbabilityThatFeedback=lCurrentBest->intersect(*lCurrentIntersection)
          /(lCurrentBest->countAboveThreshold()+1);
      }

      // the probability that the user makes this sequence
      // of feedbacks
      double lCurrentProbability=1;
      double lLastProbability=1;

      int lZeroCounter=0;
      if(inContent.size()>1){

        CContent::iterator i=lLast;
        while(i!=inContent.begin()
    	  && (lZeroCounter<mForgetAfterNthInconsistency)){

          cout << "X" << flush;

          i--;

          cout << "Distance to the beginning:"
    	   << i-inContent.begin()
    	   << ","
    	   << i->first
    	   << ","
    	   << int(i->second)
    	   << endl
    	   << flush;

          lCurrentProbability *= lCurrentIntersection->intersect(*(i->second));

          cout << "here"
    	   << endl;

    #ifndef CLEAN
          if(lCurrentProbability!=0 && !lZeroCounter){
    #endif //CLEAN
    	i->first=1;

    	cout << "if1" << endl;
    	lLastProbability=lCurrentProbability;
    	lLastIntersection=lCurrentIntersection->clone();
    	cout << "if1b" << endl;
    #ifndef CLEAN
          }else{

    	lZeroCounter++;

    	//inconsistency detected
    	i->first=0;

    	assert(lLastIntersection);
    	{
    	  lCurrentProbability=lLastProbability;

    	  delete lCurrentIntersection;
    	  lCurrentIntersection=lLastIntersection->clone();

    	  cout << "###DETECTED INCONSISTENCY###" << endl;
    	}
    	cout << "if2" << endl;
          }
    #endif //CLEAN
        }
        while(i!=inContent.begin()){
          (--i)->first=0;
          cout << "###forgetting###"
    	   << endl;
        }
      }

      inContent.push_back(make_pair(lProbabilityThatFeedback/mNumberOfImages,
    				lCurrentIntersection));
    /* #else */
    /*   lCurrentIntersection->intersect(*inContent.front().second); */
    /*   inContent.push_back(make_pair(lProbabilityThatFeedback/mNumberofImages, */
    /* 				lCurrentIntersection)); */
    /* #endif */
      return 1+lProbabilityThatFeedback/mNumberOfImages;
    }

    template<class T>
    double CPSetOfPSets<T>::evaluateContent(const CContent& inContent,
    					bool inWithOutput,
    					string inOutputName)const{
      double lReturnValue=0;//a measure for the quality of the inContent
      for(CContent::const_iterator i=inContent.begin();
          i!=inContent.end();
          i++){
        //cout << ":" << i->first << endl;
        assert((i->first>=0)&&(i->first<=1));
        lReturnValue+=i->first;
      }

      if(lReturnValue>0){
        lReturnValue =
          inContent.back().second
          ->calculateInformation()//too much information is bad
          *
          sqrt(lReturnValue);//too much size is bad
      }
      {
        CProbabilisticSet<int>::CElementVector lDiagnosis;
        inContent.back().second->getContent(lDiagnosis);
        if(inWithOutput){
          show_ProbabilisticSetElements(lDiagnosis.begin(),
    				    lDiagnosis.end(),
    				    inOutputName);
        }
      }

      return lReturnValue ;
    }

    template<class T>
    double CPSetOfPSets<T>::evaluateAssumption(CAssumption* inAssumption){
      mAssumption
        =
        inAssumption;

      double lReturnValue=0;

      if(mAssumption->size()){
        //allocate a vector
        CContent lContentPlusAssumption(mContent.begin(),
    				    mContent.end());

        // add each element of the assumption to the vector
        // which we have just built up. Evaluate its
        // goodness and then make a weighted average of this
        for(CAssumption::const_iterator i=inAssumption->begin();
    	i!=mAssumption->end();
    	i++){
          cout << "bis hier"
    	   << flush;
          CSet* lCurrentAssumption=i->second->clone();
          lContentPlusAssumption.push_back(make_pair(1,
    						 lCurrentAssumption));

          double lProbability=updateWeights(lContentPlusAssumption);
          double lAssumptionValue=evaluateContent(lContentPlusAssumption);

          lReturnValue +=
    	//a-priory weight given by the user (will maybe stay unused)
    	i->first
    	//probability that this element of the assumption
    	//is taken by the user
    	* lProbability
    	//value of this assumptionElement
    	* lAssumptionValue
    	;

          cout << "Probability :"
    	   << lProbability
    	   << endl;

          //very dirty
          delete lContentPlusAssumption.back().second;
          lContentPlusAssumption.pop_back();
          delete lContentPlusAssumption.back().second;
          lContentPlusAssumption.pop_back();

        }
        /*if(lContentPlusAssumption.size())
          for(CContent::iterator i = lContentPlusAssumption.begin();
          i != lContentPlusAssumption.end();
          i++){
          cout << "deleteing" << i->second << endl << flush;
          delete (i->second);
          }*/
      }

      return lReturnValue;
    }

    template<class T>
    void CPSetOfPSets<T>::reduceToTheMax(CContent& inContent){
      if(!mMaximumSize){
        cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%clean pichunter: take what comes"
    	 << endl;
        if(inContent.size()>=2){
          CContent::iterator lSecondOldestElement=inContent.begin();
          lSecondOldestElement++;
          inContent.front().second->intersect(*lSecondOldestElement->second);
          inContent.front().second->normalize();
          inContent.erase(lSecondOldestElement);//newly added
          mCurrentBest=mContent.front().second->clone();
        }
      }else{
        cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Target tracker case "
    	 << endl;
        if(inContent.front().first>0.5){
          CContent::iterator lSecondOldestElement=inContent.begin();
          lSecondOldestElement++;
          combine(inContent.front(),
    	      *lSecondOldestElement);
          inContent.erase(lSecondOldestElement);
        }else{
          /// or delete the old unbelieved knowledge
          inContent.erase(inContent.begin());
        }
      }
    }

    ///
    template<class T>
    void CPSetOfPSets<T>::setForgetAfterNthInconsistency (int inN){
      mForgetAfterNthInconsistency=inN;
    };

    ///
    template<class T>
    void CPSetOfPSets<T>::setNumberOfImages(const int& inNumberOfImages){
     mNumberOfImages= inNumberOfImages;
    };

    ///
    template<class T>
    int CPSetOfPSets<T>::getNumberOfImages()const{
     return mNumberOfImages;
    };

    #endif