All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.gluebooster.java.booster.basic.container.ComparatorBoostUtils Maven / Gradle / Ivy

package net.sf.gluebooster.java.booster.basic.container;

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.lang3.tuple.Pair;

import net.sf.gluebooster.java.booster.basic.math.graph.BoostedNodeGraph;
import net.sf.gluebooster.java.booster.essentials.meta.BoostedComparator;

/**
 * Utility methods for comparators.
 * 
 * @author CBauer
 * @defaultParamText o1 the first object
 * @defaultParamText o2 the second object
 *
 */
@SuppressWarnings("rawtypes")
public class ComparatorBoostUtils implements
		BoostedComparator {

	/**
	 * The compare-algorithm should be a comparision of elements
	 */
	private static final int COMPARE_BY_ELEMENT_VALUES = 1;

	/**
	 * The compare-algorithm should be a comparision of PAIRS
	 */
	private static final int COMPARE_PAIRS = 2;
	/**
	 * The comparator knows the immediate predecessors of an element
	 */
	private static final int COMPARE_BY_GRAPH_ORDERING = 3;

	private static final int COMPARE_WITH_STRING_DEFAULT = 4;

	/**
	 * The type/algorithm of the comparision
	 */
	private int type;

	/**
	 * Maps classes to integers (that are used for comparison).
	 */
	private Map elementValues;

	/**
	 * Transforms classes into pairs
	 */
	private Transformer pairTransformer;
	/**
	 * One comparator.
	 */
	private Comparator comparator1;
	/**
	 * Another comparator.
	 */
	private Comparator comparator2;

	/**
	 * Should a left element be compared with a right element.
	 */
	private Boolean compareLeftWithRight;
	/**
	 * The graph containing an order. There is an edge from a to b if a <= b. If a == b then there must be to edges, one from a to b and on from b to a
	 * 
	 */
	private BoostedNodeGraph ordering;
	/**
	 * A mapping of the elements/velue to the corresponding node in the ordering graph.
	 */
	private Map nodeMapping;

	private ComparatorBoostUtils(int type) {
		this.type = type;
	}

	/**
	 * Compares objects by using a graph map with the immediate predecessor of the elements
	 * 
	 * @param immediatePredecessors
	 *            mapping lower object to higher object
	 * @return the created comparator
	 */
	public static > BoostedComparator createComparatorByImmediatePredecessors(
			Map immediatePredecessors) throws Exception {
		ComparatorBoostUtils result = new ComparatorBoostUtils(
				COMPARE_BY_GRAPH_ORDERING);
		result.ordering = new BoostedNodeGraph();
		result.nodeMapping = new HashMap();
		for (Entry entry : immediatePredecessors.entrySet()) {
			result.addNodeToOrderingIfNonExistent(entry.getKey());
			result.addNodesToOrderingIfNonExistent(entry.getValue());
			BoostedNode source = result.nodeMapping.get(entry.getKey());
			for (T target : entry.getValue()) {
				result.ordering.addEdge(result.nodeMapping.get(target), source);
			}
		}
		// result.ordering.simpleDisplay();
		return result;
	}

	/**
	 * Creates a new node for a given value in the ordering graph when necessary
	 * 
	 * @param value
	 *            the value that is to be put into the ordering graph
	 * @return true, if added (= if the value did not exist in the ordering graph before)
	 */
	private boolean addNodeToOrderingIfNonExistent(ComparedClass value) {
		if (nodeMapping.containsKey(value)) {
			return false;
		} else {
			BoostedNode node = ordering.addNodeWithValue(value);
			nodeMapping.put(value, node);
			return true;
		}
	}

	/**
	 * Creates new nodes for given values in the ordering graph when necessary
	 * 
	 * @param values
	 *            the values that are to be put into the ordering graph
	 * @return true, if at least one value has been added added (= if the value did not exist in the ordering graph before)
	 */
	private boolean addNodesToOrderingIfNonExistent(
			Collection values) {
		boolean result = false;
		for (ComparedClass value : values) {
			result |= addNodeToOrderingIfNonExistent(value);
		}
		return result;
	}

	/**
	 * Creates a comparator by comparing the positions in a given list
	 * 
	 * @param ordering
	 *            the list with the ordering
	 * @return the created comparator
	 */
	public static  BoostedComparator createComparatorByListPosition(
			List ordering) {
		ComparatorBoostUtils result = new ComparatorBoostUtils(
				COMPARE_BY_ELEMENT_VALUES);
		result.elementValues = new HashMap();
		for (int i = ordering.size() - 1; i >= 0; i--) {
			result.elementValues.put(ordering.get(i), i);
		}

		return result;
	}

	/**
	 * Creates a comparator by comparing the positions in a given list
	 * 
	 * @param ordering
	 *            the list with the ordering
	 * @return the created comparator
	 */
	public static  BoostedComparator createComparatorWithStringAsDefault() {
		ComparatorBoostUtils result = new ComparatorBoostUtils(COMPARE_WITH_STRING_DEFAULT);
		return result;
	}

	/**
	 * Creates a comparator that transforms objects into pairs which are compared. The left and right values are compared separately. There is only a compare
	 * result when both parts have the same result. Then the result is returned.
	 * 
	 * @param pairTransformer
	 *            creates a pair from a value
	 * @param leftComparator
	 *            compares the left side of the pair
	 * @param rightComparator
	 *            compares the right side of the pair.
	 * @return the created comparator
	 */
	public static  BoostedComparator createPairComparator(
			Transformer pairTransformer, Comparator leftComparator,
			Comparator rightComparator) {
		ComparatorBoostUtils result = new ComparatorBoostUtils(
				COMPARE_PAIRS);
		result.pairTransformer = pairTransformer;
		result.comparator1 = leftComparator;
		result.comparator2 = rightComparator;
		result.compareLeftWithRight = Boolean.FALSE;
		return result;

	}

	/**
	 * Creates a comparator that transforms objects into pairs which are compared. The left and right values are compared separately. Optionally separately
	 * crosswise (left with right) comparisons may be done. There is only a compare result when all parts have the same result. Then the result is returned.
	 * 
	 * @param pairTransformer
	 *            creates a pair from a value
	 * @param comparator
	 *            compares the sides of the pair
	 * @param compareLeftWithRight
	 *            should additionally a crosswise comparison be considered
	 * @return the created comparator
	 */
	public static  BoostedComparator createPairComparator(
			Transformer pairTransformer, Comparator comparator,
			boolean compareLeftWithRight) {
		ComparatorBoostUtils result = new ComparatorBoostUtils(
				COMPARE_PAIRS);
		result.pairTransformer = pairTransformer;
		result.comparator1 = comparator;
		result.comparator2 = comparator;
		result.compareLeftWithRight = compareLeftWithRight;
		return result;

	}

	/**
	 * Compares two objects by using a comparator
	 * 
	 * @param comparator
	 *            does the comparison. May be a BoostedComparator
	 * @return null if the boostedcomparator throws an exception
	 */
	public static  Integer compare(E o1, E o2, Comparator comparator) {
		if (comparator instanceof BoostedComparator) {
			try {
				return comparator.compare(o1, o2);
			} catch (IllegalStateException ex) {
				// this execption expresses that no comparison can be done.
				return null;
			}
		} else {
			return comparator.compare(o1, o2);
		}
	}

	@Override
	public int compare(ComparedClass o1, ComparedClass o2) {

		switch (type) {
		case COMPARE_BY_ELEMENT_VALUES:
			return compareByElementValues(o1, o2);
		case COMPARE_PAIRS:
			return comparePairs(o1, o2);
		case COMPARE_BY_GRAPH_ORDERING:
			return compareByGraphOrdering(o1, o2);
		case COMPARE_WITH_STRING_DEFAULT:
			if (o1 instanceof Comparable) {
				return ((Comparable) o1).compareTo(o2);
			} else {
				return ("" + o1).compareTo("" + o2);
			}
		default:
			throw new UnsupportedOperationException("compare type " + type
					+ " not yet supported");
		}

	}

	/**
	 * Returns an exception that states the the two objects can not be compared
	 * 
	 * @param info
	 *            info why the comparison is not possible
	 * @return the created exception
	 */
	private IllegalStateException createCouldNotCompare(ComparedClass o1,
			ComparedClass o2, String info) {
		if (info == null) {
			info = "";
		}
		return new IllegalStateException("could not compare " + o1 + " and "
				+ o2 + "  " + info);
	}

	/**
	 * Compares two object by anaylzing their position in a graph.
	 * 
	 * @return o1 is less than o2 if o1 is a predecessor of o2.
	 */
	private int compareByGraphOrdering(ComparedClass o1,ComparedClass o2) {

		BoostedNode node1 = nodeMapping.get(o1);
		BoostedNode node2 = nodeMapping.get(o2);
		boolean o1BeforeO2 = ordering.isWalk(node1, node2);
		boolean o2BeforeO1 = ordering.isWalk(node2, node1);

		if (o1BeforeO2 && o2BeforeO1) {
			return 0;
		} else if (o1BeforeO2) {
			return -1;
		} else if (o2BeforeO1) {
			return 1;
		} else {
			throw createCouldNotCompare(o1, o2, null);
		}
	}

	/**
	 * Compares by comparing the integers of the corrseponding element values.
	 * 
	 * @return the comparison result
	 */
	private int compareByElementValues(ComparedClass o1, ComparedClass o2) {
		Integer i1 = elementValues.get(o1);
		Integer i2 = elementValues.get(o2);

		if (i1 == null || i2 == null) {
			throw createCouldNotCompare(o1, o2,
					"because not all element values are present");
		} else {
			return i1.compareTo(i2);
		}
	}

	/**
	 * Compares by transforming the objects into pairs which are compared.
	 * 
	 * The left and right values are compared separately. Optionally separately crosswise (left with right) comparisons may be done. There is only a compare
	 * result when all parts have the same result. Then the result is returned.
	 * 
	 * @return the result of the comparison
	 */
	private int comparePairs(ComparedClass o1, ComparedClass o2) {
		Pair pair1 = pairTransformer.transform(o1);
		Pair pair2 = pairTransformer.transform(o2);

		if (pair1.equals(pair2))
			return 0;

		Integer leftCompare = compare(pair1.getLeft(), pair2.getLeft(),
				comparator1);
		Integer rightCompare = compare(pair1.getRight(), pair2.getRight(),
				comparator2);
		Integer leftRightCompare = null;
		Integer rightLeftCompare = null;
		if (Boolean.TRUE.equals(compareLeftWithRight)) {
			leftRightCompare = compare(pair1.getLeft(), pair2.getRight(),
					comparator1);
			rightLeftCompare = compare(pair1.getRight(), pair2.getLeft(),
					comparator1);
		}
		
		// if the sign of all comparisons is equal or 0 or null return the sign
		// as result
		// if all is null nothing is known
		// if different signs occur nothing is known
		Integer result = null;
		result = computeSign(result, leftCompare);
		result = computeSign(result, rightCompare);
		result = computeSign(result, leftRightCompare);
		result = computeSign(result, rightLeftCompare);
		
		if (result == null || result.intValue() == 0) {
			throw createCouldNotCompare(o1, o2, " pairs are " + pair1 + " "
					+ pair2);
		} else {
			return result.intValue();
		}
		
	}

	/**
	 * Checks whether two signs are equal
	 * 
	 * @param oldCompare
	 *            the first sign (the original sign)
	 * @param compareValue
	 *            the second sign (the current sign)
	 * @return the compareValue if no changes happened or the oldCompare is null; old compare if the compareValue is 0 or not known
	 * @throws IllegalStateException
	 *             if the signs are different
	 */
	private static Integer computeSign(Integer oldCompare, Integer compareValue)
			throws IllegalStateException {
		if (oldCompare == null)
			return compareValue;
		if (compareValue == null || compareValue.intValue() == 0)
			return oldCompare;
		if (Math.signum(oldCompare) * Math.signum(compareValue) >= 0) { // equal
																		// or 0
			return compareValue; // because it is not 0
		} else {
			throw new IllegalStateException("comparison not possible");
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy