std::map associer des index et une classe, comparison function

std::map associer des index et une classe, comparison function - C++ - Programmation

Marsh Posté le 20-10-2008 à 18:01:32    

Bonjour, j'utilise assez massivement la map de la stl, avec succes... jusqu'a present. Il s'agit d'associer des index et une classe super petite, qui contient deux elements : une longueur et un enum pouvant prendre quelques valeurs. La voici :
 

Code :
  1. class linkDirAndLength
  2. {
  3. public:
  4.    linkDirAndLength(){length=-1;};
  5.    linkdir dir;
  6.    int length;
  7.  
  8.    bool operator== (const linkDirAndLength a) const
  9.    {
  10.       if(a.dir==dir && a.length==length)
  11.          return true;
  12.       return false;
  13.    }
  14.  
  15.    bool operator< (const linkDirAndLength a) const
  16.    {
  17.       if(length<a.length && a.dir==dir)
  18.          return true;
  19.       return false;
  20.    }
  21. };


 
Ensuite, je construit ma map comme suit :  

Code :
  1. linkDirAndLength lkdl;lkdl.dir=lk.getDir();lkdl.length=lk.getLength();
  2.             m_mapLinkToListPhysicalLinks[lkdl]=listPhysicalLinks.size()-1;


C'est inscrit dans une boucle qui genere toutes les possibilites de longueur et de valeurs de l'enum, il y a 28 entrees en tout.
 
Le probleme est lorsque je cherche a acceder a mes donnees associee a une cle : donc dans la fonction de comparaison.
Si je defini la fonction de comparaison comme suit :

Code :
  1. bool operator< (const linkDirAndLength a) const
  2.    {
  3.       if(length<a.length)
  4.          return true;
  5.       return false;
  6.    }


La map sort parfois les mauvaises cles, car seule la longueur est testee : apparemment, si la longueur est bonne, je me retrouve avec une donnee erronne dans l'enum (bonne longueur, mauvais enum...)
J'ai essaye comme montre dans la definition de la classe avec une comparaison de l'enum, marche pas : je me retrouve avec  des retours vraiment errones sur la longueur...
 
Mais je comprend pas vraiment pourquoi ? Et surtout comment reussir a associer mes cles/index comme je le veut  :cry:  
 
Avez-vous une idee ? Merci !


---------------
Un blog qu'il est bien
Reply

Marsh Posté le 20-10-2008 à 18:01:32   

Reply

Marsh Posté le 20-10-2008 à 23:00:03    

J'ai fini par trouver : la bonne solution est bien de comparer seulement les longueurs... seulement, j'etais persuade de ne rechercher _que_ des entrees existatnes, et ce n'etait pas le cas. J'enregistre en effet les longueurs sous forme signee, et les recherchaient de facon absolues. Bref, mea culpa.


---------------
Un blog qu'il est bien
Reply

Marsh Posté le 31-10-2008 à 15:50:37    

Mais non en fait ca marche pas... (je sais ca fait plusieurs jours, j'ai plein de trucs a faire  :D )
Voici un exemple simple : une classe qui contient deux entiers (mettons que ce sont des positions, x/y)
 

Code :
  1. #ifndef _CPOINT2D_H_
  2. #define _CPOINT2D_H_
  3. #include <iostream>
  4. #include <sstream>
  5. using namespace std;
  6. class CPoint2D
  7. {
  8. public:
  9. int x,y;
  10. public:
  11. CPoint2D(){this->x=0;this->y=0;}
  12. CPoint2D(int x=0,int y=0){this->x=x;this->y=y;}
  13. ~CPoint2D(void){}
  14.  
  15.    bool operator< (const CPoint2D p) const
  16.    {
  17.       return (x*x+y*y)<(p.x*p.x+p.y*p.y);
  18.    }
  19.  
  20.    bool operator!= (CPoint2D p) const
  21.    {
  22.       if(p.x!=this->x || p.y!=this->y)
  23.          return true;
  24.       return false;
  25.    }
  26.  
  27.    string toString() const
  28.    {
  29.       ostringstream oss;
  30.       oss<<x<<";"<<y;return oss.str();
  31.    }
  32. };
  33. #endif


 
Ensuite on construit une map qui fait la correspondance entre une position et un index unique (j'ai verifie, ils sont bien parfaitement uniques)
Je vous fourni (pour fins de tests si vous le desirez) les fonctions necessaires :

Code :
  1. /** Map direct position in waferic to address in wafernet
  2.    */
  3.    map<CPoint2D, int> m_positionToAddr;
  4. /**Calcul de l'index de la cellule en fonction de
  5.     * @param i_wf : numero de reticule dans le wafer
  6.     * @param i_ret : numero de la cellule dans le reticule
  7.     */
  8.    int calc_index_nanopads(int i_wf, int i_ret)
  9.    {
  10.       return i_wf*retSize*retSize+i_ret;
  11.    }
  12.    int calc_num_wf(int x, int y)
  13.    {
  14.       if(x<0 || x>=WICSizeX || y<0 || y>=WICSizeY)
  15.          std::cout<<"Erreur : recherche d'un reticule hors waferIC"<<std::endl;
  16.       return y*WICSizeX+x;
  17.    }
  18.    int calc_num_ret(int x, int y)
  19.    {
  20.       if(x<0 || x>=retSize || y<0 || y>=retSize)
  21.          std::cout<<"Erreur : recherche d'une cellule hors reticule"<<std::endl;
  22.       return y*retSize+x;
  23.    }
  24.  
  25.    int calc_addr(int x_wf, int y_wf, int x_ret, int y_ret){return this->calc_index_nanopads(this->calc_num_wf(x_wf,y_wf),this->calc_num_ret(x_ret,y_ret))+1;}
  26. void createLUTPostToAddr()
  27. {
  28.    for(int x=0; x<WICSizeX*retSize; x++)
  29.    {
  30.       for(int y=0; y<WICSizeY*retSize; y++)
  31.       {
  32.          /** Calcul de la position de la cellule courante
  33.           */
  34.          int x_wf = x/retSize; //index du reticule courant dans le waferIC en x
  35.          int y_wf = y/retSize; //index du reticule courant dans le waferIC en y
  36.          int x_ret = x%retSize; //index de la cellule courante dans le reticule en x
  37.          int y_ret = y%retSize; //index de la cellule courante dans le reticule en y
  38.          /** Calcul de l'index de la cellule courante (unique)
  39.           */
  40.          int addr = calc_addr(x_wf,y_wf,x_ret,y_ret);
  41.          CPoint2D p(x,y);
  42.          m_positionToAddr[p]=addr;
  43.       }
  44.    }


 
Ensuite, essayons avec la map de faire des recherches dedans : et bien vous trouverez des resultats qui vont correspondere a ce genre la :
#Adresses pos_x pos_y
13837 108 96
13837 96 108
 
Lors d'un appel a la hash table, par exemple : m_positionToAddr.find(CPoint2D(pos_x1,pos_y1))->second
Pour recuperer l'adresse correspondante a la position pos_x1, pos_y1 : la hash table renvoie tantot l'element x1, y1 et tanto y1,x1 a la meme adresse !!
 
Pourtant les adresses sont bien uniques, on peut le verifier avec ca :
 

Code :
  1. map<CPoint2D, int>::const_iterator it;
  2.    map<CPoint2D, int>::const_iterator it2;
  3.    int i=0,j=0;
  4.    for ( it = m_positionToAddr.begin(); it != m_positionToAddr.end(); ++it )
  5.    {
  6.       for ( it2 = m_positionToAddr.begin(); it2 != m_positionToAddr.end(); ++it2 )
  7.       {
  8.          if(it->second==it2->second && i!=j)  //same addresses but not same position in wafer ???
  9.             cout<<"Positions "<<it->first.toString()<<" and "<<it2->first.toString()<<" have adresses "<<it->second<<" and "<<it2->second<<endl;
  10.          j++;
  11.       }
  12.       j=0;
  13.       i++;


L'output de cette fonction est rien... aucun doublon n'est trouve. Donc ma hash table est correcte, c'est mon operateur < de la classe CPoint2d qui ne fonctionne pas... mais je comprend rien  :??:  
 
Si vous avez un peu de temps a consacrer a mon probleme.... merci milles fois !


---------------
Un blog qu'il est bien
Reply

Marsh Posté le 31-10-2008 à 23:43:29    

Normal. La clé de ta map est un CPoint2D, pas ta valeur 13837.
 
Si on prends les points suivants : CPoint2D p1( 108, 96 ) et CPoint2D p2( 96, 108 ), ces 2 points sont différents d'après ton operateur!=
 
Du coup p1 et p2 peuvent avoir la même "adresse".


---------------
Be the one with the flames.
Reply

Marsh Posté le 03-11-2008 à 18:51:50    

Riot a écrit :

Normal. La clé de ta map est un CPoint2D, pas ta valeur 13837.
 
Si on prends les points suivants : CPoint2D p1( 108, 96 ) et CPoint2D p2( 96, 108 ), ces 2 points sont différents d'après ton operateur!=
 
Du coup p1 et p2 peuvent avoir la même "adresse".


?? Excuse moi je comprend pas : si ils sont differents ils peuvent avoir la meme adresse ?? Adresse dans la map, ou selon mon calcul d'adresse ?
Rhaa c'est stupide parce que mon calcul d'adresse calc_addr renvoi bien une adresse differente pour x/y inverses grace aux parametres x_wf,y_wf,x_ret,y_ret
Mais la map ne tiens pas compte de cela a cause de l'operateur != de CPoint2D ?
 
Si c'est le cas, je sais pas trop quelle solution elegante retenir. Pour le moment, j'ai triche en modifiant ma classe CPoint2D, en "linearisant" l'espace 2D sur une ligne loooongue ce qui rend l'operateur < plus "juste" : CPoint2D p1( 108, 96 ) et CPoint2D p2( 96, 108 ) seront bien rendu different.


---------------
Un blog qu'il est bien
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed