Ticket #7295: use_djikstra_assignment.patch

File use_djikstra_assignment.patch, 38.1 KB (added by joshdoe, 14 years ago)

utils2plugin using Hungarian algorithm for assigning nodes

  • src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/ReplaceGeometryUtils.java

     
    11package org.openstreetmap.josm.plugins.utilsplugin2.replacegeometry;
    22
     3import edu.princeton.cs.algs4.AssignmentProblem;
    34import java.awt.geom.Area;
    45import java.awt.geom.Point2D;
    56import java.util.*;
     
    263264                geometryPool.add(node);
    264265        }
    265266
    266         boolean useHungarian = Main.pref.getBoolean("utilsplugin2.replace-geometry.robustAssignment", false);
     267        boolean useHungarian = Main.pref.getBoolean("utilsplugin2.replace-geometry.robustAssignment", true);
    267268       
    268269        // Find new nodes that are closest to the old ones, remove matching old ones from the pool
    269270        // Assign node moves with least overall distance moved
     
    272273            if (useHungarian) {  // use robust, but slower assignment
    273274                int gLen = geometryPool.size();
    274275                int nLen = nodePool.size();
    275                 double cost[][] = new double[nLen][gLen];
     276                int N = Math.max(gLen, nLen);
     277                double cost[][] = new double[N][N];
     278                for (int i = 0; i < N; i++) {
     279                    for (int j = 0; j < N; j++) {
     280                        cost[i][j] = Double.MAX_VALUE;
     281                    }
     282                }
    276283
    277284                double maxDistance = Double.parseDouble(Main.pref.get("utilsplugin2.replace-geometry.max-distance", "1"));
    278285                for (int i = 0; i < nLen; i++) {
     
    285292                        }
    286293                    }
    287294                }
    288                 int[][] assignment = HungarianAlgorithm.hgAlgorithm(cost, "min");
    289                 for (int i = 0; i < nLen; i++) {
    290                     int nIdx = assignment[i][0];
    291                     int gIdx = assignment[i][1];
     295                AssignmentProblem assignment = new AssignmentProblem(cost);
     296//                int[][] assignment = HungarianAlgorithm.hgAlgorithm(cost, "min");
     297                for (int i = 0; i < N; i++) {
     298//                    int nIdx = assignment[i][0];
     299//                    int gIdx = assignment[i][1];
     300                    int nIdx = i;
     301                    int gIdx = assignment.sol(i);
    292302                    if (cost[nIdx][gIdx] != Double.MAX_VALUE) {
    293303                        nodeAssoc.put(geometryPool.get(gIdx), nodePool.get(nIdx));
    294304                    }
  • src/edu/princeton/cs/algs4/EdgeWeightedDigraph.java

     
     1package edu.princeton.cs.algs4;
     2
     3/*************************************************************************
     4 *  Compilation:  javac EdgeWeightedDigraph.java
     5 *  Execution:    java EdgeWeightedDigraph V E
     6 *  Dependencies: Bag.java DirectedEdge.java
     7 *
     8 *  An edge-weighted digraph, implemented using adjacency lists.
     9 *
     10 *************************************************************************/
     11
     12/**
     13 *  The <tt>EdgeWeightedDigraph</tt> class represents an directed graph of vertices
     14 *  named 0 through V-1, where each edge has a real-valued weight.
     15 *  It supports the following operations: add an edge to the graph,
     16 *  iterate over all of edges leaving a vertex.
     17 *  Parallel edges and self-loops are permitted.
     18 *  <p>
     19 *  For additional documentation, see <a href="http://algs4.cs.princeton.edu/44sp">Section 4.4</a> of
     20 *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
     21 */
     22
     23
     24
     25public class EdgeWeightedDigraph {
     26    private final int V;
     27    private int E;
     28    private Bag<DirectedEdge>[] adj;
     29   
     30    /**
     31     * Create an empty edge-weighted digraph with V vertices.
     32     */
     33    public EdgeWeightedDigraph(int V) {
     34        if (V < 0) throw new RuntimeException("Number of vertices must be nonnegative");
     35        this.V = V;
     36        this.E = 0;
     37        adj = (Bag<DirectedEdge>[]) new Bag[V];
     38        for (int v = 0; v < V; v++)
     39            adj[v] = new Bag<DirectedEdge>();
     40    }
     41
     42   /**
     43     * Create a edge-weighted digraph with V vertices and E edges.
     44     */
     45    public EdgeWeightedDigraph(int V, int E) {
     46        this(V);
     47        if (E < 0) throw new RuntimeException("Number of edges must be nonnegative");
     48        for (int i = 0; i < E; i++) {
     49            int v = (int) (Math.random() * V);
     50            int w = (int) (Math.random() * V);
     51            double weight = Math.round(100 * Math.random()) / 100.0;
     52            DirectedEdge e = new DirectedEdge(v, w, weight);
     53            addEdge(e);
     54        }
     55    }
     56
     57    /**
     58     * Create an edge-weighted digraph from input stream.
     59     */
     60//    public EdgeWeightedDigraph(In in) {
     61//        this(in.readInt());
     62//        int E = in.readInt();
     63//        for (int i = 0; i < E; i++) {
     64//            int v = in.readInt();
     65//            int w = in.readInt();
     66//            double weight = in.readDouble();
     67//            addEdge(new DirectedEdge(v, w, weight));
     68//        }
     69//    }
     70
     71   /**
     72     * Copy constructor.
     73     */
     74    public EdgeWeightedDigraph(EdgeWeightedDigraph G) {
     75        this(G.V());
     76        this.E = G.E();
     77        for (int v = 0; v < G.V(); v++) {
     78            // reverse so that adjacency list is in same order as original
     79            Stack<DirectedEdge> reverse = new Stack<DirectedEdge>();
     80            for (DirectedEdge e : G.adj[v]) {
     81                reverse.push(e);
     82            }
     83            for (DirectedEdge e : reverse) {
     84                adj[v].add(e);
     85            }
     86        }
     87    }
     88
     89   /**
     90     * Return the number of vertices in this digraph.
     91     */
     92    public int V() {
     93        return V;
     94    }
     95
     96   /**
     97     * Return the number of edges in this digraph.
     98     */
     99    public int E() {
     100        return E;
     101    }
     102
     103
     104   /**
     105     * Add the edge e to this digraph.
     106     */
     107    public void addEdge(DirectedEdge e) {
     108        int v = e.from();
     109        adj[v].add(e);
     110        E++;
     111    }
     112
     113
     114   /**
     115     * Return the edges leaving vertex v as an Iterable.
     116     * To iterate over the edges leaving vertex v, use foreach notation:
     117     * <tt>for (DirectedEdge e : graph.adj(v))</tt>.
     118     */
     119    public Iterable<DirectedEdge> adj(int v) {
     120        return adj[v];
     121    }
     122
     123   /**
     124     * Return all edges in this graph as an Iterable.
     125     * To iterate over the edges, use foreach notation:
     126     * <tt>for (DirectedEdge e : graph.edges())</tt>.
     127     */
     128    public Iterable<DirectedEdge> edges() {
     129        Bag<DirectedEdge> list = new Bag<DirectedEdge>();
     130        for (int v = 0; v < V; v++) {
     131            for (DirectedEdge e : adj(v)) {
     132                list.add(e);
     133            }
     134        }
     135        return list;
     136    }
     137
     138   /**
     139     * Return number of edges leaving v.
     140     */
     141    public int outdegree(int v) {
     142        return adj[v].size();
     143    }
     144
     145
     146
     147   /**
     148     * Return a string representation of this graph.
     149     */
     150    public String toString() {
     151        String NEWLINE = System.getProperty("line.separator");
     152        StringBuilder s = new StringBuilder();
     153        s.append(V + " " + E + NEWLINE);
     154        for (int v = 0; v < V; v++) {
     155            s.append(v + ": ");
     156            for (DirectedEdge e : adj[v]) {
     157                s.append(e + "  ");
     158            }
     159            s.append(NEWLINE);
     160        }
     161        return s.toString();
     162    }
     163
     164    /**
     165     * Test client.
     166     */
     167//    public static void main(String[] args) {
     168//        In in = new In(args[0]);
     169//        EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
     170//        StdOut.println(G);
     171//    }
     172
     173}
  • src/edu/princeton/cs/algs4/Stack.java

     
     1package edu.princeton.cs.algs4;
     2
     3/*************************************************************************
     4 *  Compilation:  javac Stack.java
     5 *  Execution:    java Stack < input.txt
     6 *
     7 *  A generic stack, implemented using a linked list. Each stack
     8 *  element is of type Item.
     9 * 
     10 *  % more tobe.txt
     11 *  to be or not to - be - - that - - - is
     12 *
     13 *  % java Stack < tobe.txt
     14 *  to be not that or be (2 left on stack)
     15 *
     16 *************************************************************************/
     17
     18import java.util.Iterator;
     19import java.util.NoSuchElementException;
     20
     21
     22/**
     23 *  The <tt>Stack</tt> class represents a last-in-first-out (LIFO) stack of generic items.
     24 *  It supports the usual <em>push</em> and <em>pop</em> operations, along with methods
     25 *  for peeking at the top item, testing if the stack is empty, and iterating through
     26 *  the items in LIFO order.
     27 *  <p>
     28 *  All stack operations except iteration are constant time.
     29 *  <p>
     30 *  For additional documentation, see <a href="/algs4/13stacks">Section 1.3</a> of
     31 *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
     32 */
     33public class Stack<Item> implements Iterable<Item> {
     34    private int N;          // size of the stack
     35    private Node first;     // top of stack
     36
     37    // helper linked list class
     38    private class Node {
     39        private Item item;
     40        private Node next;
     41    }
     42
     43   /**
     44     * Create an empty stack.
     45     */
     46    public Stack() {
     47        first = null;
     48        N = 0;
     49        assert check();
     50    }
     51
     52   /**
     53     * Is the stack empty?
     54     */
     55    public boolean isEmpty() {
     56        return first == null;
     57    }
     58
     59   /**
     60     * Return the number of items in the stack.
     61     */
     62    public int size() {
     63        return N;
     64    }
     65
     66   /**
     67     * Add the item to the stack.
     68     */
     69    public void push(Item item) {
     70        Node oldfirst = first;
     71        first = new Node();
     72        first.item = item;
     73        first.next = oldfirst;
     74        N++;
     75        assert check();
     76    }
     77
     78   /**
     79     * Delete and return the item most recently added to the stack.
     80     * Throw an exception if no such item exists because the stack is empty.
     81     */
     82    public Item pop() {
     83        if (isEmpty()) throw new RuntimeException("Stack underflow");
     84        Item item = first.item;        // save item to return
     85        first = first.next;            // delete first node
     86        N--;
     87        assert check();
     88        return item;                   // return the saved item
     89    }
     90
     91
     92   /**
     93     * Return the item most recently added to the stack.
     94     * Throw an exception if no such item exists because the stack is empty.
     95     */
     96    public Item peek() {
     97        if (isEmpty()) throw new RuntimeException("Stack underflow");
     98        return first.item;
     99    }
     100
     101   /**
     102     * Return string representation.
     103     */
     104    public String toString() {
     105        StringBuilder s = new StringBuilder();
     106        for (Item item : this)
     107            s.append(item + " ");
     108        return s.toString();
     109    }
     110       
     111
     112    // check internal invariants
     113    private boolean check() {
     114        if (N == 0) {
     115            if (first != null) return false;
     116        }
     117        else if (N == 1) {
     118            if (first == null)      return false;
     119            if (first.next != null) return false;
     120        }
     121        else {
     122            if (first.next == null) return false;
     123        }
     124
     125        // check internal consistency of instance variable N
     126        int numberOfNodes = 0;
     127        for (Node x = first; x != null; x = x.next) {
     128            numberOfNodes++;
     129        }
     130        if (numberOfNodes != N) return false;
     131
     132        return true;
     133    }
     134
     135
     136   /**
     137     * Return an iterator to the stack that iterates through the items in LIFO order.
     138     */
     139    public Iterator<Item> iterator()  { return new ListIterator();  }
     140
     141    // an iterator, doesn't implement remove() since it's optional
     142    private class ListIterator implements Iterator<Item> {
     143        private Node current = first;
     144        public boolean hasNext()  { return current != null;                     }
     145        public void remove()      { throw new UnsupportedOperationException();  }
     146
     147        public Item next() {
     148            if (!hasNext()) throw new NoSuchElementException();
     149            Item item = current.item;
     150            current = current.next;
     151            return item;
     152        }
     153    }
     154
     155
     156   /**
     157     * A test client.
     158     */
     159//    public static void main(String[] args) {
     160//        Stack<String> s = new Stack<String>();
     161//        while (!StdIn.isEmpty()) {
     162//            String item = StdIn.readString();
     163//            if (!item.equals("-")) s.push(item);
     164//            else if (!s.isEmpty()) StdOut.print(s.pop() + " ");
     165//        }
     166//        StdOut.println("(" + s.size() + " left on stack)");
     167//    }
     168}
     169
  • src/edu/princeton/cs/algs4/DirectedEdge.java

     
     1package edu.princeton.cs.algs4;
     2
     3/*************************************************************************
     4 *  Compilation:  javac DirectedEdge.java
     5 *  Execution:    java DirectedEdge
     6 *
     7 *  Immutable weighted directed edge.
     8 *
     9 *************************************************************************/
     10
     11/**
     12 *  The <tt>DirectedEdge</tt> class represents a weighted edge in an directed graph.
     13 *  <p>
     14 *  For additional documentation, see <a href="http://algs4.cs.princeton.edu/44sp">Section 4.4</a> of
     15 *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
     16 */
     17
     18public class DirectedEdge {
     19    private final int v;
     20    private final int w;
     21    private final double weight;
     22
     23   /**
     24     * Create a directed edge from v to w with given weight.
     25     */
     26    public DirectedEdge(int v, int w, double weight) {
     27        this.v = v;
     28        this.w = w;
     29        this.weight = weight;
     30    }
     31
     32   /**
     33     * Return the vertex where this edge begins.
     34     */
     35    public int from() {
     36        return v;
     37    }
     38
     39   /**
     40     * Return the vertex where this edge ends.
     41     */
     42    public int to() {
     43        return w;
     44    }
     45
     46   /**
     47     * Return the weight of this edge.
     48     */
     49    public double weight() { return weight; }
     50
     51   /**
     52     * Return a string representation of this edge.
     53     */
     54    public String toString() {
     55        return v + "->" + w + " " + String.format("%5.2f", weight);
     56    }
     57
     58   /**
     59     * Test client.
     60     */
     61//    public static void main(String[] args) {
     62//        DirectedEdge e = new DirectedEdge(12, 23, 3.14);
     63//        StdOut.println(e);
     64//    }
     65}
  • src/edu/princeton/cs/algs4/Bag.java

     
     1package edu.princeton.cs.algs4;
     2
     3/*************************************************************************
     4 *  Compilation:  javac Bag.java
     5 *  Execution:    java Bag < input.txt
     6 *
     7 *  A generic bag or multiset, implemented using a linked list.
     8 *
     9 *************************************************************************/
     10
     11import java.util.Iterator;
     12import java.util.NoSuchElementException;
     13
     14/**
     15 *  The <tt>Bag</tt> class represents a bag (or multiset) of
     16 *  generic items. It supports insertion and iterating over the
     17 *  items in arbitrary order.
     18 *  <p>
     19 *  The <em>add</em>, <em>isEmpty</em>, and <em>size</em>  operation
     20 *  take constant time. Iteration takes time proportional to the number of items.
     21 *  <p>
     22 *  For additional documentation, see <a href="http://algs4.cs.princeton.edu/13stacks">Section 1.3</a> of
     23 *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
     24 */
     25public class Bag<Item> implements Iterable<Item> {
     26    private int N;         // number of elements in bag
     27    private Node first;    // beginning of bag
     28
     29    // helper linked list class
     30    private class Node {
     31        private Item item;
     32        private Node next;
     33    }
     34
     35   /**
     36     * Create an empty stack.
     37     */
     38    public Bag() {
     39        first = null;
     40        N = 0;
     41        assert check();
     42    }
     43
     44   /**
     45     * Is the BAG empty?
     46     */
     47    public boolean isEmpty() {
     48        return first == null;
     49    }
     50
     51   /**
     52     * Return the number of items in the bag.
     53     */
     54    public int size() {
     55        return N;
     56    }
     57
     58   /**
     59     * Add the item to the bag.
     60     */
     61    public void add(Item item) {
     62        Node oldfirst = first;
     63        first = new Node();
     64        first.item = item;
     65        first.next = oldfirst;
     66        N++;
     67        assert check();
     68    }
     69
     70    // check internal invariants
     71    private boolean check() {
     72        if (N == 0) {
     73            if (first != null) return false;
     74        }
     75        else if (N == 1) {
     76            if (first == null)      return false;
     77            if (first.next != null) return false;
     78        }
     79        else {
     80            if (first.next == null) return false;
     81        }
     82
     83        // check internal consistency of instance variable N
     84        int numberOfNodes = 0;
     85        for (Node x = first; x != null; x = x.next) {
     86            numberOfNodes++;
     87        }
     88        if (numberOfNodes != N) return false;
     89
     90        return true;
     91    }
     92
     93
     94   /**
     95     * Return an iterator that iterates over the items in the bag.
     96     */
     97    public Iterator<Item> iterator()  {
     98        return new ListIterator(); 
     99    }
     100
     101    // an iterator, doesn't implement remove() since it's optional
     102    private class ListIterator implements Iterator<Item> {
     103        private Node current = first;
     104
     105        public boolean hasNext()  { return current != null;                     }
     106        public void remove()      { throw new UnsupportedOperationException();  }
     107
     108        public Item next() {
     109            if (!hasNext()) throw new NoSuchElementException();
     110            Item item = current.item;
     111            current = current.next;
     112            return item;
     113        }
     114    }
     115
     116}
  • src/edu/princeton/cs/algs4/AssignmentProblem.java

     
     1package edu.princeton.cs.algs4;
     2
     3/*************************************************************************
     4 *  Compilation:  javac AssignmentProblem.java
     5 *  Execution:    java AssignmentProblem N
     6 *  Dependencies: DijkstraSP.java DirectedEdge.java
     7 *
     8 *  Solve an N-by-N assignment problem in N^3 log N time using the
     9 *  successive shortest path algorithm.
     10 *
     11 *  Remark: could use dense version of Dijsktra's algorithm for
     12 *  improved theoretical efficiency of N^3, but it doesn't seem to
     13 *  help in practice.
     14 *
     15 *  Assumes N-by-N cost matrix is nonnegative.
     16 *
     17 *
     18 *********************************************************************/
     19
     20public class AssignmentProblem {
     21    private static final int UNMATCHED = -1;
     22
     23    private int N;              // number of rows and columns
     24    private double[][] weight;  // the N-by-N cost matrix
     25    private double[] px;        // px[i] = dual variable for row i
     26    private double[] py;        // py[j] = dual variable for col j
     27    private int[] xy;           // xy[i] = j means i-j is a match
     28    private int[] yx;           // yx[j] = i means i-j is a match
     29
     30 
     31    public AssignmentProblem(double[][] weight) {
     32        N = weight.length;
     33        this.weight = new double[N][N];
     34        for (int i = 0; i < N; i++)
     35            for (int j = 0; j < N; j++)
     36                this.weight[i][j] = weight[i][j];
     37
     38        // dual variables
     39        px = new double[N];
     40        py = new double[N];
     41
     42        // initial matching is empty
     43        xy = new int[N];
     44        yx = new int[N];
     45        for (int i = 0; i < N; i++) xy[i] = UNMATCHED;
     46        for (int j = 0; j < N; j++) yx[j] = UNMATCHED;
     47
     48        // add N edges to matching
     49        for (int k = 0; k < N; k++) {
     50            assert isDualFeasible();
     51            assert isComplementarySlack();
     52            augment();
     53        }
     54        assert check();
     55    }
     56
     57    // find shortest augmenting path and upate
     58    private void augment() {
     59
     60        // build residual graph
     61        EdgeWeightedDigraph G = new EdgeWeightedDigraph(2*N+2);
     62        int s = 2*N, t = 2*N+1;
     63        for (int i = 0; i < N; i++) {
     64            if (xy[i] == UNMATCHED) G.addEdge(new DirectedEdge(s, i, 0.0));
     65        }
     66        for (int j = 0; j < N; j++) {
     67            if (yx[j] == UNMATCHED) G.addEdge(new DirectedEdge(N+j, t, py[j]));
     68        }
     69        for (int i = 0; i < N; i++) {
     70            for (int j = 0; j < N; j++) {
     71                if (xy[i] == j) G.addEdge(new DirectedEdge(N+j, i, 0.0));
     72                else            G.addEdge(new DirectedEdge(i, N+j, reduced(i, j)));
     73            }
     74        }
     75
     76        // compute shortest path from s to every other vertex
     77        DijkstraSP spt = new DijkstraSP(G, s);
     78
     79        // augment along alternating path
     80        for (DirectedEdge e : spt.pathTo(t)) {
     81            int i = e.from(), j = e.to() - N;
     82            if (i < N) {
     83                xy[i] = j;
     84                yx[j] = i;
     85            }
     86        }
     87
     88        // update dual variables
     89        for (int i = 0; i < N; i++) px[i] += spt.distTo(i);
     90        for (int j = 0; j < N; j++) py[j] += spt.distTo(N+j);
     91    }
     92
     93    // reduced cost of i-j
     94    private double reduced(int i, int j) {
     95        return weight[i][j] + px[i] - py[j];
     96    }
     97
     98    // total weight of min weight perfect matching
     99    public double weight() {
     100        double total = 0.0;
     101        for (int i = 0; i < N; i++) {
     102            if (xy[i] != UNMATCHED)
     103                total += weight[i][xy[i]];
     104        }
     105        return total;
     106    }
     107
     108    public int sol(int i) {
     109        return xy[i];
     110    }
     111
     112    // check that dual variables are feasible
     113    private boolean isDualFeasible() {
     114        // check that all edges have >= 0 reduced cost
     115        for (int i = 0; i < N; i++) {
     116            for (int j = 0; j < N; j++) {
     117                if (reduced(i, j) < 0) {
     118//                    StdOut.println("Dual variables are not feasible");
     119                    return false;
     120                }
     121            }
     122        }
     123        return true;
     124    }
     125
     126    // check that primal and dual variables are complementary slack
     127    private boolean isComplementarySlack() {
     128
     129        // check that all matched edges have 0-reduced cost
     130        for (int i = 0; i < N; i++) {
     131            if ((xy[i] != UNMATCHED) && (reduced(i, xy[i]) != 0)) {
     132//                StdOut.println("Primal and dual variables are not complementary slack");
     133                return false;
     134            }
     135        }
     136        return true;
     137    }
     138
     139    // check that primal variables are a perfect matching
     140    private boolean isPerfectMatching() {
     141
     142        // check that xy[] is a perfect matching
     143        boolean[] perm = new boolean[N];
     144        for (int i = 0; i < N; i++) {
     145            if (perm[xy[i]]) {
     146//                StdOut.println("Not a perfect matching");
     147                return false;
     148            }
     149            perm[xy[i]] = true;
     150        }
     151
     152        // check that xy[] and yx[] are inverses
     153        for (int j = 0; j < N; j++) {
     154            if (xy[yx[j]] != j) {
     155//                StdOut.println("xy[] and yx[] are not inverses");
     156                return false;
     157            }
     158        }
     159        for (int i = 0; i < N; i++) {
     160            if (yx[xy[i]] != i) {
     161//                StdOut.println("xy[] and yx[] are not inverses");
     162                return false;
     163            }
     164        }
     165
     166        return true;
     167    }
     168
     169
     170    // check optimality conditions
     171    private boolean check() {
     172        return isPerfectMatching() && isDualFeasible() && isComplementarySlack();
     173    }
     174
     175//    public static void main(String[] args) {
     176//        In in = new In(args[0]);
     177//        int N = in.readInt();
     178//        double[][] weight = new double[N][N];
     179//        for (int i = 0; i < N; i++) {
     180//            for (int j = 0; j < N; j++) {
     181//                weight[i][j] = in.readDouble();
     182//            }
     183//        }
     184//
     185//        AssignmentProblem assignment = new AssignmentProblem(weight);
     186//        StdOut.println("weight = " + assignment.weight());
     187//        for (int i = 0; i < N; i++)
     188//            StdOut.println(i + "-" + assignment.sol(i) + " " + weight[i][assignment.sol(i)]);
     189//    }
     190
     191}
  • src/edu/princeton/cs/algs4/IndexMinPQ.java

     
     1package edu.princeton.cs.algs4;
     2
     3/*************************************************************************
     4 *  Compilation:  javac IndexMinPQ.java
     5 *  Execution:    java IndexMinPQ
     6 *
     7 *  Indexed PQ implementation using a binary heap.
     8 *
     9 *********************************************************************/
     10
     11import java.util.Iterator;
     12import java.util.NoSuchElementException;
     13
     14public class IndexMinPQ<Key extends Comparable<Key>> implements Iterable<Integer> {
     15    private int N;           // number of elements on PQ
     16    private int[] pq;        // binary heap using 1-based indexing
     17    private int[] qp;        // inverse of pq - qp[pq[i]] = pq[qp[i]] = i
     18    private Key[] keys;      // keys[i] = priority of i
     19
     20    public IndexMinPQ(int NMAX) {
     21        keys = (Key[]) new Comparable[NMAX + 1];    // make this of length NMAX??
     22        pq   = new int[NMAX + 1];
     23        qp   = new int[NMAX + 1];                   // make this of length NMAX??
     24        for (int i = 0; i <= NMAX; i++) qp[i] = -1;
     25    }
     26
     27    // is the priority queue empty?
     28    public boolean isEmpty() { return N == 0; }
     29
     30    // is k an index on the priority queue?
     31    public boolean contains(int k) {
     32        return qp[k] != -1;
     33    }
     34
     35    // number of keys in the priority queue
     36    public int size() {
     37        return N;
     38    }
     39
     40    // associate key with index k
     41    public void insert(int k, Key key) {
     42        if (contains(k)) throw new NoSuchElementException("item is already in pq");
     43        N++;
     44        qp[k] = N;
     45        pq[N] = k;
     46        keys[k] = key;
     47        swim(N);
     48    }
     49
     50    // return the index associated with a minimal key
     51    public int minIndex() {
     52        if (N == 0) throw new NoSuchElementException("Priority queue underflow");
     53        return pq[1];       
     54    }
     55
     56    // return a minimal key
     57    public Key minKey() {
     58        if (N == 0) throw new NoSuchElementException("Priority queue underflow");
     59        return keys[pq[1]];       
     60    }
     61
     62    // delete a minimal key and returns its associated index
     63    public int delMin() {
     64        if (N == 0) throw new NoSuchElementException("Priority queue underflow");
     65        int min = pq[1];       
     66        exch(1, N--);
     67        sink(1);
     68        qp[min] = -1;            // delete
     69        keys[pq[N+1]] = null;    // to help with garbage collection
     70        pq[N+1] = -1;            // not needed
     71        return min;
     72    }
     73
     74    // return key associated with index k
     75    public Key keyOf(int k) {
     76        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
     77        else return keys[k];
     78    }
     79
     80    // change the key associated with index k
     81    public void change(int k, Key key) {
     82        changeKey(k, key);
     83    }
     84
     85    // change the key associated with index k
     86    public void changeKey(int k, Key key) {
     87        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
     88        keys[k] = key;
     89        swim(qp[k]);
     90        sink(qp[k]);
     91    }
     92
     93    // decrease the key associated with index k
     94    public void decreaseKey(int k, Key key) {
     95        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
     96        if (keys[k].compareTo(key) <= 0) throw new RuntimeException("illegal decrease");
     97        keys[k] = key;
     98        swim(qp[k]);
     99    }
     100
     101    // increase the key associated with index k
     102    public void increaseKey(int k, Key key) {
     103        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
     104        if (keys[k].compareTo(key) >= 0) throw new RuntimeException("illegal decrease");
     105        keys[k] = key;
     106        sink(qp[k]);
     107    }
     108
     109    // delete the key associated with index k
     110    public void delete(int k) {
     111        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
     112        int index = qp[k];
     113        exch(index, N--);
     114        swim(index);
     115        sink(index);
     116        keys[k] = null;
     117        qp[k] = -1;
     118    }
     119
     120
     121   /**************************************************************
     122    * General helper functions
     123    **************************************************************/
     124    private boolean greater(int i, int j) {
     125        return keys[pq[i]].compareTo(keys[pq[j]]) > 0;
     126    }
     127
     128    private void exch(int i, int j) {
     129        int swap = pq[i]; pq[i] = pq[j]; pq[j] = swap;
     130        qp[pq[i]] = i; qp[pq[j]] = j;
     131    }
     132
     133
     134   /**************************************************************
     135    * Heap helper functions
     136    **************************************************************/
     137    private void swim(int k)  {
     138        while (k > 1 && greater(k/2, k)) {
     139            exch(k, k/2);
     140            k = k/2;
     141        }
     142    }
     143
     144    private void sink(int k) {
     145        while (2*k <= N) {
     146            int j = 2*k;
     147            if (j < N && greater(j, j+1)) j++;
     148            if (!greater(k, j)) break;
     149            exch(k, j);
     150            k = j;
     151        }
     152    }
     153
     154
     155   /***********************************************************************
     156    * Iterators
     157    **********************************************************************/
     158
     159   /**
     160     * Return an iterator that iterates over all of the elements on the
     161     * priority queue in ascending order.
     162     * <p>
     163     * The iterator doesn't implement <tt>remove()</tt> since it's optional.
     164     */
     165    public Iterator<Integer> iterator() { return new HeapIterator(); }
     166
     167    private class HeapIterator implements Iterator<Integer> {
     168        // create a new pq
     169        private IndexMinPQ<Key> copy;
     170
     171        // add all elements to copy of heap
     172        // takes linear time since already in heap order so no keys move
     173        public HeapIterator() {
     174            copy = new IndexMinPQ<Key>(pq.length - 1);
     175            for (int i = 1; i <= N; i++)
     176                copy.insert(pq[i], keys[pq[i]]);
     177        }
     178
     179        public boolean hasNext()  { return !copy.isEmpty();                     }
     180        public void remove()      { throw new UnsupportedOperationException();  }
     181
     182        public Integer next() {
     183            if (!hasNext()) throw new NoSuchElementException();
     184            return copy.delMin();
     185        }
     186    }
     187
     188
     189//    public static void main(String[] args) {
     190//        // insert a bunch of strings
     191//        String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" };
     192//
     193//        IndexMinPQ<String> pq = new IndexMinPQ<String>(strings.length);
     194//        for (int i = 0; i < strings.length; i++) {
     195//            pq.insert(i, strings[i]);
     196//        }
     197//
     198//        // delete and print each key
     199//        while (!pq.isEmpty()) {
     200//            int i = pq.delMin();
     201//            StdOut.println(i + " " + strings[i]);
     202//        }
     203//        StdOut.println();
     204//
     205//        // reinsert the same strings
     206//        for (int i = 0; i < strings.length; i++) {
     207//            pq.insert(i, strings[i]);
     208//        }
     209//
     210//        // print each key using the iterator
     211//        for (int i : pq) {
     212//            StdOut.println(i + " " + strings[i]);
     213//        }
     214//        while (!pq.isEmpty()) {
     215//            pq.delMin();
     216//        }
     217//
     218//    }
     219}
  • src/edu/princeton/cs/algs4/DijkstraSP.java

     
     1package edu.princeton.cs.algs4;
     2
     3/*************************************************************************
     4 *  Compilation:  javac DijkstraSP.java
     5 *  Execution:    java DijkstraSP input.txt s
     6 *  Dependencies: EdgeWeightedDigraph.java IndexMinPQ.java Stack.java DirectedEdge.java
     7 *  Data files:   http://algs4.cs.princeton.edu/44sp/tinyEWD.txt
     8 *                http://algs4.cs.princeton.edu/44sp/mediumEWD.txt
     9 *                http://algs4.cs.princeton.edu/44sp/largeEWD.txt
     10 *
     11 *  Dijkstra's algorithm. Computes the shortest path tree.
     12 *  Assumes all weights are nonnegative.
     13 *
     14 *  % java DijkstraSP tinyEWD.txt 0
     15 *  0 to 0 (0.00) 
     16 *  0 to 1 (1.05)  0->4  0.38   4->5  0.35   5->1  0.32   
     17 *  0 to 2 (0.26)  0->2  0.26   
     18 *  0 to 3 (0.99)  0->2  0.26   2->7  0.34   7->3  0.39   
     19 *  0 to 4 (0.38)  0->4  0.38   
     20 *  0 to 5 (0.73)  0->4  0.38   4->5  0.35   
     21 *  0 to 6 (1.51)  0->2  0.26   2->7  0.34   7->3  0.39   3->6  0.52   
     22 *  0 to 7 (0.60)  0->2  0.26   2->7  0.34   
     23 *
     24 *  % java DijkstraSP mediumEWD.txt 0
     25 *  0 to 0 (0.00) 
     26 *  0 to 1 (0.71)  0->44  0.06   44->93  0.07   ...  107->1  0.07   
     27 *  0 to 2 (0.65)  0->44  0.06   44->231  0.10  ...  42->2  0.11   
     28 *  0 to 3 (0.46)  0->97  0.08   97->248  0.09  ...  45->3  0.12   
     29 *  0 to 4 (0.42)  0->44  0.06   44->93  0.07   ...  77->4  0.11   
     30 *  ...
     31 *
     32 *************************************************************************/
     33
     34public class DijkstraSP {
     35    private double[] distTo;          // distTo[v] = distance  of shortest s->v path
     36    private DirectedEdge[] edgeTo;    // edgeTo[v] = last edge on shortest s->v path
     37    private IndexMinPQ<Double> pq;    // priority queue of vertices
     38
     39    public DijkstraSP(EdgeWeightedDigraph G, int s) {
     40        distTo = new double[G.V()];
     41        edgeTo = new DirectedEdge[G.V()];
     42        for (int v = 0; v < G.V(); v++)
     43            distTo[v] = Double.POSITIVE_INFINITY;
     44        distTo[s] = 0.0;
     45
     46        // relax vertices in order of distance from s
     47        pq = new IndexMinPQ<Double>(G.V());
     48        pq.insert(s, distTo[s]);
     49        while (!pq.isEmpty()) {
     50            int v = pq.delMin();
     51            for (DirectedEdge e : G.adj(v))
     52                relax(e);
     53        }
     54
     55        // check optimality conditions
     56        assert check(G, s);
     57    }
     58
     59    // relax edge e and update pq if changed
     60    private void relax(DirectedEdge e) {
     61        int v = e.from(), w = e.to();
     62        if (distTo[w] > distTo[v] + e.weight()) {
     63            distTo[w] = distTo[v] + e.weight();
     64            edgeTo[w] = e;
     65            if (pq.contains(w)) pq.change(w, distTo[w]);
     66            else                pq.insert(w, distTo[w]);
     67        }
     68    }
     69
     70    // length of shortest path from s to v
     71    public double distTo(int v) {
     72        return distTo[v];
     73    }
     74
     75    // is there a path from s to v?
     76    public boolean hasPathTo(int v) {
     77        return distTo[v] < Double.POSITIVE_INFINITY;
     78    }
     79
     80    // shortest path from s to v as an Iterable, null if no such path
     81    public Iterable<DirectedEdge> pathTo(int v) {
     82        if (!hasPathTo(v)) return null;
     83        Stack<DirectedEdge> path = new Stack<DirectedEdge>();
     84        for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) {
     85            path.push(e);
     86        }
     87        return path;
     88    }
     89
     90
     91    // check optimality conditions:
     92    // (i) for all edges e:            distTo[e.to()] <= distTo[e.from()] + e.weight()
     93    // (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight()
     94    private boolean check(EdgeWeightedDigraph G, int s) {
     95
     96        // check that edge weights are nonnegative
     97        for (DirectedEdge e : G.edges()) {
     98            if (e.weight() < 0) {
     99                System.err.println("negative edge weight detected");
     100                return false;
     101            }
     102        }
     103
     104        // check that distTo[v] and edgeTo[v] are consistent
     105        if (distTo[s] != 0.0 || edgeTo[s] != null) {
     106            System.err.println("distTo[s] and edgeTo[s] inconsistent");
     107            return false;
     108        }
     109        for (int v = 0; v < G.V(); v++) {
     110            if (v == s) continue;
     111            if (edgeTo[v] == null && distTo[v] != Double.POSITIVE_INFINITY) {
     112                System.err.println("distTo[] and edgeTo[] inconsistent");
     113                return false;
     114            }
     115        }
     116
     117        // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight()
     118        for (int v = 0; v < G.V(); v++) {
     119            for (DirectedEdge e : G.adj(v)) {
     120                int w = e.to();
     121                if (distTo[v] + e.weight() < distTo[w]) {
     122                    System.err.println("edge " + e + " not relaxed");
     123                    return false;
     124                }
     125            }
     126        }
     127
     128        // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight()
     129        for (int w = 0; w < G.V(); w++) {
     130            if (edgeTo[w] == null) continue;
     131            DirectedEdge e = edgeTo[w];
     132            int v = e.from();
     133            if (w != e.to()) return false;
     134            if (distTo[v] + e.weight() != distTo[w]) {
     135                System.err.println("edge " + e + " on shortest path not tight");
     136                return false;
     137            }
     138        }
     139        return true;
     140    }
     141
     142
     143//    public static void main(String[] args) {
     144//        In in = new In(args[0]);
     145//        EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
     146//        int s = Integer.parseInt(args[1]);
     147//
     148//        // compute shortest paths
     149//        DijkstraSP sp = new DijkstraSP(G, s);
     150//
     151//
     152//        // print shortest path
     153//        for (int t = 0; t < G.V(); t++) {
     154//            if (sp.hasPathTo(t)) {
     155//                StdOut.printf("%d to %d (%.2f)  ", s, t, sp.distTo(t));
     156//                if (sp.hasPathTo(t)) {
     157//                    for (DirectedEdge e : sp.pathTo(t)) {
     158//                        StdOut.print(e + "   ");
     159//                    }
     160//                }
     161//                StdOut.println();
     162//            }
     163//            else {
     164//                StdOut.printf("%d to %d         no path\n", s, t);
     165//            }
     166//        }
     167//    }
     168
     169}