/*
* Copyright 2011 Christian Thiemann <christian@spato.net>
* Developed at Northwestern University <http://rocs.northwestern.edu>
*
* This file is part of the SPaTo Visual Explorer (SPaTo).
*
* SPaTo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPaTo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SPaTo. If not, see <http://www.gnu.org/licenses/>.
*/
package net.spato.sve.app;
public class Dijkstra {
/**
* Fibonacci Heap
* http://en.wikipedia.org/wiki/Fibonacci_heap
* http://www.cs.princeton.edu/~wayne/cs423/lectures/fibonacci-4up.pdf
* http://www.cs.princeton.edu/~wayne/cs423/fibonacci/FibonacciHeapAlgorithm.html
* This version only implements what we need for Dijkstra.
* Also, only non-negative integers can be "elements" of the heap.
*/
private static class FibonacciHeap extends Object {
private static class Node {
int element;
float key;
boolean marked;
int degree;
Node prev, next, child, parent; // only one child is pointed to;
// its siblings are organized in a double-linked list via prev/next
Node(int element, float key) { this.element = element; this.key = key;
marked = false; degree = 0;
next = this; prev = this; child = null; parent = null; }
}
int N, Nt; // number of nodes and number of trees
Node nodes[]; // wasteful array to quickly find an element by its "element" value
Node min; // minimum node (the root of the tree)
public FibonacciHeap(int maxElement) {
N = Nt = 0;
min = null;
nodes = new Node[maxElement+1];
}
public void insert(int element, float key) {
Node n = new Node(element, key);
nodes[element] = n; // link in nodes array for quick access
if (min == null) // if heap is empty, this element will be the new minimum
min = n;
else { // otherwise add to the left of min and update min
n.next = min;
n.prev = min.prev;
min.prev = n;
n.prev.next = n;
if (key < min.key)
min = n;
}
N++; Nt++;
}
public int deleteMin() {
if (min == null) return -1; // nothing to do
// calculate max degree
int maxdegree = (int)Math.ceil(Math.log(N)/Math.log(1.619f));
// REMOVE MIN
int element = min.element; // save return value
N--; Nt--; // we'll remove min, thus one root node less in heap
Nt += min.degree; // but we'll add so many new root nodes
// if heap is empty now, set min to null and return
if (N == 0) { min = null; return element; }
// update root list: replace min with its children
if (min.next == min) // min was the only tree left
min = min.child; // min's children are the new root list
else {
if (min.child == null) {
// simply remove min
min.prev.next = min.next;
min.next.prev = min.prev;
} else {
// link last child to right neighbor of min
min.child.prev.next = min.next;
min.next.prev = min.child.prev;
// link first child to left neighbor of min
min.child.prev = min.prev;
min.prev.next = min.child;
}
}
// compile a list of root nodes
Node roots[] = new Node[Nt];
for (int i = 0; i < Nt; i++) {
min = min.next; // get next root node
roots[i] = min; // and add it to the array
roots[i].parent = null; // this overrides all min childrens' parent pointers
roots[i].marked = false; // root nodes should not be marked
}
roots[0].prev = roots[Nt-1]; roots[Nt-1].next = roots[0]; // close cycle again
min = roots[0]; // updating min: first guess...
// CONSOLIDATE
Node A[] = new Node[maxdegree+1]; // degree pointer array
for (int i = 0; i < A.length; i++)
A[i] = null;
for (int i = 0; i < roots.length; i++) {
Node x = roots[i];
while (A[x.degree] != null) { // merge x and y
Node y = A[x.degree];
A[x.degree] = null;
// make sure that x has the lower key of the two
if (y.key < x.key) { Node tmp = y; y = x; x = tmp; }
if (min == y) min = x; // this can happen if y.key == x.key; make sure min stays a pointer to a root
// remove y from root list
y.prev.next = y.next; y.next.prev = y.prev; Nt--;
// make y a child of x and unmark it
y.parent = x;
y.marked = false;
if (x.child == null)
x.child = y.next = y.prev = y;
else {
y.next = x.child.next;
y.next.prev = y;
x.child.next = y;
y.prev = x.child;
}
x.degree++;
}
A[x.degree] = x;
if (x.key < min.key)
min = x;
}
// remove min from easy-access list and return
nodes[element] = null;
return element;
}
public void decreaseKey(int element, float key) {
Node z = nodes[element];
// if element is not on heap or new key is not lower, then there's nothing to do
if ((z == null) || (z.key <= key)) return;
// decrease key of z
z.key = key;
// update tree structure if necessary
if ((z.parent != null) && (z.key < z.parent.key)) {
Node x = z;
do {
// CUT
Node y = x.parent;
// remove x from the child list of y
if (x.next == x) // only child?
y.child = null;
else {
if (y.child == x) y.child = x.next;
x.prev.next = x.next;
x.next.prev = x.prev;
}
y.degree--;
// add x to root list
x.next = min.next; x.next.prev = x;
x.prev = min; min.next = x;
Nt++;
// update accounting
x.marked = false;
x.parent = null;
// CASCADING-CUT decision
if (y.marked) // if parent was already marked
x = y; // now y will cut in the next iteration (if it's not a root node already)
else if (y.parent != null) // if parent was not marked before and is not a root node...
y.marked = true; // ...mark it and leave x as it is (thus x.parent == null and the while-loop will exit)
} while (x.parent != null);
}
// update min pointer
if (z.key < min.key)
min = z;
}
public boolean isEmpty() { return min == null; }
}
public static void calculateShortestPathTree(int edges[][], float weights[][], int i0, int pred[], float dist[]) {
calculateShortestPathTree(edges, weights, i0, pred, dist, false); }
// if useInv is true, 1/weights will be used
public static void calculateShortestPathTree(int edges[][], float weights[][], int i0, int pred[], float dist[], boolean useInv) {
int N = edges.length;
boolean optimal[] = new boolean[N];
FibonacciHeap Q = new FibonacciHeap(N);
for (int i = 0; i < N; i++) {
dist[i] = Float.POSITIVE_INFINITY;
pred[i] = -1;
optimal[i] = false;
Q.insert(i, dist[i]);
}
dist[i0] = 0;
Q.decreaseKey(i0, 0);
while (!Q.isEmpty()) {
int u = Q.deleteMin();
optimal[u] = true;
int edgesu[] = edges[u];
float weightsu[] = weights[u];
float distu = dist[u];
for (int n = 0; n < edgesu.length; n++) {
int v = edgesu[n];
if (optimal[v]) continue;
float alt = distu + (useInv ? 1/weightsu[n] : weightsu[n]);
if (alt < dist[v]) {
dist[v] = alt;
Q.decreaseKey(v, alt);
pred[v] = u;
}
}
}
}
}