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

org.aksw.jena_sparql_api.views.EquiMap Maven / Gradle / Ivy

The newest version!
package org.aksw.jena_sparql_api.views;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.aksw.commons.collections.multimaps.BiHashMultimap;
import org.aksw.commons.collections.multimaps.IBiSetMultimap;
import org.aksw.commons.collections.multimaps.MultimapUtils;

import com.google.common.collect.Sets;


/**
 * A map where keys can be stated as equivalent.
 * 
 * Provides methods for checking consistency (the map gets inconsistent
 * as soon as a key maps to multiple non-equal values)
 * 
 * 
 * TODO Not sure if a conflict resultion strategy for the case that
 * values are not directly equal but not contradictory should go here.
 * For instance if a key x maps to {A, B} and y maps to {A} one resolution stragtegy
 * might be to map both to A.
 * 
 * Essentially I have the ValueSets in mind to quickly reject inconsistent bindings.
 * 
 * @author raven
 *
 * @param 
 * @param 
 */
public class EquiMap
{
	private IBiSetMultimap equivalences = new BiHashMultimap();
	private Map keyToValue = new HashMap();
	
	
	
	/**
	 * 
	 * @return A view of all keys
	 */
	public Set keySet() {
		return Sets.union(equivalences.asMap().keySet(), keyToValue.keySet());
	}
	
	public void clear()
	{
		equivalences.clear();
		keyToValue.clear();
	}
	
	public boolean isEqual(K a, K b) {
		return get(a).contains(b);
	}
	
	public boolean areAllEqual(Collection set) {
		if(set.isEmpty()) {
			return true; // Is that sane? Should it be false?
		}
		
		return get(set.iterator().next()).containsAll(set);
	}

	
	public boolean isConsistentInsertEquiv(K a, K b)
	{
		return isConsistentSet(Sets.union(get(a), get(b)));
	}
	
	public boolean isConsistentSet(Set set)
	{
		return set.size() <= 1;
	}
	
	public boolean isConsistentInsertValue(K a, V b)
	{
		Set values = get(a);
		
		if(values.isEmpty()) {
			return true;
		} else if(values.size() == 1 && values.contains(b)) {
			return true;
		} else if(values.size() > 1) {
			throw new RuntimeException("Should not happen");
		}
		
		return false;
	}
	
	public boolean isSelfConsistent()
	{
		Set open = new HashSet(keyToValue.keySet());
		while(!open.isEmpty()) {
			K key = open.iterator().next();
			open.remove(key);

			Set keys = getEquivalences(key, false);
			open.removeAll(keys);
			
			Set values = get(keys);
			if(!isConsistentSet(values)) {
				return false;
			}
		}			
			
		return true;
	}

	
	public EquiMap()
	{
	}
	
	public EquiMap(EquiMap other)
	{		
		for(Map.Entry> entry : equivalences.asMap().entrySet()) {
			for(K value : entry.getValue()) {
				this.equivalences.put(entry.getKey(), value);
			}
		}
		
		
		this.keyToValue.putAll(other.keyToValue);
	}
	
	
	public IBiSetMultimap getEquivalences()
	{
		return equivalences;
	}

	public Map getKeyToValue()
	{
		return keyToValue;
	}

	
	public void put(K key, V value)
	{
		keyToValue.put(key, value);
	}
	
	public Set getAll(Set keys)
	{
		Set result = new HashSet();

		for(Object key : keys) {
			if(keyToValue.containsKey(key)) {
				result.add(keyToValue.get(key));
			}
		}
		
		return result;		
	}
	
	public Set getEquivalences(Object key, boolean reflexiv)
	{
		Set result = MultimapUtils.transitiveGetBoth(equivalences, key);
		if(reflexiv) {
			result.add((K)key);
		}
		
		return result;
	}
	
	public Set getAllEquivalences(Collection keys, boolean reflexiv)
	{
		Set result = new HashSet();

		Set open = new HashSet(keys);
		while(!open.isEmpty()) {
			Object key = open.iterator().next();
			open.remove(key);

			Set equivs = getEquivalences(key, reflexiv);
			open.removeAll(equivs);
			
			result.addAll(equivs);			
		}			

		return result;
	}


	public Set get(Object key)
	{
		return getAll(getEquivalences(key, true));		
	}

	public boolean makeEqual(K a, K b)
	{
		return equivalences.put(a, b);
	}
	
	
	/**
	 * Checks whether the union of two equimaps is again consistent.
	 * 
	 * 
	 * @param other
	 * @return
	 */
	public boolean isCompatible(EquiMap other)
	{
		// We have to check whether any of the keys refer to multiple distinct variables
		// So we need to check for each key that has a value attached
		Set open = new HashSet(keyToValue.keySet());				

		while(!open.isEmpty()) {
			K key = open.iterator().next();
			open.remove(key);
			
			Set bothEquivs = new HashSet();
			//bothEquivs.add(key); redundant
			
			// We need to traverse the bipartite graph is order to collect 
			// all equivalences
			//
			//
			Set newEquivs = Collections.singleton(key);
			do {
				Set thisEquivs = getAllEquivalences(newEquivs, true);
				thisEquivs.removeAll(bothEquivs);
				open.removeAll(thisEquivs);
				bothEquivs.addAll(thisEquivs);				
		
				newEquivs = other.getAllEquivalences(thisEquivs, true);
				newEquivs.removeAll(bothEquivs);
				open.removeAll(newEquivs);
				
				bothEquivs.addAll(newEquivs);				
				
			} while(!newEquivs.isEmpty());
				
			Set thisValues = getAll(bothEquivs);
			Set otherValues = other.getAll(bothEquivs);

			Set union = Sets.union(thisValues, otherValues);

			if(!isConsistentSet(union)) {
				return false;
			}
		}
		
		return true;
	}

	@Override
	public String toString()
	{
		return "[equivalences=" + equivalences + ", keyToValue="
				+ keyToValue + "]";
	}
	
}