/* ========================================== * JGraphT : a free Java graph-theory library * ========================================== * * Project Info: http://jgrapht.sourceforge.net/ * Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh) * * (C) Copyright 2003-2008, by Barak Naveh and Contributors. * * This program and the accompanying materials are dual-licensed under * either * * (a) the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation, or (at your option) any * later version. * * or (per the licensee's choosing) * * (b) the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation. */ /* ----------------- * EquivalenceSetCreator.java * ----------------- * (C) Copyright 2005-2008, by Assaf Lehr and Contributors. * * Original Author: Assaf Lehr * Contributor(s): - * * $Id$ * * Changes * ------- */ package org.jgrapht.experimental.equivalence; import java.util.*; /** * FIXME Document me. * * @param <E> the type of the elements in the set * @param <C> the type of the context the element is compared against, e.g. a * Graph TODO hb 060208: REVIEW: Using an array for aElementsArray causes * problems with generics elsewhere - changed to List? * * @author Assaf * @since Jul 21, 2005 */ public class EquivalenceSetCreator<E, C> { private static final EqGroupSizeComparator groupSizeComparator = new EqGroupSizeComparator(); /** * Checks for equivalance groups in the aElementsArray. Returns an ordered * array of them, where the smallest one is the first in the array. * * @param aElementsArray * @param aEqComparator * * @deprecated To improve type-safety when using generics, use {@link * #createEqualityGroupOrderedArray(Collection, EquivalenceComparator, * Object)} */ @Deprecated public static <EE, CC> EquivalenceSet [] createEqualityGroupOrderedArray( EE [] aElementsArray, EquivalenceComparator<? super EE, ? super CC> aEqComparator, CC aContext) { return (createEqualityGroupOrderedArray( Arrays.asList(aElementsArray), aEqComparator, aContext)); // ArrayList<EquivalenceSet<? super EE,? super CC>> arrayList = new // ArrayList<EquivalenceSet<? super EE,? super CC>>(); // // HashMap<Integer,List<EquivalenceSet<? super EE,? super CC>>> map // = createEqualityGroupMap(aElementsArray, aEqComparator, // aContext); // each of the map values is a list with one or // more groups in it. // Object[] array = map.values().toArray(); // // for (int i = 0; i < array.length; i++) // { // List list = // (List)array[i]; // // for (List<EquivalenceSet<? super EE,? super CC>> list : // map.values() ) { for (EquivalenceSet<? super EE,? super CC> // eSet : list ) { arrayList.add( eSet ); } } // // // now we got all the eq. groups in an array list. we need to sort // // them EquivalenceSet [] resultArray = new EquivalenceSet // [arrayList.size()]; arrayList.toArray(resultArray); // Arrays.sort(resultArray, groupSizeComparator); return // resultArray; } /** * Checks for equivalance groups in the aElementsArray. Returns an ordered * array of them, where the smallest one is the first in the array. * * @param elements * @param aEqComparator TODO hb 060208: Using an array for aElementsArray * causes problems with generics elsewhere - change to List? */ public static <EE, CC> EquivalenceSet [] createEqualityGroupOrderedArray( Collection<EE> elements, EquivalenceComparator<? super EE, ? super CC> aEqComparator, CC aContext) { ArrayList<EquivalenceSet<? super EE, ? super CC>> arrayList = new ArrayList<EquivalenceSet<? super EE, ? super CC>>(); HashMap<Integer, List<EquivalenceSet<? super EE, ? super CC>>> map = createEqualityGroupMap(elements, aEqComparator, aContext); // each of the map values is a list with one or more groups in it. // Object[] array = map.values().toArray(); // for (int i = 0; i < array.length; i++) // { // List list = (List)array[i]; for (List<EquivalenceSet<? super EE, ? super CC>> list : map.values()) { for (EquivalenceSet<? super EE, ? super CC> eSet : list) { arrayList.add(eSet); } } // now we got all the eq. groups in an array list. we need to sort // them EquivalenceSet [] resultArray = new EquivalenceSet[arrayList.size()]; arrayList.toArray(resultArray); Arrays.sort(resultArray, groupSizeComparator); return resultArray; } /** * The data structure we use to store groups is a map, where the key is * eqGroupHashCode, and the value is list, containing one or more eqGroup * which match this hash. * * @param elements * @param aEqComparator * * @return a hashmap with key=group hashcode , value = list of eq.groups * which match that hash. TODO hb 060208: Using an array for aElementsArray * causes problems with generics elsewhere - change to List? */ private static <EE, CC> HashMap<Integer, List<EquivalenceSet<? super EE, ? super CC>>> createEqualityGroupMap( Collection<EE> elements, EquivalenceComparator<? super EE, ? super CC> aEqComparator, CC aComparatorContext) { HashMap<Integer, List<EquivalenceSet<? super EE, ? super CC>>> equalityGroupMap = new HashMap<Integer, List<EquivalenceSet<? super EE, ? super CC>>>( elements.size()); for (EE curentElement : elements) { int hashcode = aEqComparator.equivalenceHashcode( curentElement, aComparatorContext); List<EquivalenceSet<? super EE, ? super CC>> list = equalityGroupMap.get(Integer.valueOf(hashcode)); // determine the type of value. It can be null(no value yet) , // or a list of EquivalenceSet if (list == null) { // create list with one element in it list = new LinkedList<EquivalenceSet<? super EE, ? super CC>>(); list.add( new EquivalenceSet<EE, CC>( curentElement, aEqComparator, aComparatorContext)); // This is the first one .add it to the map , in an eqGroup equalityGroupMap.put(Integer.valueOf(hashcode), list); } else { boolean eqWasFound = false; // we need to check the groups in the list. If none are good, // create a new one for (EquivalenceSet<? super EE, ? super CC> eqGroup : list) { if (eqGroup.equivalentTo( curentElement, aComparatorContext)) { // add it to the list and break eqGroup.add(curentElement); eqWasFound = true; break; } } // if no match was found add it to the list as a new group if (!eqWasFound) { list.add( new EquivalenceSet<EE, CC>( curentElement, aEqComparator, aComparatorContext)); } } } return equalityGroupMap; } /** * Functor used to order groups by size (number of elements in the group) * from the smallest to the biggest. If they have the same size, uses the * hashcode of the group to compare from the smallest to the biggest. Note * that it is inconsistent with equals(). See Object.equals() javadoc. * * @author Assaf * @since Jul 22, 2005 */ private static class EqGroupSizeComparator implements Comparator<EquivalenceSet> { /** * compare by size , then (if size equal) by hashcode * * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ @SuppressWarnings("unchecked") public int compare(EquivalenceSet arg1, EquivalenceSet arg2) { int eqGroupSize1 = arg1.size(); int eqGroupSize2 = arg2.size(); if (eqGroupSize1 > eqGroupSize2) { return 1; } else if (eqGroupSize1 < eqGroupSize2) { return -1; } else { // size equal , compare hashcodes int eqGroupHash1 = arg1.hashCode(); int eqGroupHash2 = arg2.hashCode(); if (eqGroupHash1 > eqGroupHash2) { return 1; } else if (eqGroupHash1 < eqGroupHash2) { return -1; } else { return 0; } } } } } // End EquivalenceSetCreator.java