import java.util.*; import java.lang.Math; public class myWeightedGraph { protected String[] names; // 1-d array to store the vertices protected double[] x; // 1-d array to store x-coordinates protected double[] y; // 1-d array to store y-coordinates protected EdgeLinkList[] Edges; // 1-d array to store adjacencies between vertices, protected int numVertices; protected int numEdges; // Default constructor. Sets aside enough capacity for one vertex public myWeightedGraph( ) { this(1); } // Constructor that sets aside as much capacity as specified by the user public myWeightedGraph(int capacity) { names = new String[capacity]; x = new double[capacity]; y = new double[capacity]; Edges = new EdgeLinkList[capacity]; for (int i = 0 ; i < capacity ; i ++) { Edges[i] = new EdgeLinkList(); } } public int numberOfVertices() { return numVertices; } public int numberOfEdges() { return numEdges; } // Finds the location at which a vertex is stored in Vertices. // Returns -1 if vertex not found public int getIndex(String vertex) { for(int i = 0; i < numVertices; i++) if(vertex.equals(names[i])) return i; return -1; } /* // Finds the location at which a vertex is stored in Vertices. // Returns -1 if vertex not found public int getIndex(String vertex) { int first = 0; int last = numVertices -1; while(first <= last) { int mid = (first + last)/2; int result = vertex.compareTo(names[mid]); if(result == 0) return mid; else if (result < 0) last = mid -1; else first = mid + 1; } return -1; } */ // Constructs a random graph using the Erdos-Renyi model myWeightedGraph makeRandomGraph(int n, double p) { Random rand = new Random(); String[] namesArray = new String[n]; myWeightedGraph g = new myWeightedGraph(n); for(int i = 0; i < n; i++) { Integer t = new Integer(i); namesArray[i] = t.toString(); } Arrays.sort(namesArray); for(int i = 0; i < n; i++) g.addVertex(namesArray[i]); for(int i = 0; i < n; i++) for(int j = 0; j < i; j++) if(rand.nextDouble() <= p) { String s = (new Integer(i)).toString(); String t = (new Integer(j)).toString(); g.addEdge(s, t); } return g; } // Resizes the array of vertices. Can make it larger or smaller, depending // on what newSize is. protected String[] resize(String[] array, int newSize) { String[] temp = new String[newSize]; int smallerSize = newSize; if(array.length < smallerSize) smallerSize = array.length; for(int i = 0; i < smallerSize; i++) temp[i] = array[i]; return temp; } // Resizes the array of coordinates. Can make it larger or smaller, depending // on what newSize is. protected double[] resize(double[] array, int newSize) { double[] temp = new double[newSize]; int smallerSize = newSize; if(array.length < smallerSize) smallerSize = array.length; for(int i = 0; i < smallerSize; i++) temp[i] = array[i]; return temp; } // Resizes the array of Edges. Can make it larger or smaller, depending // on what newSize is. protected EdgeLinkList[] resize (EdgeLinkList[] array, int newSize) { EdgeLinkList[] temp = new EdgeLinkList[newSize]; int smallerSize = newSize; if(array.length < smallerSize) smallerSize = array.length; for(int i = 0; i < smallerSize; i++) temp[i] = array[i]; for (int i = smallerSize ; i < temp.length ; i ++) temp [i] = new EdgeLinkList(); return temp; } // Adds coordinates to an already existing vertex public boolean addCoordinates(String vertex, double xcoord, double ycoord) { int index = getIndex(vertex); if(index == -1) return false; x[index] = xcoord; y[index] = ycoord; return true; } // Adds a new vertex public void addVertex(String newVertex) { if(getIndex(newVertex) != -1) { System.out.print("addVertex: "); System.out.print(newVertex); System.out.println(" failed -- vertex already exists."); return; } // if array of vertices is full, we need to expand it and // also expand Edges if (names.length == numVertices) { names = resize(names, 2*numVertices+1); x = resize(x, 2*numVertices+1); y = resize(y, 2*numVertices+1); Edges = resize(Edges, 2*numVertices+1); } names[numVertices++] = newVertex; } // Adds a new vertex public void addVertex(String newVertex, double xcoord, double ycoord) { if(getIndex(newVertex) != -1) { System.out.print("addVertex: "); System.out.print(newVertex); System.out.println(" failed -- vertex already exists."); return; } // if array of vertices is full, we need to expand it and // also expand Edges if (names.length == numVertices) { names = resize(names, 2*numVertices+1); x = resize(x, 2*numVertices+1); y = resize(y, 2*numVertices+1); Edges = resize(Edges, 2*numVertices+1); } names[numVertices] = newVertex; x[numVertices] = xcoord; y[numVertices++] = ycoord; } // Deletes a vertex whose name is given public void deleteVertex(String newVertex) { int index = getIndex(newVertex); if(index == -1) { System.out.print("deleteVertex: "); System.out.print(newVertex); System.out.println(" failed -- vertex does not exist."); return; } deleteVertex(index); } // Deletes a vertex with the given index from the graph public void deleteVertex(int i) { EdgeLinkList temp = Edges[i]; while(temp.size() > 0) { // delete the first neighbor from this vertex's link list String neighbor = temp.removeFirst(); // get the neighbors index int neighborLocation = getIndex(neighbor); // Delete the ith vertex from the neighbors linked list EdgeLink t = Edges[neighborLocation].delete(names[i]); numEdges--; } // end-of-while // Shift all the vertices (and the adjacency lists) up by one slot for(int j = i+1; j < numVertices; j++) { names[j-1] = names[j]; Edges[j-1] = Edges[j]; } numVertices--; } // end deleteVertex // Adds a new edge with default weight 1.0 // The endpoints of the edge are specified by indices public void addEdge(int i, int j) { addEdge(i, j, 1.0); } // Adds a new edge with default weight 1.0 public void addEdge(String vertex1, String vertex2) { addEdge(vertex1, vertex2, 1.0); } // Adds a new edge with weight w. The edge is specified by // indices of endpoints public void addEdge(int i, int j, double w) { if((i < 0) || (i > numVertices-1)) { System.out.print("addEdge failed: "); System.out.print("index " + i); System.out.println(" is out of bounds."); return; } if((j < 0) || (j > numVertices-1)) { System.out.print("addEdge failed: "); System.out.print("index " + j); System.out.println(" is out of bounds."); return; } Edges[i].insertFirst(names[j], w); Edges[j].insertFirst(names[i], w); numEdges++; } // Adds a new edge with weight w public void addEdge(String vertex1, String vertex2, double w) { int i = getIndex(vertex1); if(i == -1) { System.out.print("addEdge failed: "); System.out.print(vertex1); System.out.println(" does not exist."); return; } int j = getIndex(vertex2); if(j == -1) { System.out.print("addEdge failed: "); System.out.print(vertex2); System.out.println(" does not exist."); return; } addEdge(i, j, w); } // Prints the neighbors of the given vertex public void printAdjacencyList (String vertex) { int i = getIndex(vertex); if(i == -1) { System.out.print("addEdge failed: "); System.out.print(vertex); System.out.println(" does not exist."); return; } System.out.print (vertex + " is connected to "); Edges [i].displayList(); } // Prints coordinates of vertices public void printCoordinates() { for(int i = 0; i < numVertices; i++) System.out.println("{{ " + x[i] + ", " + y[i] + "}},"); } // Prints all the edges of a graph public void printEdgeIndices(double t) { for(int i = 0; i < numVertices; i++) { int[] nbrs = getNeighbors(i); for(int j = 0; j < nbrs.length; j++) { if(i < nbrs[j]) { double w = getWeight(i, nbrs[j]); if(w < t) System.out.println("{{ " + (i+1) + ", " + (nbrs[j]+1) + "}, EdgeColor->LightBlue" + "},"); else System.out.println("{{ " + (i+1) + ", " + (nbrs[j]+1) + "}, EdgeColor->Purple" + "},"); } } } } // Prints all the edges of a graph public void printEdges() { for(int i = 0; i < numVertices; i++) { int[] nbrs = getNeighbors(i); for(int j = 0; j < nbrs.length; j++) System.out.println(names[i] + " " + names[nbrs[j]]); } } // returns the names of all the neighbors of a given vertex in a // String array public String[] getNeighbors(String vertex) { int source = getIndex(vertex); if(source == -1) { System.out.print("getNeighbors failed: Vertex "); System.out.print(vertex); System.out.println(" does not exist."); return null; } return Edges[source].copyIntoArray(); } // returns the indices of all the neighbors of a given vertex. The // vertex is specified as an index and the neighbors are returned // in an int array public int[] getNeighbors(int index) { if((index < 0) || (index >= numVertices)) { System.out.print("getNeighbors failed: Index"); System.out.print(index); System.out.println(" is out of bounds."); return null; } // Call the earlier getNeighbors function to get the names of // neighbors String[] nbrNames = getNeighbors(names[index]); // Turn the array of neighbor names into an array // of neighbor indices int[] nbrIndices = new int[nbrNames.length]; for(int i = 0; i < nbrIndices.length; i++) nbrIndices[i] = getIndex(nbrNames[i]); return nbrIndices; } // returns the degree of a vertex with given name public int degree(String vertex) { // Get the index of the vertex int i = getIndex(vertex); if(i == -1) { System.out.print("In degree: "); System.out.print(vertex); System.out.println(" does not exist."); return -1; } // Call the other degree function that returns the degree // of a vertex, given its index return degree(i); } // returns the degree of a vertex with given index public int degree(int index) { return Edges[index].size(); } // returns the weighted degree of a vertex with given name public double weightedDegree(String vertex) { // Get the index of the vertex int i = getIndex(vertex); if(i == -1) { System.out.print("In degree: "); System.out.print(vertex); System.out.println(" does not exist."); return -1; } // Call the other weighted degree function that returns the weightedDegree // of a vertex, given its index return weightedDegree(i); } // returns the "weighted degree" of a vertex with given index. // This is the sum of the weights of all the edges incident on the vertex with given index public double weightedDegree(int index) { return Edges[index].totalWeight(); } // Gets the weight of the edge connecting a pair of vertices // whose indices are given public Double getWeight(int i, int j) { if((i < 0) || (i > numVertices-1)) { System.out.print("getWeight failed: "); System.out.print("index " + i); System.out.println(" out of bounds."); return null; } if((j < 0) || (j > numVertices-1)) { System.out.print("getWeight failed: "); System.out.print("index " + j); System.out.println(" out of bounds."); return null; } // Look for vertex j in Edges[i] //System.out.println("Looking for " + names[j] + " in linked list " + i); EdgeLink e = Edges[i].find(names[j]); // If vertex j is found in Edges[i] then return the weight of // the edge, otherwise return null if(e != null) return new Double(e.weight); else return null; } // Gets the weight of the edge connecting a pair of vertices // whose names are given public Double getWeight(String vertex1, String vertex2) { int i = getIndex(vertex1); if(i == -1) { System.out.print("getWeight failed: "); System.out.print(vertex1); System.out.println(" does not exist."); return null; } int j = getIndex(vertex2); if(j == -1) { System.out.print("getWeight failed: "); System.out.print(vertex2); System.out.println(" does not exist."); return null; } return getWeight(i, j); } // Boolean method that tells us if {i, j} is an edge in the graph public boolean isEdge(int i, int j) { if((i < 0) || (i > numVertices-1)) { System.out.print("isEdge failed: "); System.out.print("index " + i); System.out.println(" is out of bounds."); return false; } if((j < 0) || (j > numVertices-1)) { System.out.print("isEdge failed: "); System.out.print("index " + j); System.out.println(" is out of bounds."); return false; } // if vertex2 exists in the adjacency list of // vertex1, then return true return (Edges[i].find(names[j]) != null); } // Boolean method that tells us if {v1, v2} is an edge in the graph public boolean isEdge(String vertex1, String vertex2) { int i = getIndex(vertex1); if(i == -1) { System.out.print("isEdge failed: "); System.out.print(vertex1); System.out.println(" does not exist."); return false; } int j = getIndex(vertex2); if(j == -1) { System.out.print("isEdge failed: "); System.out.print(vertex2); System.out.println(" does not exist."); return false; } return isEdge(i, j); } // Computes the clustering coefficient of a vertex. This is the // version that takes a vertex index as argument. public double clusteringCoefficient(int i) { // Copy the adjacency list into an array, for easy access // copyIntoArray is a new method in the GenericLinkList class String[] temp = Edges[i].copyIntoArray(); // initialize edges-in-neighborhood to 0 int edgesInNbd = 0; // Scan pairs of neighbors and increment counter whenever // there is an edge for(int j = 0; j < temp.length; j++) for(int k = 0; k < j; k++) if(isEdge(temp[j], temp[k])) edgesInNbd++; // if there are no neighbors or one neighbor then, clustering // coefficient is trivially defined to be 1. Otherwise, // compute the ratio of number of edges in neighborhood to // the total number of pairs of neighbors if(temp.length <= 1) return 1; else return edgesInNbd*2.0/(temp.length*(temp.length-1)); } // Computes the clustering coefficient of a vertex. This is the // version that takes a vertex name as argument. public double clusteringCoefficient(String v) { int i = getIndex(v); if(i == -1) { System.out.print("clusteringCoefficient failed: "); System.out.print(v); System.out.println(" does not exist."); return 0; } return clusteringCoefficient(i); } // Computes the clustering coefficient of the entire graph // added on 2/23 public double clusteringCoefficient() { double sum = 0; for(int i = 0; i < numVertices; i++) sum = sum + clusteringCoefficient(i); return sum/numVertices; } // Checks whether the graph is connected or not by calling breadthFirstSearch public boolean isConnected() { // Perform breadth first search int[] bfsTree = breadthFirstSearch(names[0]); // Scan the bfsTree array, looking for -1. The graph // is not connected if there is -1 in this array for(int i = 0; i < bfsTree.length; i++) if(bfsTree[i] == -1) return false; return true; } // Returns the number of connected components of a graph public int numConnectedComponents() { String[][] cc = connectedComponents(); return cc.length; } // Returns the largest connected component public int largestConnectedComponentSize() { String[][] cc = connectedComponents(); // Pick the giant component int maxIndex = -1; int maxSize = -1; for(int i = 0; i < cc.length; i++) if(cc[i].length > maxSize) { maxIndex = i; maxSize = cc[i].length; } return maxSize; } // Returns a 2-d array of vertex names representing the connected components // of the graph. Each row in the 2-d array is a connected component. public String[][] connectedComponents() { // The maximum number of connected components equals the number // of vertices; so start by allocating this many rows. String[][] cc = new String[numVertices][]; // Keeps track of which vertices have been visited by repeated // calls to bfs boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; // Keeps track of the number of vertices have been visited by repeated // calls to bfs int numVisited = 0; // Keeps track of the number of connected components int numComponents = 0; // Repeat bfs until all vertices have been visited while(numVisited < numVertices) { // Scan visited until an unvisited vertex is found // and start bfs at that source int source; for(source = 0; source < numVisited; source++) if(!visited[source]) break; // Compute the bfsTree starting at this source int[] bfsTree = breadthFirstSearch(names[source]); // Scan bfsTree to count number of newly visited vertices int countNewVisited = 0; for(int i = 0; i < numVertices; i++) if(bfsTree[i] != -1) countNewVisited++; // Allocate a row of size countNewVisited in the current row of // cc to store the new connected component cc[numComponents] = new String[countNewVisited]; // Scan bfsTree again, this time to copy the newly visited // vertices into cc and set them as visited countNewVisited = 0; for(int i = 0; i < numVertices; i++) if(bfsTree[i] != -1) { cc[numComponents][countNewVisited++] = names[i]; visited[i] = true; } // Update numVisited numVisited = numVisited + countNewVisited; // Update numComponents numComponents++; } // end while // Resize cc to have exactly as mamy rows as numComponents String[][] newCC = new String[numComponents][]; for(int i = 0; i < numComponents; i++) newCC[i] = cc[i]; return newCC; } // Returns a 2-d array of vertex indices representing the connected components // of the graph. Each row in the 2-d array is a connected component. public int[][] connectedComponentIndices() { // The maximum number of connected components equals the number // of vertices; so start by allocating this many rows. int[][] cc = new int[numVertices][]; // Keeps track of which vertices have been visited by repeated // calls to bfs boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; // Keeps track of the number of vertices have been visited by repeated // calls to bfs int numVisited = 0; // Keeps track of the number of connected components int numComponents = 0; // Repeat bfs until all vertices have been visited while(numVisited < numVertices) { // Scan visited until an unvisited vertex is found // and start bfs at that source int source; for(source = 0; source < numVisited; source++) if(!visited[source]) break; // Compute the bfsTree starting at this source int[] bfsTree = breadthFirstSearch(names[source]); // Scan bfsTree to count number of newly visited vertices int countNewVisited = 0; for(int i = 0; i < numVertices; i++) if(bfsTree[i] != -1) countNewVisited++; // Allocate a row of size countNewVisited in the current row of // cc to store the new connected component cc[numComponents] = new int[countNewVisited]; // Scan bfsTree again, this time to copy the newly visited // vertices into cc and set them as visited countNewVisited = 0; for(int i = 0; i < numVertices; i++) if(bfsTree[i] != -1) { cc[numComponents][countNewVisited++] = i; visited[i] = true; } // Update numVisited numVisited = numVisited + countNewVisited; // Update numComponents numComponents++; } // end while // Resize cc to have exactly as mamy rows as numComponents int[][] newCC = new int[numComponents][]; for(int i = 0; i < numComponents; i++) newCC[i] = cc[i]; return newCC; } // Returns the diameter of the graph. Will return -1 if the graph is not connected int diameter() { int currentDiameter = 0; int maxDistanceI; for(int i = 0; i < numVertices; i++) { int[] distances = breadthFirstSearchDistances(i); // Compute the maximum distance from source i maxDistanceI = 0; for(int j = 0; j < numVertices; j++) if(maxDistanceI < distances[j]) maxDistanceI = distances[j]; // if max. distance from source i is more // than current diameter, update it if(currentDiameter < maxDistanceI) currentDiameter = maxDistanceI; } return currentDiameter; } // Returns the diameter of the graph. Will return -1 if the graph is not connected double averagePathLength() { if(!isConnected()) return -1; double sum = 0; for(int i = 0; i < numVertices; i++) { int[] distances = breadthFirstSearchDistances(i); // Compute the maximum distance from source i for(int j = 0; j < numVertices; j++) sum += distances[j]; } return sum*2/(numVertices*(numVertices-1)); } // Computes a shortest path (in hops) from source to destination. Does // this by simply calling breadthFirstSearch and following the parent // pointers in the BFS tree. If the source and destination are not in // the same component, returns null. Otherwise, returns a String array // of vertices in a shortest path public String[] shortestPath(String source, String dest, String attribute) { // Get index of source int sourceIndex = getIndex(source); if(sourceIndex == -1) { System.out.print("breadthFirstSearch failed: "); System.out.print(source); System.out.println(" does not exist."); return null; } // Get index of destination int destIndex = getIndex(dest); if(destIndex == -1) { System.out.print("breadthFirstSearch failed: "); System.out.print(dest); System.out.println(" does not exist."); return null; } // Perform a BFS or a DSP from destination int[] spTree; if(attribute.equals("hops")) spTree = breadthFirstSearch(destIndex); else spTree = DSP(dest); // If source is unreachable from destination if(spTree[sourceIndex] == -1) return null; // Define a String[] for shortest path and place the source vertex // in it String[] path = new String[numVertices]; path[0] = names[sourceIndex]; // Start following parent pointers and store each new vertex // encountered, in the path array. The while-loop executes // until the root of the BFS tree is encountered int currentIndex = sourceIndex; int pathLength = 0; while(currentIndex != spTree[currentIndex]) { currentIndex = spTree[currentIndex]; pathLength++; path[pathLength] = names[currentIndex]; } // Resize the path array to be exactly of the correct size String[] newPath = new String[pathLength + 1]; for(int i = 0; i < newPath.length; i++) newPath[i] = path[i]; return newPath; } public double shortestPathCost(String source, String dest, String attribute) { // Get index of source int sourceIndex = getIndex(source); if(sourceIndex == -1) { System.out.print("breadthFirstSearch failed: "); System.out.print(source); System.out.println(" does not exist."); return Double.MAX_VALUE; } // Get index of destination int destIndex = getIndex(dest); if(destIndex == -1) { System.out.print("breadthFirstSearch failed: "); System.out.print(dest); System.out.println(" does not exist."); return Double.MAX_VALUE; } // Perform a BFS or a DSP from destination int[] spTree; if(attribute.equals("hops")) spTree = breadthFirstSearch(destIndex); else spTree = DSP(dest); // If source is unreachable from destination if(spTree[sourceIndex] == -1) return Double.MAX_VALUE; // Start following parent pointers and store each new vertex // encountered, in the path array. The while-loop executes // until the root of the BFS tree is encountered int currentIndex = sourceIndex; double pathCost = 0; while(currentIndex != spTree[currentIndex]) { pathCost += getWeight(currentIndex, spTree[currentIndex]).doubleValue(); currentIndex = spTree[currentIndex]; } return pathCost; } // Breadth first search function that takes a vertex name as argument; // returns a breadth first search tree // stored in an array of integers with the entry in slot i containing // the index of the parent of the vertex with index i // parent of source is itself; unvisited nodes have parent -1 public int[] breadthFirstSearch(String source) { int sourceIndex = getIndex(source); if(sourceIndex == -1) { System.out.print("breadthFirstSearch failed: "); System.out.print(source); System.out.println(" does not exist."); return null; } return breadthFirstSearch(sourceIndex); } public int[] breadthFirstSearchDistances(int sourceIndex) { // Initialization // First initialize the distance array int[] distances = new int[numVertices]; for(int i = 0; i < numVertices; i++) distances[i] = -1; distances[sourceIndex] = 0; // Then initialize the visited array boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; visited[sourceIndex] = true; // Then initialize the queue Queue Q = new Queue(numVertices); Q.enqueue(sourceIndex); while(!Q.isEmpty()) { int current = Q.dequeue(); int[] neighbors = getNeighbors(current); // Scan the neighbors for(int i = 0; i < neighbors.length; i++) { // Get the index of the current neighbor int currentNeighbor = neighbors[i]; // Check if the neighbor is new, i.e., not visited // If so, mark the neighbor as visited, enqueue the neighbor, and // set the neighbor's parent in bfsTree if(!visited[currentNeighbor]) { visited[currentNeighbor] = true; Q.enqueue(currentNeighbor); distances[currentNeighbor] = distances[current] + 1; } } // end-scanning neighbors } // end-while Q is not empty return distances; } // Breadth first search function that takes a vertex index as argument; // returns a breadth first search tree // stored in an array of integers with the entry in slot i containing // the index of the parent of the vertex with index i // parent of source is itself; unvisited nodes have parent -1 public int[] breadthFirstSearch(int sourceIndex) { // Initialize the bfsTree array; the entry -1 means // not yet visited. int[] bfsTree = new int[numVertices]; for(int i = 0; i < numVertices; i++) bfsTree[i] = -1; // The parent of the tree root is itself bfsTree[sourceIndex] = sourceIndex; // Then initialize the visited array boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; visited[sourceIndex] = true; // Then initialize the queue Queue Q = new Queue(numVertices); Q.enqueue(sourceIndex); while(!Q.isEmpty()) { // get the index of the vertex first in line int current = Q.dequeue(); // Get the indices of the neighbors of the current vertex int[] neighbors = getNeighbors(current); // Scan the neighbors for(int i = 0; i < neighbors.length; i++) { // Get the index of the current neighbor int currentNeighbor = neighbors[i]; // Check if the neighbor is new, i.e., not visited // If so, mark the neighbor as visited, enqueue the neighbor, and // set the neighbor's parent in bfsTree if(!visited[currentNeighbor]) { visited[currentNeighbor] = true; Q.enqueue(currentNeighbor); bfsTree[currentNeighbor] = current; } } // end-scanning neighbors } // end-while Q is not empty return bfsTree; } // Computes the MST of this edge-weighted tree. Returns the tree in an int[] with parent // pointers and rooted at vertex 0 int[] MST() { // Initialize the list of vertices in the tree // Initially, no one except vertex 0 is in the tree boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; visited[0] = true; // Initialize the int[] that maintains the tree to default values // No vertices have parents set, except vertex 0 whose parent is itself int[] tree = new int[numVertices]; for(int i = 0; i < numVertices; i++) tree[i] = -1; tree[0] = 0; for(int i = 1; i <= numVertices-1; i++) { double minWeight = Double.MAX_VALUE; int bestVertex = -1; int bestParent = -1; for(int j = 0; j < numVertices; j++) { for(int k = 0; k < numVertices; k++) { if((visited[j]) && (!visited[k]) && (isEdge(j, k))) { if(getWeight(j, k).doubleValue() < minWeight) { minWeight = getWeight(j, k).doubleValue(); bestVertex = k; bestParent = j; } // end if better distance is found } // end if an edge between a visited and an unvisited is found } // end for-k } // end for-j // Update visited and tree visited[bestVertex] = true; tree[bestVertex] = bestParent; } // end for-i return tree; } // Computes an MST and returns it as a weighted graph myWeightedGraph MSTGraph() { int[] tree = MST(); myWeightedGraph g = new myWeightedGraph(); // Add all the vertices of this graph to g for(int i = 0; i < numVertices; i++) g.addVertex(names[i]); // Scan the int[] returned by MST, pick out the edges, and add these to g for(int i = 0; i < numVertices; i++) if(tree[i] != i) g.addEdge(i, tree[i], getWeight(i, tree[i]).doubleValue()); return g; } // Computes an MST and returns its total weight double costMST() { int[] tree = MST(); // A variable that accumulates the cost of the minimum spanning tree double cost = 0; // Scan the int[] returned by MST, pick out the edges, and add these to g for(int i = 0; i < numVertices; i++) if(tree[i] != i) cost += getWeight(i, tree[i]); return cost; } // Implementation of Dijkstra's shortest path algorithm int[] DSP(String source) { int sourceIndex = getIndex(source); // Declarations double[] dist = new double[numVertices]; int[] previous = new int[numVertices]; VertexHeap Q = new VertexHeap(numVertices); // Initializations for(int i = 0; i < numVertices; i++) // Initializations { dist[i] = Double.MAX_VALUE; // Unknown distance function from s to v previous[i] = -1; // the array previous stores parent info. // Create a Vertex object corresponding to vertex i and insert into VertexHeap Node v = new Node(dist[i], i, previous[i]); Q.insert(v); } dist[sourceIndex] = 0; // Distance from source to source is set to 0 previous[sourceIndex] = sourceIndex; // parent of sourceIndex is itself Q.change(Q.getIndex(sourceIndex), 0, sourceIndex); // and this is updated in the priority queue as well // The main loop while(!Q.isEmpty()) { Node u = Q.delete(); // Remove best vertex from priority queue; returns source on first iteration int uIndex = u.getIdentity(); // get the neighbors of u int[] nbrs = getNeighbors(uIndex); for(int j = 0; j < nbrs.length; j++) { int vIndex = nbrs[j]; int heapVIndex = Q.getIndex(vIndex); double alt = dist[uIndex] + getWeight(uIndex, vIndex); if(alt < dist[vIndex]) // Relax (u,v) { dist[vIndex] = alt; previous[vIndex] = uIndex; Q.change(heapVIndex, dist[vIndex], uIndex) ; } // end of if alt < dist[vIndex] } // end of for-loop that scans the neighbors } // end of while-Q-is-not-empty return previous; } // end of function // Uses a greedy algorithm to compute a TSP. Returns the TSP in an int[] containing the indices // of the vertices int[] greedyTSP() { //-------------------------BEGIN INITIALIZATION-------------------------------------------- // Find a cheapest triangle // Load triangle 0-1-2 into the the first 3 slots of the greedy array int[] greedy = new int[numVertices]; // Keeps track of lengths of TSPs double currentDistance; double currentBestDistance; greedy[0] = 0; greedy[1] = 1; greedy[2] = 2; // Computes the length of the triangle 0-1-2 if((getWeight(0, 1) == null) || (getWeight(1, 2) == null) || (getWeight(2, 0) == null)) currentBestDistance = Double.MAX_VALUE; else currentBestDistance = getWeight(0, 1).doubleValue() + getWeight(1, 2).doubleValue() + getWeight(2, 0).doubleValue(); // Picks the best triangle for(int i = 0; i < numVertices; i++) for(int j = 0; j < i; j++) for(int k = 0; k < j; k++) { if((getWeight(i, j) != null) && (getWeight(j, k) != null) && (getWeight(i, k) != null)) { currentDistance = getWeight(i, j).doubleValue() + getWeight(j, k).doubleValue() + getWeight(i, k).doubleValue(); if(currentDistance < currentBestDistance) { greedy[0] = i; greedy[1] = j; greedy[2] = k; currentBestDistance = currentDistance; } } } // Set the size of the partial tour constructed thus far int partialTourSize = 3; // Set up the array of visited vertices boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; visited[greedy[0]] = true; visited[greedy[1]] = true; visited[greedy[2]] = true; //System.out.println("The starting triangle is " + names[greedy[0]] + " " + names[greedy[1]] + " " + names[greedy[2]]); //------------------------- END INITIALIZATION-------------------------------------------- // Try greedily to add a city that yields the smallest increase // in the cost of the tour // Main loop: keep repeating until partial tour covers all cities while(partialTourSize < numVertices) { double smallestIncrease = Double.MAX_VALUE; double increase = 0; int bestInsertionPoint = 0; int bestVertex = 0; // Scan through all vertices, stopping at unvisited vertices for(int i = 0; i < numVertices; i++) { if(!visited[i]) { // Consider all possible positions of inserting vertex i into the tour // and record the smallest increase for(int j = 0; j < partialTourSize; j++) { // Compute the increase from inserting vertex i between positions j and j+1 in the // partial TSP array if((getWeight(greedy[j], i) == null) || (getWeight(i, greedy[(j+1)%partialTourSize]) == null)) increase = Double.MAX_VALUE; else if (getWeight(greedy[j], greedy[(j+1)%partialTourSize]) == null) increase = getWeight(greedy[j], i).doubleValue() + getWeight(i, greedy[(j+1)%partialTourSize]).doubleValue() - Double.MAX_VALUE; else increase = getWeight(greedy[j], i).doubleValue() + getWeight(i, greedy[(j+1)%partialTourSize]).doubleValue() - getWeight(greedy[j], greedy[(j+1)%partialTourSize]).doubleValue(); // If the increase is at least as good as the best increase thus far if(increase <= smallestIncrease) { smallestIncrease = increase; bestVertex = i; bestInsertionPoint = j; } // end of if we have found a smaller increase } // end of for-j } // end of if not visited } // end of for-i // Now we are ready to insert the bestVertex at the bestInsertionPoint for(int j = partialTourSize-1; j > bestInsertionPoint; j--) greedy[j+1] = greedy[j]; greedy[bestInsertionPoint+1] = bestVertex; visited[bestVertex] = true; partialTourSize++; } // end-while return greedy; } // Prints a greedy TSP void printGreedyTSP() { int[] greedyTSP = greedyTSP(); for(int i = 0; i < numVertices; i++) System.out.println(names[greedyTSP[i]]); } // Computes the cost of a greedy TSP double costGreedyTSP() { int[] greedyTSP = greedyTSP(); double cost = 0; for(int i = 0; i < numVertices; i++) if(getWeight(greedyTSP[i], greedyTSP[(i+1)%numVertices]) == null) return Double.MAX_VALUE; else cost += getWeight(greedyTSP[i], greedyTSP[(i+1)%numVertices]).doubleValue(); return cost; } // Prints the brute-force TSP void printTSP() { int[] TSP = TSP(); for(int i = 0; i < numVertices; i++) System.out.println(names[TSP[i]]); } // Computes the cost of the brute-force TSP double costTSP() { int[] TSP = TSP(); double cost = 0; for(int i = 0; i < numVertices; i++) if(getWeight(TSP[i], TSP[(i+1)%numVertices]) == null) return Double.MAX_VALUE; else cost += getWeight(TSP[i], TSP[(i+1)%numVertices]).doubleValue(); return cost; } void copy(int[] source, int[] dest) { for(int i = 0; i < dest.length; i++) dest[i] = source[i]; } // A wrapper function for TSP. This returns an optimal TSP as // an integer array int[] TSP() { // Set up the partial TSP int[] R = new int[numVertices]; R[0] = 0; // Set partial tour size to 1 int partialTourSize = 1; // Vertex 0 has been visited. No other vertex has. boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; visited[0] = true; // Call greedy TSP int[] T = greedyTSP(); // Call TSP TSP(R, partialTourSize, visited, T); return T; } void TSP(int[] R, int partialTourSize, boolean[] visited, int[] T) { // Base case: we have discovered a tour better than T if((partialTourSize == numVertices)&&(cost(R) < cost(T))) { System.out.println("Base case. Tour cost is " + cost(R)); copy(R, T); return; } // Another base case: In this base case, we check whether the TSP is // worth completing. We do this by computing the MST of the rest of the // vertices boolean[] unvisited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) unvisited[i] = !visited[i]; myWeightedGraph g = makeInducedSubGraph(unvisited); if (cost(R, partialTourSize) + g.costMST() >= cost(T)) return; // Recursive case: R is not complete and is currently better than T // and is therefore worth completing for(int i = 0; i < numVertices; i++) { if(!visited[i]) { //System.out.println("Appending " + i); visited[i] = true; R[partialTourSize++] = i; TSP(R, partialTourSize, visited, T); partialTourSize--; visited[i] = false; //System.out.println("Deleting " + i); } } // end of for-loop } // end of TSP double cost(int[] tour) { return cost(tour, tour.length); } double cost(int[] tour, int tourSize) { double c = 0; for(int i = 0; i < tourSize; i++) { Double temp = getWeight(tour[i], tour[(i+1)%tourSize]); if(temp == null) return Double.MAX_VALUE; c = c + temp.doubleValue(); } return c; } // Method to compute average degree of the graph // added on 11/24/2007 public double averageDegree() { double sum = 0; for(int i = 0; i < numVertices; i++) sum = sum + degree(i); return sum/numVertices; } // Method to compute maximum degree of the graph // added on 11/24/2007 public int maximumDegree() { int maxDegree = -1; int temp; for(int i = 0; i < numVertices; i++) { temp = degree(i); if(temp > maxDegree) maxDegree = temp; } return maxDegree; } // Method to compute minimum degree of the graph // added on 11/24/2007 public int minimumDegree() { int minDegree = numVertices; int temp; for(int i = 0; i < numVertices; i++) { temp = degree(i); if(temp < minDegree) minDegree = temp; } return minDegree; } // Constructs a weighted graph, induced by a bunch of selected vertices // These selected vertices are represented by a boolean array myWeightedGraph makeInducedSubGraph(boolean[] selectedVertices) { myWeightedGraph g = new myWeightedGraph(); for(int i = 0; i < numVertices; i++) if(selectedVertices[i]) g.addVertex(names[i], x[i], y[i]); for(int i = 0; i < numVertices; i++) for(int j = 0; j < i; j++) if((selectedVertices[i]) && (selectedVertices[j])) { Double d = getWeight(i, j); if(d != null) g.addEdge(names[i], names[j], d.doubleValue()); } return g; } // Constructs a weighted graph, induced by a bunch of selected vertices // These selected vertices are represented by a String array myWeightedGraph makeInducedSubGraph(String[] selectedVertices) { boolean[] turnedOn = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) turnedOn[i] = false; int index; for(int i = 0; i < selectedVertices.length; i++) { index = getIndex(selectedVertices[i]); if(index != -1) turnedOn[index] = true; } return makeInducedSubGraph(turnedOn); } // Constructs a random spanning subgraph of this graph induced by edges along // which an SIR disease may have spread. Parameters of the SIR model, namely // beta and gamma (using Hethcote's notation) are passed in as arguments to the // method. beta is the adequate contact rate and 1/gamma is the average // infectious period myWeightedGraph makePercolatedGraph(double beta, double gamma) { myWeightedGraph g = new myWeightedGraph(); Random rand = new Random(); int[] infectionPeriod = new int[numVertices]; // Add all the vertices of this graph; also compute length of // infection for each vertex for(int i = 0; i < numVertices; i++) { g.addVertex(names[i]); // Find infection period for vertex i. This samples a geometric // distribution with mean 1/gamma and finds the number of days // that vertex i is infected for int numDays = 1; double prob; while(true) { prob = rand.nextDouble(); if(prob <= gamma) break; numDays++; } infectionPeriod[i] = numDays; } for(int i = 0; i < numVertices; i++) { // get the indices of neighbors of vertex i int[] nbrIndices = getNeighbors(i); // scan these neighbors and only look at neighbors with higher index. // This is to ensure that each edge is only considered once for(int j = 0; j < nbrIndices.length; j++) { int currentNbrIndex = nbrIndices[j]; // the number of contacts along this edge per day double d = getWeight(i, nbrIndices[j]).doubleValue()/28; // the probability that infection spread along this edge in a day double r = 1 - java.lang.Math.pow((1 - beta), d); // Run through the number of days that i can be infected for double prob; for(int days = 0; days < infectionPeriod[i]; days++) { prob = rand.nextDouble(); if(prob <= r) g.addEdge(names[i], names[currentNbrIndex]); } } } return g; } // end of make percolated graph } // end of class