eqclass.cpp

// $Id$

/* COMIENZO DE DESCRIPCION 

   __USE_WIKI__

   Dado un conjunto #S# y una relacion de orden 
   #bool comp(int x,int y)# separar #S#, segun 
   sus clases de equivalencia en una lista #list<set<int>> L#. 
   Signatura: 
   #void eqclass(set<int> &S, bool (*)(int x,int y),list<set<int>> &L)#

   [Tomado en el 3er parcial 2008-11-20].  
   keywords: conjunto

   FIN DE DESCRIPCION */

#include <time.h>
#include <sys/time.h>
#include <cassert>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include "./util.h"

using namespace std;

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Utilidad que imprime el conjunto
void print_set(set<int> &s,const char *lab=NULL) {
  set<int>::iterator q = s.begin();
  if (lab) printf("%s: ",lab);
  while (q != s.end()) 
    printf("%d ",*q++);
  printf("\n");
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Toma un elemento '*q' de S y lo va insertando en la
// clase (o sea el conjunto) correspondiente de
// L. El algoritmo para
void eqclass(set<int> &S, bool (*comp)(int x,int y),
             list<set<int> > &L) {
  L.clear(); 
  set<int>::iterator q = S.begin();
  while (q != S.end()) {
    list<set<int> >::iterator r = L.begin();
    int xr;
    while (r!=L.end()) {
      // `xr' es un elemento cualquiera de el conjunto `*r'
      xr = *(*r).begin();
      // Se detiene cuando *q <= xr
      // (Similar al algoritmo `lower_bound')
      if (!comp(xr,*q)) break;
      r++;
    }
    // En esta posicion esta o deberia estar
    // la clase de equivalencia (o sea el conjunto)
    // correspondiente a `*q'
    if (r==L.end() || comp(*q,xr)) {
      // No esta la clase equivalente a '*q', insertamos
      // un conjunto vacio
      r = L.insert(r,set<int>());
    }
    // Inserta el elemento
    r->insert(*q);
    q++;
  }
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
typedef bool (*less_fun_t)(int x,int y);
less_fun_t less_fun;

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// `Adapta' una funcion de comparacion para enteros
// a una para conjuntos de enteros. Esto es necesario
// para la version `eqclass3()'. 
bool less_for_sets(set<int> x,set<int> y) {
  // Verifica que los conjuntos no deberian estar vacios
  assert(!x.empty());
  assert(!y.empty());
  // Compara cualquiera elemento de `x' con cualquiera de `y'
  // (Total, como son clases de equivalencia deberian ser todos
  // equivalentes entre si). 
  return less_fun(*x.begin(),*y.begin());
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Toma un elemento '*q' de S y lo va comparando con las
// clases ya guardadas en `L', si no lo encuentra lo guarda
// al final, en una nueva clase.  Lo bueno de esta version
// es que no hay que andar buscando donde insertar,
// simplemente lo inserta al final. Lo malo es que entonces
// las clases quedan en principio desordenadas pero despues
// se pueden ordenar usando el `sort()', pero OJO es un sort
// de una lista de conjuntos de enteros.
void eqclass2(set<int> &S, bool (*comp)(int x,int y),
              list<set<int> > &L) {
  L.clear(); 
  set<int>::iterator q = S.begin();
  while (q != S.end()) {
    list<set<int> >::iterator r = L.begin();
    int xr;
    while (r!=L.end()) {
      // `xr' es un elemento cualquiera de el conjunto `*r'
      xr = *(*r).begin();
      // Se detiene cuando *q <= xr
      // (Similar al algoritmo `lower_bound')
      if (!comp(xr,*q) && !comp(*q,xr)) break;
      r++;
    }
    // O bien `r' esta apuntando a la clase de equivalencia
    // de `*q' o bien estamos al final de la lista.
    if (r==L.end()) {
      // No esta la clase equivalente a '*q', insertamos
      // un conjunto vacio
      r = L.insert(r,set<int>());
    }
    // Inserta el elemento
    r->insert(*q);
    q++;
  }

  // Bueno, ahora lo unico que falta es ordenar las clases
  // de equivalencia. Para eso podemos usar `sort', pero OJO
  // en este caso cada elemento de la lista es un conjunto de
  // manera que tenemos que construir un predicado ad-hoc.
  // Un punto debil es que tenemos que pasar la funcion
  // a `less_for_sets' por un puntero global. No se como
  // hacerlo de otra forma. 
  less_fun = comp;
  L.sort(less_for_sets);
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// En esta version ponemos todos los elementos de
// de `S' en un vector, lo ordenamos y despues
// vamos leyendo las clases de equivalencia del vector
// (deberian quedar ordenadas). 
void eqclass3(set<int> &S, bool (*comp)(int x,int y),
              list<set<int> > &L) {
  L.clear(); 
  vector<int> v;
  set<int>::iterator q = S.begin();
  while (q!=S.end()) v.push_back(*q++);

  sort(v.begin(),v.end(),comp);
  int j=0, k;
  while (j<v.size()) {
    // Busca la clase de equivalencia del siguiente elemento
    // `j'.  Como lo acabamos de ordenar estan todos juntos,
    // en el intervalo [j,k)
    list<set<int> >::iterator q = L.insert(L.end(),set<int>());
    k = j;
    while (!comp(v[j],v[k]) && !comp(v[k],v[j])) {
      q->insert(v[k]);
      k++;
    }
    j = k;
  }
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
bool less_abs(int x,int y) {
  // Menor en valor absoluto
  return abs(x) < abs(y);
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
int modulo(int n,int m) {
  int k = n % m;
  if (k<0) k += m;
  return k;
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
bool less_mod(int x,int y) {
  // Compara por modulo 10, o sea que las
  // clases de equivalencia son
  // {pares}, {impares}
  return modulo(x,2) < modulo(y,2);
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Funcion utilitaria que imprime todos los
// conjuntos de `L' uno por linea
void print_set_list(list< set<int> > &L) {
  list< set<int> >::iterator q = L.begin();
  while(q != L.end()) {
    print_set(*q);
    q++;
  }
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// El tipo de funciones que separa un conjunto por clases de
// equivalencia. Esto nos permite escribir despues una funcion
// que `prueba' cada uno de los algoritmos. 
typedef void eqclass_fun_t(set<int> &S, bool (*comp)(int x,int y),
                           list<set<int> > &L);

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Prueba uno de los algoritmos
void test_eqclass_fun(eqclass_fun_t eqclass_fun) {
  
  set<int> S;

  // Inserta los enteros en [-4,4]
  for (int j=-4; j<=4; j++)
    S.insert(j);
  list< set<int> > L;

  printf("clases de equivalencia para less_abs()\n");
  // Las clases de equivalencia deberian ser
  // {0} y los pares {-x,x} con x>0. 
  eqclass_fun(S, less_abs, L);
  print_set_list(L);
  
  printf("clases de equivalencia para less_mod()\n");
  // Las clases de equivalencia deberian ser
  // {pares}, {impares}
  eqclass_fun(S, less_mod, L);
  print_set_list(L);
  
}

//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
int main() {
  // Prueba cada uno de los algoritmos 
  printf("------ Con EQCLASS ------\n");
  test_eqclass_fun(eqclass);
  printf("------ Con EQCLASS2 ------\n");
  test_eqclass_fun(eqclass2);
  printf("------ Con EQCLASS3 ------\n");
  test_eqclass_fun(eqclass3);
}

Generated by GNU Enscript 1.6.6.