/*
* Copyright 1999-2002 Carnegie Mellon University.
* Portions Copyright 2002 Sun Microsystems, Inc.
* Portions Copyright 2002 Mitsubishi Electric Research Laboratories.
* All Rights Reserved. Use is subject to license terms.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*
*/
package edu.cmu.sphinx.trainer;
import java.util.ArrayList;
import java.util.Iterator;
/** Implementation of a graph */
public class Graph {
private ArrayList<Edge> edges; // The list of edges.
private ArrayList<Node> nodes; // The list of nodes.
private Iterator<Edge> edgeIterator; // The iterator for the list of edges.
private Iterator<Node> nodeIterator; // The iterator for the list of nodes.
/** The initial node in the graph. This has no incoming edges. */
private Node initialNode;
/*
* The final node in the graph. This has no outgoing edges.
*/
private Node finalNode;
/** Constructor for class. Creates lists of edges and nodes. */
public Graph() {
edges = new ArrayList<Edge>();
nodes = new ArrayList<Node>();
}
/** Set the initial node
* @param node node
* @throws IllegalArgumentException if node is not in the graph
*/
public void setInitialNode(Node node) throws IllegalArgumentException {
if (isNodeInGraph(node)) {
initialNode = node;
} else {
throw new IllegalArgumentException("Initial node not in graph");
}
}
/** Set the final node
* @param node node
* @throws IllegalArgumentException if node is not in the graph
*/
public void setFinalNode(Node node) throws IllegalArgumentException {
if (isNodeInGraph(node)) {
finalNode = node;
} else {
throw new IllegalArgumentException("Final node not in graph");
}
}
/** Get the initial node
* @return initial node
*/
public Node getInitialNode() {
return initialNode;
}
/** Get the final node
* @return final node
*/
public Node getFinalNode() {
return finalNode;
}
/**
* Get this graph's size. The size of a graph is the number of nodes in the graph.
*
* @return the size of the graph
*/
public int size() {
return nodes.size();
}
/**
* Get node at the specified position in the list. The order is the same in which the nodes were entered.
*
* @param index index of item to retun
* @return the item
*/
public Node getNode(int index) {
return nodes.get(index);
}
/**
* Gets an array containing the nodes in this graph.
*
* @return an array of nodes
*/
public Node[] nodeToArray() {
return nodes.toArray(new Node[nodes.size()]);
}
/**
* Gets the index of a particular node in the graph.
*
* @param node the node
* @return the index in this graph, or -1 if not found
*/
public int indexOf(Node node) {
return nodes.indexOf(node);
}
/**
* Returns whether the given node is the initial node in this graph.
*
* @param node the node we want to compare
* @return if true, the node is the initial node
*/
public boolean isInitialNode(Node node) {
return node == initialNode;
}
/**
* Returns whether the given node is the final node in this graph.
*
* @param node the node we want to compare
* @return if true, the node is the final node
*/
public boolean isFinalNode(Node node) {
return node == finalNode;
}
/**
* Link two nodes. If the source or destination nodes are not in the graph, they are added to it. No check is
* performed to ensure that the nodes are linked to other nodes in the graph.
* @param sourceNode source node
* @param destinationNode destination node
* @return created edge
*/
public Edge linkNodes(Node sourceNode, Node destinationNode) {
Edge newLink = new Edge(sourceNode, destinationNode);
sourceNode.addOutgoingEdge(newLink);
destinationNode.addIncomingEdge(newLink);
if (!isNodeInGraph(sourceNode)) {
addNode(sourceNode);
}
if (!isNodeInGraph(destinationNode)) {
addNode(destinationNode);
}
addEdge(newLink);
return newLink;
}
/** Add node to list of nodes.
* @param node node to add
*/
public void addNode(Node node) {
nodes.add(node);
}
/** Add edge to list of nodes.
* @param edge edge to add
*/
public void addEdge(Edge edge) {
edges.add(edge);
}
/** Check if a node is in the graph.
* @param node node to check
* @return if node in the graph
*/
public boolean isNodeInGraph(Node node) {
return nodes.contains(node);
}
/** Check if an edge is in the graph.
* @param edge edge to check
* @return if edge in the graph
*/
public boolean isEdgeInGraph(Edge edge) {
return edges.contains(edge);
}
/** Start iterator for nodes. */
public void startNodeIterator() {
nodeIterator = nodes.iterator();
}
/** @return whether there are more nodes.
*/
public boolean hasMoreNodes() {
return nodeIterator.hasNext();
}
/** @return next node.
*/
public Node nextNode() {
return nodeIterator.next();
}
/** Start iterator for edges. */
public void startEdgeIterator() {
edgeIterator = edges.iterator();
}
/** @return whether there are more edges.
*/
public boolean hasMoreEdges() {
return edgeIterator.hasNext();
}
/** @return next edge. */
public Edge nextEdge() {
return edgeIterator.next();
}
/**
* Copy a graph to the current graph object.
*
* @param graph the graph to copy from
*/
public void copyGraph(Graph graph) {
// Make sure the current graph is empty
assert ((nodes.isEmpty()) && (edges.isEmpty()));
for (graph.startNodeIterator();
graph.hasMoreNodes();) {
addNode(graph.nextNode());
}
for (graph.startEdgeIterator();
graph.hasMoreEdges();) {
addEdge(graph.nextEdge());
}
setInitialNode(graph.getInitialNode());
setFinalNode(graph.getFinalNode());
}
/**
* Insert a graph in the current graph, replacing a particular node.
*
* @param graph the graph to insert
* @param node the node that this graph will replace
*/
public void insertGraph(Graph graph, Node node) {
// Make sure the node belongs to the graph
assert isNodeInGraph(node) : "Node not in graph";
assert graph != null : "Graph not defined";
assert ((!isFinalNode(node)) && (!isInitialNode(node)));
int nodePosition = nodes.indexOf(node);
nodes.remove(nodePosition);
int index;
for (graph.startNodeIterator(), index = nodePosition;
graph.hasMoreNodes(); index++) {
nodes.add(index, graph.nextNode());
}
for (graph.startEdgeIterator();
graph.hasMoreEdges();) {
addEdge(graph.nextEdge());
}
Node initialNode = graph.getInitialNode();
for (node.startIncomingEdgeIterator();
node.hasMoreIncomingEdges();) {
Edge edge = node.nextIncomingEdge();
edge.setDestination(initialNode);
initialNode.addIncomingEdge(edge);
}
Node finalNode = graph.getFinalNode();
for (node.startOutgoingEdgeIterator();
node.hasMoreOutgoingEdges();) {
Edge edge = node.nextOutgoingEdge();
edge.setSource(finalNode);
finalNode.addOutgoingEdge(edge);
}
}
/**
* Validate the graph. It checks out basics about the graph, such as whether all nodes have at least one incoming
* and outgoing edge, except for the initial and final.
*
* @return if true, graph validation passed
*/
public boolean validate() {
boolean passed = true;
for (startNodeIterator();
hasMoreNodes();) {
Node node = nextNode();
passed &= node.validate();
int incoming = node.incomingEdgesSize();
int outgoing = node.outgoingEdgesSize();
if (incoming < 1) {
if (!isInitialNode(node)) {
System.out.println("No incoming edge: " + node);
passed = false;
}
}
for (node.startIncomingEdgeIterator();
node.hasMoreIncomingEdges();) {
passed &= edges.contains(node.nextIncomingEdge());
}
if (outgoing < 1) {
if (!isFinalNode(node)) {
System.out.println("No outgoing edge: " + node);
passed = false;
}
}
for (node.startOutgoingEdgeIterator();
node.hasMoreOutgoingEdges();) {
passed &= edges.contains(node.nextOutgoingEdge());
}
}
for (startEdgeIterator();
hasMoreEdges();) {
Edge edge = nextEdge();
passed &= edge.validate();
passed &= nodes.contains(edge.getSource());
passed &= nodes.contains(edge.getDestination());
}
return passed;
}
/** Prints out the graph. For debugging purposes. */
public void printGraph() {
for (startNodeIterator();
hasMoreNodes();) {
Node node = nextNode();
if (isInitialNode(node)) {
System.out.println("Initial Node");
}
if (isFinalNode(node)) {
System.out.println("Final Node");
}
System.out.println(node);
node.print();
}
for (startEdgeIterator();
hasMoreEdges();) {
Edge edge = nextEdge();
System.out.println(edge);
edge.print();
}
}
}