com.factor18.oss.DAG Maven / Gradle / Ivy
The newest version!
package com.factor18.oss;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class DAG, P> {
public DAG() {
this.traverser = new Traverser();
}
public boolean addVertex(V vertex) {
if(this.vertices.contains(vertex)) {
return false;
} else {
this.vertices.add(vertex);
return true;
}
}
public boolean addEdge(V source, P sourcePort, V target, P targetPort) {
return addEdge(new Edge<>(source, target, sourcePort, targetPort));
}
public boolean addEdge(Edge edge) {
if(connectionExists(edge.getSource(), edge.getTarget(), edge.getSourcePort(), edge.getTargetPort())) {
return false;
} else {
edges.add(edge);
if(isCyclic()) {
edges.remove(edge);
return false;
} else {
return true;
}
}
}
public Set getVertices() {
return vertices;
}
public Set> getEdges() {
return edges;
}
public Iterator getTopologicalIterator() {
try {
return this.traverser.getTopologicalIterator(this);
} catch (CyclicDependencyException e) {
// It will never come here
return null;
}
}
private boolean isCyclic() {
return this.traverser.isCyclic(this);
}
private boolean connectionExists(V source, V target, P sourcePort, P targetPort) {
if(vertices.contains(source) && vertices.contains(target) && source.getOutPorts().contains(sourcePort) && target.getInPorts().contains(targetPort)) {
return edges.stream().anyMatch((e) ->
e.getSource().equals(source)
&& e.getTarget().equals(target)
&& e.getSourcePort().equals(sourcePort)
&& e.getTargetPort().equals(targetPort)
);
} else {
return false;
}
}
public Set getInVertices(V vertex) {
return edges.stream().filter((e) -> e.getSource().equals(vertex)).map(Edge::getSource).collect(Collectors.toSet());
}
public Set getOutVertices(V vertex) {
return edges.stream().filter((e) -> e.getSource().equals(vertex)).map(Edge::getTarget).collect(Collectors.toSet());
}
public Set> getInEdges(V vertex, P port) {
return edges.stream().filter((e) -> e.getTarget().equals(vertex) && e.getTargetPort().equals(port)).collect(Collectors.toSet());
}
public Set> getOutEdges(V vertex, P port) {
return edges.stream().filter((e) -> e.getSource().equals(vertex) && e.getSourcePort().equals(port)).collect(Collectors.toSet());
}
public Set> getAllInEdges(V vertex) {
return edges.stream().filter((e) -> e.getTarget().equals(vertex)).collect(Collectors.toSet());
}
public Set> getAllOutEdges(V vertex) {
return edges.stream().filter((e) -> e.getSource().equals(vertex)).collect(Collectors.toSet());
}
private Traverser traverser;
private Set> edges = Sets.newHashSet();
private Set vertices = Sets.newHashSet();
private class Traverser {
private void traverse(V vertex, List traversed, List order) throws CyclicDependencyException {
if(traversed.contains(vertex)) throw new CyclicDependencyException(vertex.getName());
traversed.add(vertex);
Set outgoing = getOutVertices(vertex);
if(outgoing.size() != 0) {
for (V v: outgoing) {
traverse(v, Lists.newArrayList(traversed), order);
}
}
if(!order.contains(vertex)) order.add(vertex);
}
public Iterator getTopologicalIterator(DAG dag) throws CyclicDependencyException {
Set vertices = dag.getVertices();
ArrayList order = Lists.newArrayList();
for (V vertex: vertices) {
traverse(vertex, Lists.newArrayList(), order);
}
return Lists.reverse(order).iterator();
}
public boolean isCyclic(DAG dag) {
try {
getTopologicalIterator(dag);
return false;
} catch (CyclicDependencyException e) {
return true;
}
}
}
}