diff --git a/common/com/pahimar/ee3/emc/graph/Node.java b/common/com/pahimar/ee3/emc/graph/Node.java index 9491da53..acb8b269 100644 --- a/common/com/pahimar/ee3/emc/graph/Node.java +++ b/common/com/pahimar/ee3/emc/graph/Node.java @@ -1,64 +1,70 @@ -package com.pahimar.ee3.emc.graph; - -/** - * Equivalent-Exchange-3 - * - * Node - * - * @author pahimar - * @license Lesser GNU Public License v3 (http://www.gnu.org/licenses/lgpl.html) - * - */ -public class Node> implements Comparable> { - - public enum NodeTraversalStatus { - UNDISCOVERED, DISCOVERED - } - - public final T nodeObject; - public NodeTraversalStatus traversalState; - - public Node(T nodeObject) { - - this.nodeObject = nodeObject; - traversalState = NodeTraversalStatus.UNDISCOVERED; - } - - @Override - public boolean equals(Object object) { - - if (!(object instanceof Node)) { - return false; - } - - Node node = (Node) object; - - return this.traversalState == node.traversalState && this.nodeObject.equals(node.nodeObject); - } - - /* - * (non-Javadoc) - * @see java.lang.Comparable#compareTo(java.lang.Object) - */ - @Override - public int compareTo(Node node) { - - if (node instanceof Node && node.nodeObject instanceof Comparable) { - if (this.nodeObject instanceof Comparable) { - return this.nodeObject.compareTo(node.nodeObject); - } - else { - return -1; - } - } - else { - return 1; - } - } - - @Override - public String toString() { - - return nodeObject.toString(); - } -} +package com.pahimar.ee3.emc.graph; + +/** + * Equivalent-Exchange-3 + * + * Node + * + * @author pahimar + * @license Lesser GNU Public License v3 (http://www.gnu.org/licenses/lgpl.html) + * + */ +public class Node> implements Comparable> { + + public enum NodeTraversalStatus { + UNDISCOVERED, DISCOVERED + } + + public final T nodeObject; + public NodeTraversalStatus traversalState; + + public Node(T nodeObject) { + + this.nodeObject = nodeObject; + traversalState = NodeTraversalStatus.UNDISCOVERED; + } + + @Override + public boolean equals(Object object) { + + if (!(object instanceof Node)) { + return false; + } + + Node node = (Node) object; + + return this.traversalState == node.traversalState && this.nodeObject.equals(node.nodeObject); + } + + /* + * (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(Node node) { + + if (node instanceof Node && node.nodeObject instanceof Comparable) { + if (this.nodeObject instanceof Comparable) { + return this.nodeObject.compareTo(node.nodeObject); + } + else { + return -1; + } + } + else { + return 1; + } + } + + @Override + public int hashCode() { + + return this.nodeObject.hashCode(); + } + + @Override + public String toString() { + + return nodeObject.toString(); + } +} diff --git a/common/com/pahimar/ee3/emc/graph/WeightedDirectedGraph.java b/common/com/pahimar/ee3/emc/graph/WeightedDirectedGraph.java index f9cf782c..c0670860 100644 --- a/common/com/pahimar/ee3/emc/graph/WeightedDirectedGraph.java +++ b/common/com/pahimar/ee3/emc/graph/WeightedDirectedGraph.java @@ -2,69 +2,66 @@ package com.pahimar.ee3.emc.graph; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import com.google.common.collect.ImmutableList; -public class WeightedDirectedGraph> implements Iterable> { +public class WeightedDirectedGraph> + implements Iterable> { - // FIXME This whole class should be considered very broken right now, as it needs to be adjusted now that we are wrapping objects into Nodes - - private final Map, SortedSet>> graph = new HashMap, SortedSet>>(); + // FIXME This whole class should be considered very broken right now, as it + // needs to be adjusted now that we are wrapping objects into Nodes - public boolean addNode(T node) { + private final Map, SortedSet>>> graph = new HashMap, SortedSet>>>(); - if (containsNode(node)) { - return false; - } - - graph.put(new Node(node), new TreeSet>()); - - return true; - } - - public void addEdge(T from, T to) { - - addEdge(from, to, 1); - } - - public void addEdge(T from, T to, float weight) { - - if (containsNode(from) && containsNode(to) && !containsWeightedEdge(from, to, weight)) { - graph.get(from).add(new WeightedEdge(to, weight)); - } - } - - /*** + /** + * Checks whether or not the provided Node exists in the graph * * @param node - * The node we are checking for - * @return True if specified node exists in the graph, false otherwise + * The Node we are looking for in the graph + * @return true if the Node exists in the graph, false otherwise */ - public boolean containsNode(T node) { + public boolean containsNode(Node node) { return graph.containsKey(node); } - /*** + /** + * Checks whether or not the provided object exists in the graph * - * @param from - * The 'from' node in the graph - * @param to - * The 'to' node in the graph - * @return True if there exists at least one WeightedEdge from the 'from' - * node going to the 'to' node + * @param nodeObject + * The object that we are checking if it is contained within a + * Node in the graph + * @return true if there exists a Node in the graph that contains the + * provided object, false otherwise */ - public boolean containsAnyEdge(T from, T to) { + public boolean containsNode(T nodeObject) { - if (containsNode(from)) { + return this.containsNode(new Node(nodeObject)); + } - Iterator> edgeIterator = graph.get(from).iterator(); + /** + * Checks whether or not there exists any edge between two Nodes + * + * @param sourceNode + * The source Node of an edge + * @param destinationNode + * The destination Node of an edge + * @return true if there exists any WeightedEdge between two Nodes, where + * the source Node is sourceNode and the destination Node is + * destinationNode + */ + public boolean containsEdge(Node sourceNode, Node destinationNode) { + + if (this.containsNode(sourceNode) && this.containsNode(destinationNode)) { + + Iterator>> edgeIterator = graph.get(sourceNode).iterator(); while (edgeIterator.hasNext()) { - if (edgeIterator.next().targetNode.equals(to)) { + if (edgeIterator.next().destinationNode.equals(destinationNode)) { return true; } } @@ -73,54 +70,331 @@ public class WeightedDirectedGraph> implements Iterable< return false; } - /*** + /** + * Checks whether or not there exists any edge between two Nodes * - * @param from - * The 'from' node in the graph - * @param to - * The 'to' node in the graph - * @param weight - * The weight of the WeightedEdge we are looking for - * @return + * @param sourceObject + * Object that is contained within the source Node of an edge + * @param destinationNode + * Object that is contained within the destination Node of an + * edge + * @return true if there exists any WeightedEdge between two Nodes, where + * the source Node contains sourceObject and the destination Node + * contains destinationNode */ - public boolean containsWeightedEdge(T from, T to, float weight) { + public boolean containsEdge(T sourceObject, T destinationNode) { - if (containsNode(from)) { - return graph.get(from).contains(new WeightedEdge(to, weight)); + return this.containsEdge(new Node(sourceObject), new Node(destinationNode)); + } + + /** + * Checks whether or not there exists an edge between two Nodes with a + * specific edge weight + * + * @param sourceNode + * The from Node of an edge + * @param targetNode + * The to Node of an edge + * @param edgeWeight + * The edge weight of an edge + * @return true if there exists a WeightedEdge from fromNode to toNode + * with the specified edge weight edgeWeight, false otherwise + */ + public boolean containsEdge(Node sourceNode, Node targetNode, float edgeWeight) { + + if (this.containsNode(sourceNode) && this.containsNode(targetNode)) { + return graph.get(sourceNode).contains(new WeightedEdge>(targetNode, edgeWeight)); } return false; } - /*** + /** + * Checks whether or not there exists an edge between two Nodes with the + * specified Node contents and with a specific edge weight + * + * @param sourceObject + * Object that is contained within the from Node of an edge + * @param targetObject + * Object that is contained within the to Node of an edge + * @param edgeWeight + * The edge weight of an edge + * @return true if there exists a WeightedEdge from fromNode to toNode + * with the specified edge weight edgeWeight, false otherwise + */ + public boolean containsEdge(T sourceObject, T targetObject, float edgeWeight) { + + return this.containsEdge(new Node(sourceObject), new Node(targetObject), edgeWeight); + } + + /** + * Adds the specified Node to the graph * * @param node - * @return An ImmutableSet of WeightedEdges from the specified node + * Node to be added to the graph + * @return true if the Node was successfully added to the graph, false + * otherwise */ - public ImmutableList> edgesFrom(T node) { + public boolean addNode(Node node) { - if (containsNode(node)) { - return ImmutableList.copyOf(graph.get(node)); + if (this.containsNode(node)) { + return false; } - + + graph.put(node, new TreeSet>>()); + + return true; + } + + /** + * Adds the specified object to the graph + * + * @param nodeObject + * Object to encapsulate in a Node and add to the graph + * @return true if the Node was successfully added to the graph, false + * otherwise + */ + public boolean addNode(T nodeObject) { + + return this.addNode(new Node(nodeObject)); + } + + /** + * Adds a WeightedEdge from Node sourceNode to Node destinationNode with + * edge weight edgeWeight, if those Nodes exist in the graph and a + * WeightedEdge doesn't already exist with the specified parameters + * + * @param sourceNode + * The source Node for the WeightedEdge + * @param destinationNode + * The C Node for the WeightedEdge + * @param edgeWeight + * The edge weight for the WeightedEdge + */ + public void addEdge(Node sourceNode, Node destinationNode, float edgeWeight) { + + if (this.containsNode(sourceNode) && this.containsNode(destinationNode) && !this.containsEdge(sourceNode, destinationNode, edgeWeight)) { + graph.get(sourceNode).add(new WeightedEdge>(destinationNode, edgeWeight)); + } + } + + /** + * Adds a WeightedEdge from Node sourceNode to Node destinationNode with a + * default edge weight of 1, if those Nodes exist in the graph and a + * WeightedEdge doesn't already exist with the specified parameters + * + * @param sourceNode + * The source Node for the WeightedEdge + * @param destinationNode + * The destination Node for the WeightedEdge + */ + public void addEdge(Node sourceNode, Node destinationNode) { + + this.addEdge(sourceNode, destinationNode, 1); + } + + /** + * Adds a WeightedEdge from sourceObject to destinationObject with edge + * weight edgeWeight, if Nodes exist in the graph containing those objects + * and a WeightedEdge doesn't already exist with the specified parameters + * + * @param sourceObject + * The source Object for the WeightedEdge + * @param destinationObject + * The destination Object for the WeightedEdge + * @param edgeWeight + * The edge weight for the WeightedEdge + */ + public void addEdge(T sourceObject, T destinationObject, float edgeWeight) { + + this.addEdge(new Node(sourceObject), new Node(destinationObject), edgeWeight); + } + + /** + * Adds a WeightedEdge from sourceObject to destinationObject with a default + * edge weight of 1, if Nodes exist in the graph containing those objects + * and a WeightedEdge doesn't already exist with the specified parameters + * + * @param sourceObject + * The source Object for the WeightedEdge + * @param destinationObject + * The destination Object for the WeightedEdge + * @param edgeWeight + * The edge weight for the WeightedEdge + */ + public void addEdge(T sourceObject, T destinationObject) { + + this.addEdge(sourceObject, destinationObject, 1); + } + + /** + * Get a list of all WeightedEdges that start at the provided Node + * + * @param sourceNode + * The Node we are gathering all WeightedEdges from + * @return An ImmutableList of all the WeightedEdges that start from the + * from Node + */ + public ImmutableList>> edgesFrom(Node sourceNode) { + + if (this.containsNode(sourceNode)) { + return ImmutableList.copyOf(graph.get(sourceNode)); + } + return ImmutableList.of(); } - public ImmutableList> edgesTo(T targetNode) { + /** + * Removes the specified Node from the graph, and all WeightedEdges for + * which node is either the source or destination + * + * @param node + */ + public void removeNode(Node node) { - ImmutableList.Builder> edgesToTargetNodeList = ImmutableList.builder(); - - if (containsNode(targetNode)) { + if (this.containsNode(node)) { + + this.removeEdgesTo(node); + this.removeEdgesFrom(node); + graph.remove(node); + } + } - for (Node graphNode : getAllNodes()) { - - if (!graphNode.equals(targetNode)) { - - ImmutableList> edgesFromGraphNode = edgesFrom(graphNode.nodeObject); + /** + * Removes the Node that contains the specified node object + * + * @param nodeObject + */ + public void removeNode(T nodeObject) { + this.removeNode(new Node(nodeObject)); + } + + public void removeEdge(Node sourceNode, Node destinationNode, float weight) { + + if (this.containsNode(sourceNode) && this.containsNode(destinationNode)) { + graph.get(sourceNode).remove(new WeightedEdge>(destinationNode, weight)); + } + } + + public void removeEdge(Node sourceNode, Node destinationNode) { + + this.removeEdge(sourceNode, destinationNode, 1); + } + + public void removeEdge(T sourceObject, T destinationObject, float weight) { + + this.removeEdge(new Node(sourceObject), new Node(destinationObject), weight); + } + + public void removeEdge(T sourceObject, T destinationObject) { + + this.removeEdge(sourceObject, destinationObject, 1); + } + + /** + * Remove all WeightedEdges that start at Node node + * + * @param node + */ + public void removeEdgesFrom(Node node) { + + if (this.containsNode(node)) { + graph.get(node).clear(); + } + } - for (WeightedEdge edgeFromGraphNode : edgesFromGraphNode) { - if (edgeFromGraphNode.targetNode.equals(targetNode)) { - edgesToTargetNodeList.add(new WeightedEdge(graphNode, edgeFromGraphNode.weight)); + public void removeEdgesFrom(T nodeObject) { + this.removeEdgesFrom(new Node(nodeObject)); + } + + /** + * Removes all WeightedEdges that have Node node as the destination + * + * @param node + */ + public void removeEdgesTo(Node node) { + + if (this.containsNode(node)) { + + Iterator> nodeIterator = this.iterator(); + + while (nodeIterator.hasNext()) { + + Node graphNode = nodeIterator.next(); + + List>> fromEdges = this.edgesFrom(graphNode); + + for (WeightedEdge> fromEdge : fromEdges) { + if (fromEdge.destinationNode.equals(node)) { + graph.get(graphNode).remove(fromEdge); + } + } + } + } + } + + public void removeEdgesTo(T nodeObject) { + this.removeEdgesTo(new Node(nodeObject)); + } + + /** + * Removes all WeightedEdges between Nodes firstNode and secondNode + * + * @param firstNode + * @param secondNode + */ + public void removeEdgesBetween(Node firstNode, Node secondNode) { + + if (this.containsNode(firstNode) && this.containsNode(secondNode)) { + + for (WeightedEdge> fromEdge : this.edgesFrom(firstNode)) { + if (fromEdge.destinationNode.equals(secondNode)) { + graph.get(firstNode).remove(fromEdge); + } + } + + for (WeightedEdge> fromEdge : this.edgesFrom(secondNode)) { + if (fromEdge.destinationNode.equals(firstNode)) { + graph.get(secondNode).remove(fromEdge); + } + } + } + } + + public void removeEdgesBetween(T firstObject, T secondObject) { + this.removeEdgesBetween(new Node(firstObject), new Node(secondObject)); + } + + /** + * + * @param sourceObject + * @return + */ + public ImmutableList>> edgesFrom(T sourceObject) { + + return this.edgesFrom(new Node(sourceObject)); + } + + /** + * + * @param destinationNode + * @return + */ + public ImmutableList>> edgesTo(Node destinationNode) { + + ImmutableList.Builder>> edgesToTargetNodeList = ImmutableList.builder(); + + if (this.containsNode(destinationNode)) { + + for (Node graphNode : this.getAllNodes()) { + + if (!graphNode.equals(destinationNode)) { + + List>> edgesFromGraphNode = edgesFrom(graphNode); + + for (WeightedEdge> fromEdge : edgesFromGraphNode) { + if (fromEdge.destinationNode.equals(destinationNode)) { + edgesToTargetNodeList.add(new WeightedEdge>(graphNode, fromEdge.weight)); } } } @@ -130,71 +404,21 @@ public class WeightedDirectedGraph> implements Iterable< return edgesToTargetNodeList.build(); } - public void removeNode(T node) { + /** + * + * @param destinationObject + * @return + */ + public ImmutableList>> edgesTo(T destinationObject) { - if (containsNode(node)) { - - // Remove all edges from and to the node - removeEdgesFrom(node); - removeEdgesTo(node); - - // Remove the node - graph.remove(node); - } - } - - public void removeEdge(T from, T to) { - - removeEdge(from, to, 1); - } - - public void removeEdge(T from, T to, float weight) { - - if (containsNode(from) && containsNode(to)) { - graph.get(from).remove(new WeightedEdge(to, weight)); - } - } - - public void removeEdgesFrom(T node) { - - if (containsNode(node)) { - graph.get(node).clear(); - } - } - - public void removeEdgesTo(T targetNode) { - - if (containsNode(targetNode)) { - for (Node graphNode : graph.keySet()) { - - ImmutableList> edgesFromGraphNode = edgesFrom(graphNode.nodeObject); - - for (WeightedEdge edgeFromGraphNode : edgesFromGraphNode) { - if (edgeFromGraphNode.targetNode.equals(targetNode)) { - graph.get(graphNode).remove(edgeFromGraphNode); - } - } - } - } - } - - public void removeAllEdgesBetween(T firstNode, T secondNode) { - - if (containsNode(firstNode) && containsNode(secondNode)) { - for (WeightedEdge edgeFromFirstNode : edgesFrom(firstNode)) { - if (edgeFromFirstNode.targetNode.equals(secondNode)) { - graph.get(firstNode).remove(edgeFromFirstNode); - } - } - - for (WeightedEdge edgeFromSecondNode : edgesFrom(secondNode)) { - if (edgeFromSecondNode.targetNode.equals(firstNode)) { - graph.get(secondNode).remove(edgeFromSecondNode); - } - } - } + return this.edgesTo(new Node(destinationObject)); } + /** + * Retrieves an ImmutableList of all Nodes in the graph + * + * @return An ImmutableList of all Nodes in the graph + */ public ImmutableList> getAllNodes() { if (graph.keySet() != null) { @@ -205,71 +429,113 @@ public class WeightedDirectedGraph> implements Iterable< } } - public ImmutableList> getCriticalNodes() { + /** + * Retrieves an ImmutableList of all leaf Nodes in the graph A leaf node is + * defined as a Node that has no edges from edge + * + * @return An ImmutableList of all leaf Nodes in the graph + */ + public ImmutableList> getLeafNodes() { - ImmutableList.Builder> criticalNodesList = ImmutableList.builder(); + ImmutableList.Builder> leafNodeList = ImmutableList.builder(); Iterator> nodeIterator = this.iterator(); while (nodeIterator.hasNext()) { Node currentNode = nodeIterator.next(); - if (this.edgesFrom(currentNode.nodeObject).size() == 0) { - criticalNodesList.add(currentNode); + if (this.edgesFrom(currentNode).size() == 0) { + leafNodeList.add(currentNode); } } - return criticalNodesList.build(); + return leafNodeList.build(); } + /** + * Retrieves an ImmutableList of all "orphan" Nodes in the graph An "orphan" + * Node is defined as a Node that has no edges from it, and no edges to it + * (they are isolated in the graph) Orphan Nodes technically qualify as leaf + * Nodes + * + * @return An ImmutableList of all "orphan" Nodes in the graph + */ public ImmutableList> getOrphanNodes() { - ImmutableList.Builder> orphanNodesList = ImmutableList.builder(); + ImmutableList.Builder> orphanNodeList = ImmutableList.builder(); Iterator> nodeIterator = this.iterator(); while (nodeIterator.hasNext()) { Node currentNode = nodeIterator.next(); - if (this.edgesFrom(currentNode.nodeObject).size() == 0 && this.edgesTo(currentNode.nodeObject).size() == 0) { - orphanNodesList.add(currentNode); + if ((this.edgesFrom(currentNode).size() == 0) && (this.edgesTo(currentNode).size() == 0)) { + orphanNodeList.add(currentNode); } } - return orphanNodesList.build(); + return orphanNodeList.build(); } - @Override - public Iterator> iterator() { + /** + * Retrieves an ImmutableList of all "compound" Nodes in the graph. A + * "compound" Node is defined as a Node that has edges from it (therefore, + * it is not a leaf Node) + * + * @return An ImmutableList of all "compound" Nodes in the graph + */ + public ImmutableList> getCompoundNodes() { - return this.getAllNodes().iterator(); + ImmutableList.Builder> compoundNodeList = ImmutableList.builder(); + + Iterator> nodeIterator = this.iterator(); + + while (nodeIterator.hasNext()) { + Node currentNode = nodeIterator.next(); + + if (this.edgesFrom(currentNode).size() > 0) { + compoundNodeList.add(currentNode); + } + } + + return compoundNodeList.build(); } + /** + * Returns the Node count of the graph + * + * @return The number of Nodes in the graph + */ public int size() { return graph.size(); } + /** + * Returns whether or not the graph is empty (contains no Nodes) + * + * @return true if the graph contains no Nodes, false otherwise + */ public boolean isEmpty() { return graph.isEmpty(); } + /** + * Returns a String representation of this graph + */ @Override public String toString() { return graph.toString(); } - - public void DepthFirstSearch(T node) { - /** - * The following is specified to EE3 (as opposed to this generalized Weighted Directed Graph implementation - * - * - The edges from a node depict what "makes" that node - * - If there are no edges from a node, then nothing "makes the node" - * - If nothing "makes" the node the node, then it is a critical node - * - A Depth First Search using using critical nodes will return a spanning tree of the graph - */ + /** + * Returns an iterator of all the Nodes in the graph + */ + @Override + public Iterator> iterator() { + + return this.getAllNodes().iterator(); } } diff --git a/common/com/pahimar/ee3/emc/graph/WeightedEdge.java b/common/com/pahimar/ee3/emc/graph/WeightedEdge.java index 723143e5..3efaeecf 100644 --- a/common/com/pahimar/ee3/emc/graph/WeightedEdge.java +++ b/common/com/pahimar/ee3/emc/graph/WeightedEdge.java @@ -7,7 +7,7 @@ public class WeightedEdge> implements Comparable targetNode; + public final Node destinationNode; public EdgeTraversalStatus edgeTraversalStatus; public WeightedEdge(T nodeObject) { @@ -19,11 +19,16 @@ public class WeightedEdge> implements Comparable(nodeObject), weight); } + + public WeightedEdge(Node destinationNode) { + + this(destinationNode, 1); + } - public WeightedEdge(Node targetNode, float weight) { + public WeightedEdge(Node destinationNode, float weight) { this.weight = weight; - this.targetNode = targetNode; + this.destinationNode = destinationNode; this.edgeTraversalStatus = EdgeTraversalStatus.UNDISCOVERED; } @@ -38,7 +43,7 @@ public class WeightedEdge> implements Comparable> implements Comparable> implements Comparable