]> git.unchartedbackwaters.co.uk Git - francis/ofc.git/commitdiff
Enable topological sorting with priority function.
authorFrancis Russell <francis@unchartedbackwaters.co.uk>
Sat, 7 Apr 2012 19:55:13 +0000 (20:55 +0100)
committerFrancis Russell <francis@unchartedbackwaters.co.uk>
Sat, 7 Apr 2012 20:11:41 +0000 (21:11 +0100)
src/ofc/util/DirectedGraph.scala
src/ofc/util/Queue.scala

index 56f814688cb199186b60b9045e1597a055bdbcc6..6c060d09e8ea81fefaeb05f7c9da434040e9c9f3 100644 (file)
@@ -2,12 +2,10 @@ package ofc.util
 import ofc.LogicError
 
 object DirectedGraph {
-
-  def topoSort(graph: DirectedGraph) : Seq[DirectedGraph#Vertex] = {
+  private def topoSort(graph: DirectedGraph, queue: Queue[DirectedGraph#Vertex]) = {
     type Vertex = DirectedGraph#Vertex
     val degrees = scala.collection.mutable.Map[Vertex, Int]()
     val result = scala.collection.mutable.ArrayBuffer[Vertex]()
-    val queue = new StackQueue[Vertex]()
 
     degrees ++= { for (v <- graph.vertices) yield (v, graph.inDegree(v)) }
     queue ++= { for (v <- graph.vertices; if graph.inDegree(v) == 0) yield v }
@@ -33,6 +31,12 @@ object DirectedGraph {
     if (degrees.values.filter(x => x>0).nonEmpty) throw new LogicError("Cycle in graph.")
     result.toSeq
   }
+
+  def topoSort(graph: DirectedGraph) : Seq[DirectedGraph#Vertex] = 
+    topoSort(graph, new StackQueue[DirectedGraph#Vertex]())
+
+  def topoSort(graph: DirectedGraph, priority: DirectedGraph#Vertex => Int) : Seq[DirectedGraph#Vertex] = 
+    topoSort(graph, new PriorityQueue[DirectedGraph#Vertex](priority))
 }
 
 class DirectedGraph extends GraphBase {
index fea4559f47ef66243e010d60ee38790afe36144b..e93a6080843de942f17e9f57fcf6543506442a62 100644 (file)
@@ -1,12 +1,12 @@
 package ofc.util
 import scala.collection.generic.Growable
 
-private trait Queue[A] extends Growable[A] {
+trait Queue[A] extends Growable[A] {
   def pop() : A
   def nonEmpty : Boolean
 }
 
-private class StackQueue[A] extends Queue[A] {
+class StackQueue[A] extends Queue[A] {
   private var stack = List[A]()
 
   def nonEmpty = stack.nonEmpty
@@ -27,15 +27,34 @@ private class StackQueue[A] extends Queue[A] {
   }
 }
 
-private class PriorityQueue[A](ordering: Ordering[A]) extends Queue[A] {
-  val queue = new scala.collection.mutable.PriorityQueue[A]()(ordering)
+// Nodes with smaller priorities are popped first
+class PriorityQueue[A](priority: A => Int) extends Queue[A] {
+  // This class helps create an artificial total ordering by comparing
+  // unique integers if the compare function is non-total. This is
+  // probably unnecessary since priority queues permit duplicates.
+  private class UniqueOrdering(priority: A => Int)  extends scala.math.Ordering[(A, Int)] {
+    def compare(x: (A, Int), y: (A, Int)) = {
+      val xPri = priority(x._1)
+      val yPri = priority(y._1)
+      val comparison = -xPri.compareTo(yPri)
+      
+      if (comparison != 0)
+        comparison
+      else
+        x._2.compareTo(y._2)
+    }
+  }
+
+  var uniqueID = 0
+  val queue = new scala.collection.mutable.PriorityQueue[(A, Int)]()(new UniqueOrdering(priority))
 
   def nonEmpty = queue.nonEmpty
-  def pop() = queue.dequeue()
+  def pop() = queue.dequeue()._1
   def clear() = queue.clear()
 
   def +=(e: A) = {
-    queue += e
+    queue += (e -> uniqueID)
+    uniqueID += 1
     this
   }
 }