/*
* Author: tdanford
* Date: Oct 31, 2008
*/
package org.seqcode.gseutils.graphs;
import java.io.*;
import java.util.*;
import org.seqcode.gseutils.SetTools;
public class DirectedMultiGraph implements MultiGraph {
private static SetTools<String> tools;
static {
tools = new SetTools<String>();
}
private HashSet<String> nodes;
private Set<String> tags;
// node -> outgoing/incoming -> tags
private Map<String,Map<String,Set<String>>> edges, parents;
public DirectedMultiGraph() {
nodes = new HashSet<String>();
tags = new TreeSet<String>();
edges = new HashMap<String,Map<String,Set<String>>>();
parents = new HashMap<String,Map<String,Set<String>>>();
}
public DirectedMultiGraph(DirectedGraph dg, String t) {
tags = new TreeSet<String>();
tags.add(t);
nodes = new HashSet<String>(dg.getVertices());
edges = new HashMap<String,Map<String,Set<String>>>();
parents = new HashMap<String,Map<String,Set<String>>>();
for(String v : nodes) {
edges.put(v, new TreeMap<String,Set<String>>());
parents.put(v, new TreeMap<String,Set<String>>());
for(String p : dg.getParents(v)) {
parents.get(v).put(p, new HashSet<String>());
parents.get(v).get(p).add(t);
}
for(String n : dg.getNeighbors(v)) {
edges.get(v).put(n, new HashSet<String>());
edges.get(v).get(n).add(t);
}
}
}
public void printGraph(PrintStream ps) {
TreeSet<String> nodesOrdered = new TreeSet<String>(nodes);
for(String n : nodesOrdered) {
ps.print(n + " : ( ");
for(String nn : edges.get(n).keySet()) {
for(String tag : edges.get(n).get(nn)) {
ps.print(String.format("%s:%s ", nn, tag));
}
}
ps.println(")");
}
}
public void addVertex(String v) {
if(!nodes.contains(v)) {
nodes.add(v);
edges.put(v, new TreeMap<String,Set<String>>());
parents.put(v, new TreeMap<String,Set<String>>());
}
}
public void addEdge(String v1, String v2, String t) {
if(nodes.contains(v1) && nodes.contains(v2)) {
if(!edges.get(v1).containsKey(v2)) {
edges.get(v1).put(v2, new HashSet<String>());
}
if(!parents.get(v2).containsKey(v1)) {
parents.get(v2).put(v1, new HashSet<String>());
}
edges.get(v1).get(v2).add(t);
parents.get(v2).get(v1).add(t);
tags.add(t);
}
}
public void removeEdge(String v1, String v2, String t) {
if(containsEdge(v1, v2)) {
if(edges.get(v1).containsKey(v2)) {
edges.get(v1).get(v2).remove(t);
if(parents.get(v1).get(v2).isEmpty()) {
parents.get(v1).remove(v2);
}
}
if(parents.get(v2).containsKey(v1)) {
parents.get(v2).get(v1).remove(t);
if(parents.get(v2).get(v1).isEmpty()) {
parents.get(v2).remove(v1);
}
}
rebuildTags();
}
}
public void removeVertex(String n) {
if(nodes.contains(n)) {
nodes.remove(n);
parents.remove(n);
edges.remove(n);
for(String k : edges.keySet()) {
if(parents.get(k).containsKey(n)) {
parents.get(k).remove(n);
}
if(edges.get(k).containsKey(n)) {
edges.get(k).remove(n);
}
}
rebuildTags();
}
}
private void rebuildTags() {
tags.clear();
for(String v1 : nodes) {
for(String v2 : edges.get(v1).keySet()) {
tags.addAll(edges.get(v1).get(v2));
}
}
}
public boolean isNeighbor(String v, String n) { return containsEdge(v, n); }
public boolean containsEdge(String v1, String v2) {
return edges.get(v1).containsKey(v2);
}
public boolean containsEdge(String v1, String v2, String t) {
return tags.contains(t) &&
edges.get(v1).containsKey(v2) && edges.get(v1).get(v2).contains(t);
}
public Set<String> getAncestors(String vertex) {
Set<String> searched = new HashSet<String>();
LinkedList<String> pending = new LinkedList<String>();
pending.addAll(parents.get(vertex).keySet());
while(!pending.isEmpty()) {
String cv = pending.removeFirst();
searched.add(cv);
Set<String> ns = tools.subtract(parents.get(cv).keySet(), searched);
ns.removeAll(pending);
pending.addAll(ns);
}
return searched;
}
public Set<String> getDescendants(String vertex) {
Set<String> searched = new HashSet<String>();
LinkedList<String> pending = new LinkedList<String>();
pending.addAll(edges.get(vertex).keySet());
while(!pending.isEmpty()) {
String cv = pending.removeFirst();
searched.add(cv);
Set<String> ns = tools.subtract(edges.get(cv).keySet(), searched);
ns.removeAll(pending);
pending.addAll(ns);
}
return searched;
}
public Set<String> getRoots() {
HashSet<String> roots = new HashSet<String>();
for(String node : nodes) {
if(parents.get(node).size() == 0) {
roots.add(node);
}
}
return roots;
}
public Set<String> getVertices() {
return new HashSet<String>(nodes);
}
public Set<String> getParents(String vertex) {
return parents.get(vertex).keySet();
}
public Set<String> getNeighbors(String vertex) {
return edges.get(vertex).keySet();
}
public Set<String> getNeighbors(String vertex, String tag) {
TreeSet<String> ns = new TreeSet<String>();
for(String v2 : edges.get(vertex).keySet()) {
if(edges.get(vertex).get(v2).contains(tag)) {
ns.add(v2);
}
}
return ns;
}
public Set<String> getTags() {
return tags;
}
public boolean isNeighbor(String v, String n, String tag) {
return edges.containsKey(v) && edges.get(v).containsKey(n) && edges.get(v).get(n).contains(tag);
}
public Set<String> findNeighborTags(String v1, String v2) {
if(edges.containsKey(v1) && edges.get(v1).containsKey(v2)) {
return edges.get(v1).get(v2);
} else {
return new TreeSet<String>();
}
}
}