/*******************************************************************************
* Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tamas Szabo - initial API and implementation
*******************************************************************************/
package org.eclipse.incquery.runtime.base.itc.alg.dred;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.incquery.runtime.base.itc.alg.misc.ITcRelation;
public class DRedTcRelation<V> implements Serializable, ITcRelation<V> {
private static final long serialVersionUID = 1L;
// tc(a,b) means that b is transitively reachable from a
private Map<V, Set<V>> tuplesForward;
// data structure to efficiently get those nodes from which a given node is reachable
// symmetric to tuplesForward
private Map<V, Set<V>> tuplesBackward;
public DRedTcRelation() {
this.tuplesForward = new HashMap<V, Set<V>>();
this.tuplesBackward = new HashMap<V, Set<V>>();
}
public void clear() {
this.tuplesForward.clear();
this.tuplesBackward.clear();
}
public boolean isEmpty() {
return tuplesForward.isEmpty();
}
public void removeTuple(V source, V target) {
// removing tuple from 'forward' tc relation
Set<V> sSet = tuplesForward.get(source);
if (sSet != null) {
sSet.remove(target);
if (sSet.size() == 0)
tuplesForward.remove(source);
}
// removing tuple from 'backward' tc relation
Set<V> tSet = tuplesBackward.get(target);
if (tSet != null) {
tSet.remove(source);
if (tSet.size() == 0)
tuplesBackward.remove(target);
}
}
/**
* Returns true if the tc relation did not contain previously such a tuple that is defined by (source,target), false
* otherwise.
*
* @param source
* the source of the tuple
* @param target
* the target of the tuple
* @return true if the relation did not contain previously the tuple
*/
public boolean addTuple(V source, V target) {
// symmetric modification, it is sufficient to check the return value in one collection
// adding tuple to 'forward' tc relation
Set<V> sSet = tuplesForward.get(source);
if (sSet == null) {
Set<V> newSet = new HashSet<V>();
newSet.add(target);
tuplesForward.put(source, newSet);
} else {
sSet.add(target);
}
// adding tuple to 'backward' tc relation
Set<V> tSet = tuplesBackward.get(target);
if (tSet == null) {
Set<V> newSet = new HashSet<V>();
newSet.add(source);
tuplesBackward.put(target, newSet);
return true;
} else {
boolean ret = tSet.add(source);
return ret;
}
}
/**
* Union operation of two tc realtions.
*
* @param rA
* the other tc relation
*/
public void union(DRedTcRelation<V> rA) {
for (V source : rA.tuplesForward.keySet()) {
for (V target : rA.tuplesForward.get(source)) {
this.addTuple(source, target);
}
}
}
/**
* Computes the difference of this tc relation and the given rA parameter.
*
* @param rA
* the subtrahend relation
*/
public void difference(DRedTcRelation<V> rA) {
for (V source : rA.tuplesForward.keySet()) {
for (V target : rA.tuplesForward.get(source)) {
this.removeTuple(source, target);
}
}
}
@Override
public Set<V> getTupleEnds(V source) {
Set<V> t = tuplesForward.get(source);
return (t == null) ? new HashSet<V>() : new HashSet<V>(t);
}
/**
* Returns the set of nodes from which the target node is reachable.
*
* @param target
* the target node
* @return the set of source nodes
*/
public Set<V> getTupleStarts(V target) {
Set<V> t = tuplesBackward.get(target);
return (t == null) ? new HashSet<V>() : new HashSet<V>(t);
}
@Override
public Set<V> getTupleStarts() {
Set<V> t = tuplesForward.keySet();
return new HashSet<V>(t);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("TcRelation = ");
for (V source : this.tuplesForward.keySet()) {
for (V target : this.tuplesForward.get(source)) {
sb.append("(" + source + "," + target + ") ");
}
}
return sb.toString();
}
/**
* Returns true if a (source, target) node is present in the transitive closure relation, false otherwise.
*
* @param source
* the source node
* @param target
* the target node
* @return true if tuple is present, false otherwise
*/
public boolean containsTuple(V source, V target) {
if (tuplesForward.containsKey(source)) {
if (tuplesForward.get(source).contains(target))
return true;
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if ((obj == null) || (obj.getClass() != this.getClass())) {
return false;
}
DRedTcRelation<V> aTR = (DRedTcRelation<V>) obj;
for (V source : aTR.tuplesForward.keySet()) {
for (V target : aTR.tuplesForward.get(source)) {
if (!this.containsTuple(source, target))
return false;
}
}
for (V source : this.tuplesForward.keySet()) {
for (V target : this.tuplesForward.get(source)) {
if (!aTR.containsTuple(source, target))
return false;
}
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + tuplesForward.hashCode();
hash = 31 * hash + tuplesBackward.hashCode();
return hash;
}
public Map<V, Set<V>> getTuplesForward() {
return tuplesForward;
}
}