/* * Copyright (C) Justo Montiel, David Torres, Sergio Gomez, Alberto Fernandez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * <http://www.gnu.org/licenses/> */ package methods; import inicial.FesLog; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Vector; import java.util.logging.Level; import tipus.metodo; import tipus.tipusDades; import utils.MiMath; import utils.PrecDouble; import definicions.Cluster; import definicions.MatriuDistancies; /** * <p> * <b>MultiDendrograms</b> * </p> * * Calculates the clustering from the distances matrix * * @author Justo Montiel, David Torres, Sergio Gómez, Alberto Fernández * * @since JDK 6.0 */ public class Reagrupa { private Vector<Integer> grups; private int nextGrup = 0; private int numElems = 0; private double valmin, valmax; private final Integer grupNul = new Integer(0); private final tipusDades typeData; private final metodo method; private final int precision; private final MatriuDistancies mdAct; public Reagrupa(final MatriuDistancies md, final tipusDades typeData, final metodo method, final int precision) { //FesLog.LOG.info("MatriuDistancies" + md); this.typeData = typeData; this.method = method; this.precision = precision; this.mdAct = md; // System.out.println("into reagrupa"); this.IniciaDades(); } private void IniciaDades() { // System.out.println("into IniciaDades"); valmin = mdAct.minValue(); valmax = mdAct.maxValue(); numElems = mdAct.getCardinalitat(); grups = new Vector<Integer>(numElems); // System.out.println(numElems); for (int n = 0; n < numElems; n++) { grups.add(n, grupNul); } // System.out.println(grups); } // inRange private boolean inRang(final double d) { double max, min, val; boolean enRango; if (typeData.equals(tipusDades.DISTANCIA)) { min = MiMath.Arodoneix(valmin, precision); val = MiMath.Arodoneix(d, precision); enRango = (min >= val); } else { max = MiMath.Arodoneix(valmax, precision); val = MiMath.Arodoneix(d, precision); enRango = (max <= val); } return enRango; } public MatriuDistancies Recalcula() throws Exception { // System.out.println("into rg.recalula()"); Integer grupActual; int numElements; double dist; LinkedHashMap<Integer, Cluster> lhm; MatriuDistancies Newmd; final Vector<Cluster> v = mdAct.getClusters(); numElements = mdAct.getCardinalitat(); // introduim cada cluster en un grup, si dos clusters s'han de // fusionar, aquest s'introduiran en un mateix grup, igual amb // la resta de clusters que hi puguin exitir en el grup. // Enter each cluster in a group, if two clusters should // fuse, introduced in the same group with the same // other clusters that are also in that group. for (int i = 0; i < numElements; i++) { // grup del cluster, si en te, si no null. // cluster group, if any, otherwise null. grupActual = new Integer(grups.get(i)); // l'element "i" el comparem amb tots els que te per sota. // element "i" is compared to all those below it. for (int inext = i + 1; inext < numElements; inext++) { // inext = cluster proxim dist = mdAct.getDistancia(v.get(i), v.get(inext)); if (this.inRang(dist)) { // cal agrupar-los, estan a distsncia minima if (grupActual.equals(grupNul)) { // si cluster actual no te grup if (grups.get(inext).equals(grupNul)) { // si cluster proxim no te grup // nou identificador d'agrupacio grupActual = ++nextGrup; grups.set(i, new Integer(grupActual)); grups.set(inext, new Integer(grupActual)); } else { // el cluster proxim en te id d'agrupacio grupActual = new Integer(grups.get(inext)); grups.set(i, new Integer(grupActual)); } } else { // el cluster actual pertany a una agrupaci if (grups.get(inext).equals(grupNul)) { // el cluster proxim no te grup grups.set(inext, new Integer(grupActual)); } else { // el cluster prxim pertany a una agrupaci if (!grupActual.equals(grups.get(inext))) { // tots dos clusters son de diferents agrupacions transfuga final Integer transfuga = grups.get(inext); // afegim a l'agrupacio del cluster tots els clusters que // pertanyen a l'agrupacio del cluster proxim for (int n = 0; n < numElems; n++) { if (grups.get(n).equals(transfuga)) { // assignem a un nou grup grups.set(n, new Integer(grupActual)); } } } } } } } } //sent to log file // if (FesLog.LOG.isLoggable(Level.INFO)) { // String cad; // cad = "AGRUPACIONS\n"; // for (int n = 0; n < numElems; n++) // cad += "Id: " + v.get(n).getId() + " ---> " + grups.get(n) // + "\n"; // FesLog.LOG.info(cad); // } // System.out.println("Through recalcula for loops"); lhm = this.NousClusters(grups); // System.out.println("lhm: " + lhm.toString()); Newmd = this.NovaMatriu(lhm); // System.out.println("Through Newmd! " + "Newmd: " + Newmd.toString()); return Newmd; } private MatriuDistancies NovaMatriu( final LinkedHashMap<Integer, Cluster> lhm) throws Exception { final int numelems = lhm.size(); double tmp; PrecDouble max; Method mt; Cluster c; MatriuDistancies nMd; double minbase1 = Double.MAX_VALUE; final Vector<Cluster> v = new Vector<Cluster>(numelems); final Collection<Cluster> col = lhm.values(); final Iterator<Cluster> itr = col.iterator(); // System.out.println("into rg.NovaMatriu()"); // distancia maxima interna de les aglomeracions while (itr.hasNext()) { tmp = 0; if (typeData.equals(tipusDades.DISTANCIA)) { max = new PrecDouble(Double.MIN_VALUE); } else { max = new PrecDouble(Double.MAX_VALUE); } c = itr.next(); // System.out.println("cluster " + c + ": "); // System.out.println("Name: " + c.getNom()); // System.out.println("Elements: " + c.getCardinalitat()); // System.out.println(); // nomes s'ha de fer en els nous if (c.isNado()) { for (int i = 0; i < c.getFamily() - 1; i++) { for (int ii = i + 1; ii < c.getFamily(); ii++) { tmp = mdAct.getDistancia(c.getFill(i), c.getFill(ii)); // maxima distancia dins del supercluster if (typeData.equals(tipusDades.DISTANCIA)) { // max = (max > tmp ? max : tmp); max.SetMajor(tmp); } else { // max = (max < tmp ? max : tmp); max.SetMenor(tmp); } } } double b; if (c.getFamily() > 2) { final PrecDouble tp = new PrecDouble(c.getAlcada()); tp.Resta(max); tp.SetPositiu(); b = c.setAglomeracio(tp.parserToDouble()); } else b = c.setAglomeracio(0.0); if (b < minbase1) minbase1 = b; } v.add(c); } // matriu d'un element, afegim la copa if (numelems == 1) { nMd = new MatriuDistancies(1, typeData); nMd.setDistancia(v.get(0)); return nMd; } // System.out.println("pass up to initializating new matrix"); // nova matriu nMd = new MatriuDistancies(numelems, typeData); // System.out.println("new matrix initialized"); // distancies entre clusters for (int i = 0; i < numelems - 1; i++) { for (int ii = i + 1; ii < numelems; ii++) { // els calculs s'han de fer nomes si hi ha un cluster nou (agrupacio) if (v.get(i).isNado() || v.get(ii).isNado()) { // metode ha utilitzar en el calcul mt = this.getMethod(v.get(i), v.get(ii), mdAct); tmp = mt.Distancia(); // afegim clusters i distancies nMd.setDistancia(v.get(i), v.get(ii), tmp); } else { // ja tenim calculada la distancia entre els dos clusters tmp = mdAct.getDistancia(v.get(i), v.get(ii)); // afegim clusters i distancies nMd.setDistancia(v.get(i), v.get(ii), tmp); } } } // debug // if (FesLog.LOG.getLevel().equals(Level.FINER)) { // System.out.println("\nMariu Creada.\n"); // for (int i = 0; i < numelems - 1; i++) { // for (int ii = i + 1; ii < numelems; ii++) { // FesLog.LOG.finer("Distancia entre " // + nMd.getCluster(i).getId() // + " i " // + nMd.getCluster(ii).getId() // + " = " // + nMd.getDistancia(nMd.getCluster(i), // nMd.getCluster(ii))); // } // } // System.out.println("\n"); // } nMd.getArrel().setBase(minbase1); // System.out.println("all the way through?"); return nMd; } private Method getMethod(final Cluster ci, final Cluster cj, final MatriuDistancies md) { Method m; if (method.equals(metodo.SINGLE_LINKAGE)) { m = new SingleLinkage(ci, cj, md); } else if (method.equals(metodo.COMPLETE_LINKAGE)) { m = new CompleteLinkage(ci, cj, md); } else if (method.equals(metodo.WEIGHTED_AVERAGE)) { m = new WeightedAverage(ci, cj, md); } else if (method.equals(metodo.UNWEIGHTED_CENTROID)) { m = new UnweightedCentroid(ci, cj, md); } else if (method.equals(metodo.JOINT_BETWEEN_WITHIN)) { m = new JointBetweenWithin(ci, cj, md); } else if (method.equals(metodo.WEIGHTED_CENTROID)) { m = new WeightedCentroid(ci, cj, md); } else if (method.equals(metodo.UNWEIGHTED_AVERAGE)) { m = new UnweightedAverage(ci, cj, md); } else { m = null; } return m; } private LinkedHashMap<Integer, Cluster> NousClusters( final Vector<Integer> grup) throws Exception { Cluster sc; final LinkedHashMap<Integer, Cluster> lhm = new LinkedHashMap<Integer, Cluster>(); Integer id; for (int i = 0; i < grup.size(); i++) { id = grup.get(i); if (id == grupNul) { mdAct.getCluster(i).isNado(false); lhm.put(mdAct.getCluster(i).hashCode(), mdAct.getCluster(i)); } else { // s'afegeix el cluster al supercluster corresponent // added to the cluster corresponding Supercluster if (lhm.containsKey(id)) { lhm.get(id).addCluster(mdAct.getCluster(i)); } else { // en ell el primer cluster de l'agrupacio // in fact the first cluster grouping sc = new Cluster(); // alcada de l'agrupacio if (typeData.equals(tipusDades.DISTANCIA)) { sc.setAlcada(valmin); } else { sc.setAlcada(valmax); } // afegeixo el cluster a al supercluster sc.addCluster(mdAct.getCluster(i)); lhm.put(grup.get(i), sc); } } } return lhm; } }