/***********************************************************************
This file is part of KEEL-software, the Data Mining tool for regression,
classification, clustering, pattern mining and so on.
Copyright (C) 2004-2010
F. Herrera (herrera@decsai.ugr.es)
L. S�nchez (luciano@uniovi.es)
J. Alcal�-Fdez (jalcala@decsai.ugr.es)
S. Garc�a (sglopez@ujaen.es)
A. Fern�ndez (alberto.fernandez@ujaen.es)
J. Luengo (julianlm@decsai.ugr.es)
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 3 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, see http://www.gnu.org/licenses/
**********************************************************************/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package keel.Algorithms.Instance_Generation.GMCA;
import keel.Algorithms.Instance_Generation.Basic.PrototypeSet;
import keel.Algorithms.Instance_Generation.Basic.Prototype;
import keel.Algorithms.Instance_Generation.*;
import keel.Algorithms.Instance_Generation.utilities.*;
import java.util.*;
/**
* Pair of clusters class that implements comparator.
* It is used for sorting the pairs of clusters in inter-cluster ascending order.
*/
class PairOfClusters implements Comparable<PairOfClusters>
{
/** Pair of clusters. */
Pair<Cluster,Cluster> pair;
/** Distance between the pair of clusters. */
double distance;
/** Label of the clusters.*/
double label;
/**
* Returns the distance between the clusters.
* @return Distance beteween the clusters.
*/
public double getDistance() { return distance; }
/**
* Label of the clusters.
* @return Label of the clusters.
*/
public double getLabel() { return label; }
/**
* Returns the pair of cluster.
* @return Pair of clusters.
*/
public Pair<Cluster, Cluster> getPair() { return pair; }
/**
* Constructor.
* @param one One cluster.
* @param two Other cluster.
*/
public PairOfClusters(Cluster one, Cluster two)
{
pair = new Pair<Cluster,Cluster>(one,two);
distance = Cluster.d(one, two);
label = one.label();
}
/**
* Constructor.
* @param one One cluster.
* @param two Other cluster.
* @param dist Distance between one and two.
*/
public PairOfClusters(Cluster one, Cluster two, double dist)
{
pair = new Pair<Cluster,Cluster>(one,two);
distance = dist;
label = one.label();
}
/**
* Overriding of the compareTo function.
* @param other Other pair of clusters.
* @return -1 if distance is smaller, 0 equal or 1 greater than other's clusters distance.
*/
@Override
public int compareTo(PairOfClusters other)
{
if(distance < other.distance)
return -1;
else if(distance == other.distance)
return 0;
return 1;
}
}
/**
* Set of the clusters.
* @author diegoj
*/
public class ClusterSet
{
/** Set of clusters. */
ArrayList<Cluster> clusters;
/** Assignment of cluster to each prototype. */
HashMap<Prototype,Cluster> assignment;
// Assignment of cluster to each prototype (used to restore the set).
//HashMap<Prototype,Cluster> savedAssignment;
Cluster mixed = null;
Cluster a = null;
Cluster b = null;
/*private void saveAssignment()
{
ArrayList<Prototype> ps = new ArrayList<Prototype>(assignment.keySet());
for(Prototype p : ps)
savedAssignment.put(p, assignment.get(p));
}*/
/*private void restoreAssignment()
{
ArrayList<Prototype> ps = new ArrayList<Prototype>(savedAssignment.keySet());
for(Prototype p : ps)
if(assignment.containsKey(p) && assignment.get(p)!=savedAssignment.get(p))
{
assignment.get(p).remove(p);
assignment.put(p, savedAssignment.get(p));
savedAssignment.get(p).add(p);
}
remove(mixed);
add(a);
add(b);
mixed = null;
a = null;
b = null;
}*/
//public void save(){ saveAssignment(); }
//public void restore(){ restoreAssignment(); }
/**
* Clone the cluster set.
* @return New clusterset that is a hard-copy of present.
*/
@Override
public ClusterSet clone()
{
ClusterSet copy = new ClusterSet();
copy.clusters = new ArrayList<Cluster>();
copy.assignment = new HashMap<Prototype,Cluster>();
for(Cluster c : clusters)
copy.clusters.add(c);
ArrayList<Prototype> ps = new ArrayList<Prototype>(assignment.keySet());
for(Prototype p : ps)
copy.assignment.put(p, assignment.get(p));
return copy;
}
public ClusterSet()
{
clusters = new ArrayList<Cluster>();
assignment = new HashMap<Prototype,Cluster>();
//savedAssignment = new HashMap<Prototype,Cluster>();
}
/**
* Gets cluster in ith position.
* @param i Position of the cluster.
* @return Cluster in ith position.
*/
public Cluster get(int i){ return clusters.get(i); }
/**
* Test that every prototype of the set has got an assigned cluster .
* @param s Prototype set to be tested.
*/
void test(PrototypeSet s)
{
for(Prototype p : s)
if(!assignment.containsKey(p))
Debug.errorln("OJJJJJJOOOOOOO Prototipo " + p.getIndex() + " no tiene cluster");
}
/*protected void makeClusterSetByClasses(PrototypeSet training)
{
clusters = new ArrayList<Cluster>();
assignment = new HashMap<Prototype,Cluster>();
ArrayList<Double> classes = training.nonVoidClasses();
for(double c : classes)
{
PrototypeSet trainingC = training.getFromClass(c);
Prototype avgC = trainingC.avg();
Cluster clusterC = new Cluster(trainingC,avgC);
clusters.add(clusterC);
for(Prototype p : trainingC)
assignment.put(p, clusterC);
}
}
protected void makeInitialClusterSet(PrototypeSet training)
{
clusters = new ArrayList<Cluster>();
assignment = new HashMap<Prototype,Cluster>();
for(Prototype p : training)
{
Cluster clusterP = new Cluster(p);
clusters.add(clusterP);
assignment.put(p, clusterP);
}
}*/
/**
* Gets the cluster of a prototype.
* @param p Prototype.
* @return Cluster of p.
*/
public Cluster get(Prototype p){ return assignment.get(p); }
/*public void removeWhoseRepresentativeIs(Prototype p)
{
remove(assignment.get(p));
}*/
/**
* Merge two clusters.
* @param Ca One cluster.
* @param Cb Other cluster.
* @return Merged cluster.
*/
public Cluster merge(Cluster Ca, Cluster Cb)
{
//Debug.force(assignment.containsKey(a), "prototype (a) "+ a.getIndex() +" is NOT a representative");
//Debug.force(assignment.containsKey(b), "prototype (b) "+ b.getIndex() +" is NOT a representative");
//Debug.endsIfNull(assignment.get(a), "Cluster de a es NULL");
//Debug.endsIfNull(assignment.get(b), "Cluster de b es NULL");
//Cluster cA = assignment.get(a);
//Cluster cB = assignment.get(b);
//Debug.errorln("MERGE de CLUSTERS " + Ca.id + " y " + Cb.id);
Cluster CmixAB = Ca.mix(Cb);
assignment.put(CmixAB.getRepresentative(), CmixAB);
//Debug.errorln("HHHHHHHHHHHHHHHHHHAntes " + size());
add(CmixAB);
remove(Ca);
remove(Cb);
//Debug.errorln("Borra cluster " + Ca.id);
//Debug.errorln("Borra cluster " + Cb.id);
//Debug.errorln("HHHHHHHHHHHHHHHHHHDESPUES " + size());
mixed = CmixAB;
a = Ca;
b = Cb;
return CmixAB;
}
/**
* Remove a cluster of the set.
* @param c Cluster to be removed.
* @return TRUE if it has been removed, FALSE in other chase.
*/
public boolean remove(Cluster c)
{
for(Prototype p : c.set)
if(assignment.get(p)==c)
assignment.remove(p);
return clusters.remove(c);
}
/**
* Adds a cluster of the set.
* @param c Cluster to be added.
*/
public void add(Cluster c)
{
clusters.add(c);
for(Prototype p : c.set)
assignment.put(p, c);
assignment.put(c.getRepresentative(), c);
}
/*public Pair<Cluster,Cluster> pairOfClustersWithSameClass()
{
Pair<Cluster,Cluster> pair = null;
double dMin = Double.POSITIVE_INFINITY;
int _size = clusters.size();
for(int i=0; i<_size; ++i)
for(int j=i+1; j<_size; ++j)
{
Cluster ci = clusters.get(i);
Cluster cj = clusters.get(j);
if(ci.label() == cj.label() && ci!=cj)
{
double dij = ci.d(cj);
if(dij < dMin)
{
dMin = dij;
pair = new Pair<Cluster,Cluster>(ci,cj);
}
}
}
return pair;
}*/
/*public Pair<Cluster,Double> nearestTo(Cluster c)
{
Pair<Cluster,Double> pair = null;
double dMin = Double.POSITIVE_INFINITY;
for(Cluster k : clusters)
if(k != c)
{
double d = k.d(c);
if(d < dMin)
{
dMin = d;
pair = new Pair<Cluster,Double>(k,dMin);
}
}
return pair;
}*/
/*public Pair<Cluster,Double> nearestWithSameClassAs(Cluster c)
{
Pair<Cluster,Double> pair = null;
double label = c.label();
double dMin = Double.POSITIVE_INFINITY;
for(Cluster k : clusters)
if(k != c && k.label()==label)
{
double d = k.d(c);
if(d < dMin)
{
dMin = d;
pair = new Pair<Cluster,Double>(k,dMin);
}
}
return pair;
}*/
/**
* Returns a list of pairs of clusters in inter-cluster ascending order.
* @return List of pair of clusters closest to nearest clusters.
*/
public ArrayList<Pair<Cluster,Cluster>> nearestClustersWithSameClass()
{
ArrayList<PairOfClusters> unsorted = new ArrayList<PairOfClusters>(clusters.size());
//HashSet<Cluster> chosen = new HashSet<Cluster>();
int _size = clusters.size();
for(int i=0; i<_size; ++i)
for(int j=i+1; j<_size; ++j)
{
Cluster ci = get(i);
Cluster cj = get(j);
double dij = ci.d(cj);
unsorted.add(new PairOfClusters(ci, cj, dij));
}
Collections.sort(unsorted);
ArrayList<Pair<Cluster,Cluster>> sorted = new ArrayList<Pair<Cluster,Cluster>>(unsorted.size());
for(PairOfClusters c : unsorted)
sorted.add(c.getPair());
ArrayList<Pair<Cluster,Cluster>> editedSorted = new ArrayList<Pair<Cluster,Cluster>>(sorted.size());
int sortedSize = sorted.size();
HashSet<Cluster> chosen = new HashSet<Cluster>();
for(int i=0; i<sortedSize; ++i)
{
Pair<Cluster,Cluster> ci = sorted.get(i);
if(!chosen.contains(ci.first()) && !chosen.contains(ci.second()))
{
chosen.add(ci.first());
chosen.add(ci.second());
editedSorted.add(ci);
}
}
//Debug.errorln("SORTED: " + sorted.size());
//Debug.errorln("EDITED SORTED: " + editedSorted.size());
return editedSorted;
}
/**
* Returns the set of clusters.
* @return Set of clusters.
*/
public ArrayList<Cluster> getClusters()
{
return clusters;
}
/**
* Returns the maximum radius length of set of clusters.
* @return Maximum radius length of the set of clusters.
*/
public double maxRadiusLength()
{
double rMax = Double.NEGATIVE_INFINITY;
//ArrayList<Cluster> clusters = getClusters();
for(Cluster c : clusters)
{
double cR = c.getRadiusLength();
if(rMax < cR)
rMax = cR;
}
return rMax;
}
/**
* Returns the maximum radius length of set of clusters of one class.
* @param k Class that must have the clusters.
* @return Maximum radius length of the set of clusters with k-class.
*/
public double maxRadiusLengthOfClass(double k)
{
double rMax = Double.NEGATIVE_INFINITY;
//ArrayList<Cluster> clusters = getClusters();
for(Cluster c : clusters)
if(c.getRepresentative().label() == k)
{
double cR = c.getRadiusLength();
if(rMax < cR)
rMax = cR;
}
return rMax;
}
/**
* Move one prototype to a cluster.
* @param p Prototype to be moved.
* @param c Destination of p.
*/
public void moveTo(Prototype p, Cluster c)
{
Cluster clusterOfP = assignment.get(p);
clusterOfP.remove(p);
if(clusterOfP.isEmpty())
remove(clusterOfP);
c.add(p);//add prototype to cluster
assignment.put(p, c);//add prototype to cluster
}
/**
* Returns the cluster of a prototype.
* @param p Prototype to be its cluster returned.
* @return Cluster that contains the prototype p.
*/
public Cluster getClusterOf(Prototype p)
{
return assignment.get(p);
}
/**
* Gets the number of clusters of the set.
* @return Number of present clusters.
*/
public int size(){ return getClusters().size(); }
}