/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package automenta.spacenet.var.graph;
import edu.uci.ics.jung.graph.Hypergraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.graph.util.Pair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
*
* @author seh
*/
public class MemGraph<V,H> implements BufferedGraph<V, H>, Hypergraph<V,H>, edu.uci.ics.jung.graph.Graph<V,H> {
protected final Map<V, Set<H>> nodes; // Map of vertices to incident hyperedge sets
protected final Map<H, List<V>> edges; // Map of hyperedges to incident vertex sets
protected final Map<H, EdgeType> edgeTypes;
private final List<IfGraphChanges<V,H>> ifChanges = new LinkedList();
/** creates empty graph */
public MemGraph() {
super();
nodes = new ConcurrentHashMap();
edges = new ConcurrentHashMap();
edgeTypes = new ConcurrentHashMap();
}
/** creates graph from a JUNG hypergraph */
public MemGraph(Hypergraph<V,H> jungGraph) {
this();
for (V v : jungGraph.getVertices()) {
addNode(v);
}
for (H h : jungGraph.getEdges()) {
EdgeType type = jungGraph.getEdgeType(h);
Collection<V> eNodes = jungGraph.getIncidentVertices(h);
addEdge(h, type, eNodes);
}
}
public void clear() {
ArrayList<V> nodeList = new ArrayList<V>(getNodes());
ArrayList<H> edgeList = new ArrayList<H>(getEdges());
for (H h : edgeList) {
removeEdge(h);
}
for (V v : nodeList) {
removeNode(v);
}
// nodes.clear();
// edges.clear();
edgeTypes.clear();
}
public H addEdge(H h, List<V> v) {
return addEdge(h, EdgeType.DIRECTED, v);
}
/**
* Adds <code>hyperedge</code> to this graph and connects them to the vertex collection <code>to_attach</code>.
* Any vertices in <code>to_attach</code> that appear more than once will only appear once in the
* incident vertex collection for <code>hyperedge</code>, that is, duplicates will be ignored.
*
* @see Hypergraph#addEdge(Object, Collection)
*/
public H addEdge(H hyperedge, EdgeType e, Collection<V> vList) {
if (hyperedge == null)
throw new IllegalArgumentException("input hyperedge may not be null");
// Set<V> new_endpoints = new HashSet<V>(to_attach);
//TODO check for duplicate edge
if (edges.containsKey(hyperedge))
{
List<V> attached = edges.get(hyperedge);
if (!attached.equals(vList)) {
throw new IllegalArgumentException("Edge " + hyperedge +
" exists in this graph with endpoints " + attached);
}
else
return null;
}
edges.put(hyperedge, new ArrayList( vList ));
for (V v : vList) {
// add v if it's not already in the graph
addNode(v);
// associate v with hyperedge
this.nodes.get(v).add(hyperedge);
}
edgeTypes.put(hyperedge, e);
for (IfGraphChanges ic : ifChanges) {
ic.edgeAdded(this, hyperedge);
}
return hyperedge;
}
/**
* @see Hypergraph#getEdgeType(Object)
*/
@Override public EdgeType getEdgeType(H edge) {
if (containsEdge(edge))
return edgeTypes.get(edge);
else
return null;
}
public boolean containsNode(V node) {
return nodes.keySet().contains(node);
}
public boolean containsEdge(H edge) {
return edges.keySet().contains(edge);
}
@Override public Collection<H> getEdges() {
return edges.keySet();
}
@Override public Collection<V> getNodes() {
return nodes.keySet();
}
public int getEdgeCount()
{
return edges.size();
}
public int getNodeCount()
{
return nodes.size();
}
@Override public Collection<V> getNeighbors(V node) {
if (!containsNode(node))
return null;
Set<V> neighbors = new HashSet<V>();
for (H hyperedge : nodes.get(node)) {
neighbors.addAll(edges.get(hyperedge));
}
return neighbors;
}
@Override public Collection<H> getIncidentEdges(V node) {
return nodes.get(node);
}
@Override public List<V> getIncidentVertices(H edge) {
return edges.get(edge);
}
public H findEdge(V v1, V v2) {
if (!containsNode(v1) || !containsNode(v2))
return null;
for (H h : getIncidentEdges(v1))
{
if (isIncident(v2, h))
return h;
}
return null;
}
public Collection<H> findEdgeSet(V v1, V v2) {
if (!containsNode(v1) || !containsNode(v2))
return null;
Collection<H> edges = new ArrayList<H>();
for (H h : getIncidentEdges(v1))
{
if (isIncident(v2, h))
edges.add(h);
}
return Collections.unmodifiableCollection(edges);
}
@Override public V addNode(V node) {
if(node == null)
throw new IllegalArgumentException("cannot add a null vertex");
if (containsNode(node))
return null;
nodes.put(node, new HashSet<H>());
for (IfGraphChanges ic : ifChanges) {
ic.nodeAdded(this, node);
}
return node;
}
@Override public boolean removeNode(V node) {
if (!containsNode(node))
return false;
for (H hyperedge : nodes.get(node)) {
edges.get(hyperedge).remove(node);
}
nodes.remove(node);
for (IfGraphChanges ic : ifChanges) {
ic.nodeRemoved(this, node);
}
return true;
}
@Override public boolean removeEdge(H hyperedge) {
if (!containsEdge(hyperedge))
return false;
for (V vertex : edges.get(hyperedge))
{
nodes.get(vertex).remove(hyperedge);
}
edges.remove(hyperedge);
edgeTypes.remove(hyperedge);
for (IfGraphChanges ic : ifChanges) {
ic.edgeRemoved(this, hyperedge);
}
return true;
}
public boolean isNeighbor(V v1, V v2) {
if (!containsNode(v1) || !containsNode(v2))
return false;
if (nodes.get(v2).isEmpty())
return false;
for (H hyperedge : nodes.get(v1))
{
if (edges.get(hyperedge).contains(v2))
return true;
}
return false;
}
public boolean isIncident(V vertex, H edge) {
if (!containsNode(vertex) || !containsEdge(edge))
return false;
return nodes.get(vertex).contains(edge);
}
public int degree(V vertex) {
if (!containsNode(vertex))
return 0;
return nodes.get(vertex).size();
}
public int getNeighborCount(V vertex) {
if (!containsNode(vertex))
return 0;
return getNeighbors(vertex).size();
}
public int getIncidentCount(H edge) {
if (!containsEdge(edge))
return 0;
return edges.get(edge).size();
}
public int getEdgeCount(EdgeType edge_type) {
if (edge_type == EdgeType.UNDIRECTED)
return edges.size();
return 0;
}
@Override public Collection<H> getEdges(EdgeType edge_type) {
if (edge_type == EdgeType.UNDIRECTED)
return edges.keySet();
return null;
}
public EdgeType getDefaultEdgeType() {
return EdgeType.UNDIRECTED;
}
@Override public Collection<H> getInEdges(V vertex) {
return getIncidentEdges(vertex);
}
public Collection<H> getOutEdges(V vertex) {
return getIncidentEdges(vertex);
}
public int inDegree(V vertex)
{
return degree(vertex);
}
public int outDegree(V vertex)
{
return degree(vertex);
}
public V getDest(H h) {
List<V> vc = edges.get(h);
return vc.get(vc.size()-1);
}
public V getSource(H h) {
List<V> vc = edges.get(h);
return vc.get(0);
}
public Collection<V> getPredecessors(V vertex)
{
return getNeighbors(vertex);
}
public Collection<V> getSuccessors(V vertex)
{
return getNeighbors(vertex);
}
@Override public H addEdge(H edge, EdgeType edgeType, V... vList) {
addEdge(edge, edgeType, Arrays.asList(vList));
return edge;
}
public void addEdge(H edge, V... vList) {
addEdge(edge, EdgeType.DIRECTED, Arrays.asList(vList));
}
@Override public void add(IfGraphChanges ic) {
ifChanges.add(ic);
notifyAll(ic);
}
@Override public void remove(IfGraphChanges<V,H> ic) {
ifChanges.remove(ic);
}
/** notify existing nodes & edges*/
private void notifyAll(IfGraphChanges<V,H> ic) {
for (V v : getNodes()) {
ic.nodeAdded(this, v);
}
for (H h : getEdges()) {
ic.edgeAdded(this, h);
}
}
@Override
public Iterator<H> iterateEdges() {
return getEdges().iterator();
}
@Override
public Iterator<V> iterateNodes() {
return getNodes().iterator();
}
@Override
public String toString() {
return "n{" + getNodes() + "}, e{" + getEdges() + "}";
}
@Deprecated @Override
public Collection<V> getVertices() {
return getNodes();
}
@Deprecated @Override
public boolean containsVertex(V v) {
return containsNode(v);
}
@Deprecated @Override
public int getVertexCount() {
return getNodeCount();
}
@Deprecated @Override
public boolean addVertex(V arg0) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Deprecated @Override
public boolean addEdge(H arg0, Collection<? extends V> arg1) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Deprecated @Override
public boolean addEdge(H arg0, Collection<? extends V> arg1, EdgeType arg2) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public boolean removeVertex(V arg0) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public boolean isPredecessor(V b, V a) {
return getPredecessors(a).contains(b);
}
@Override
public boolean isSuccessor(V b, V a) {
return getSuccessors(a).contains(b);
}
@Override
public int getPredecessorCount(V a) {
return getPredecessors(a).size();
}
@Override
public int getSuccessorCount(V a) {
return getSuccessors(a).size();
}
@Override
public boolean isSource(V v, H h) {
return getSource(h) == v;
}
@Override
public boolean isDest(V v, H h) {
return getDest(h) == v;
}
@Override
public boolean addEdge(H h, V a, V b) {
LinkedList<V> ll = new LinkedList<V>();
ll.add(a);
ll.add(b);
this.addEdge(h, ll);
return true;
}
@Deprecated @Override
public boolean addEdge(H h, V a, V b, EdgeType t) {
LinkedList<V> ll = new LinkedList<V>();
ll.add(a);
ll.add(b);
this.addEdge(h, t, ll);
return true;
}
@Override
public Pair<V> getEndpoints(H h) {
return new Pair<V>(getSource(h), getDest(h));
}
@Override
public V getOpposite(V v, H h) {
if (getSource(h) == v)
return getDest(h);
else
return getSource(h);
}
public void addGraph(MemGraph<V,H> g) {
for (V v : g.getNodes()) {
addNode(v);
}
for (H h : g.getEdges()) {
//TODO this assumes the 'g' is not hypergraph.. remove this assumption/limitation
addEdge(h, g.getEndpoints(h).getFirst(), g.getEndpoints(h).getSecond());
}
}
}