Advertisement
nlw

A little kooky DAG class

nlw
May 19th, 2015
306
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 4.35 KB | None | 0 0
  1. case class cycleException(es: String) extends Exception(es)
  2.  
  3. case class Edge(a: Int, b: Int) {
  4.   def t = Edge(b, a)
  5. }
  6.  
  7. object KookyDAG {
  8.   def empty = KookyDAG(Vector(), Vector())
  9. }
  10.  
  11. /** A DAG with a list of all the paths, that allows you to find out the successors and ancestors from each node, and to
  12.   * easily check for cycles -- and for paths.
  13.   *
  14.   * @param edges a `Vector` with tuples representing each edge, origin -> destiny.
  15.   * @param paths a list of all paths, calculated via `append` or `remove`.
  16.   */
  17. case class KookyDAG(edges: Vector[Edge], paths: Vector[Edge]) {
  18.  
  19.   def append(ed: Edge) = {
  20.     if (paths contains ed.t) throw cycleException("This edge would close a cycle in the DAG")
  21.     if (edges contains ed) this
  22.     else KookyDAG(edges :+ ed, paths ++ find_paths(ed))
  23.   }
  24.  
  25.   def remove(ed: Edge) =
  26.     if (edges contains ed) KookyDAG(edges diff Vector(ed), paths diff find_paths(ed))
  27.     else this
  28.  
  29.   /** @param ab input edge.
  30.     * @return list of paths that (might) contain the given edge.
  31.     */
  32.   def find_paths(ab: Edge) = for (o <- origins(ab.a); d <- destinies(ab.b)) yield Edge(o, d)
  33.  
  34.   /** @param from input node
  35.     * @return list of nodes with paths to the given edge
  36.     */
  37.   def origins(from: Int): Vector[Int] = from +: (paths filter (_.b == from) map (_.a))
  38.  
  39.   /** @param from input node
  40.     * @return list of nodes with paths starting from the given node
  41.     */
  42.   def destinies(from: Int): Vector[Int] = from +: (paths filter (_.a == from) map (_.b))
  43. }
  44.  
  45. case class SpartanKookyDAG(edges: Vector[Edge], paths: Vector[Edge]) {
  46.  
  47.   def append(ed: Edge) = {
  48.     if (paths contains ed.t) throw cycleException("This edge would close a cycle in the DAG")
  49.     else if (edges contains ed) this
  50.     else KookyDAG(edges union Vector(ed), paths union find_paths(ed))
  51.   }
  52.  
  53.   def remove(ed: Edge) =
  54.     if (!(edges contains ed)) this
  55.     else KookyDAG(edges diff Vector(ed), paths diff find_paths(ed))
  56.  
  57.   def find_paths(ab: Edge) =
  58.     for {
  59.       o <- ab.a +: (paths filter (_.b == ab.a) map (_.a))
  60.       d <- ab.b +: (paths filter (_.a == ab.b) map (_.b))
  61.     } yield Edge(o, d)
  62. }
  63.  
  64. object MyMain extends App {
  65.  
  66.   var kd = KookyDAG.empty
  67.  
  68.   for (ed <- Seq(Edge(1, 2), Edge(2, 3), Edge(4, 5), Edge(1, 5), Edge(3, 4), Edge(2, 4))) {
  69.     kd = kd.append(ed)
  70.     println(kd)
  71.   }
  72.  
  73.   for (ed <- Seq(Edge(2, 3), Edge(4, 5), Edge(1, 5), Edge(3, 4), Edge(1, 2), Edge(2, 4))) {
  74.     kd = kd.remove(ed)
  75.     println(kd)
  76.   }
  77.  
  78.   kd = KookyDAG.empty.append(Edge(1, 2)).append(Edge(2, 3)).append(Edge(1, 3))
  79.   println(kd)
  80.   try {
  81.     kd = KookyDAG.empty.append(Edge(1, 2)).append(Edge(2, 3)).append(Edge(3, 1))
  82.     println(kd)
  83.   }
  84.   catch {
  85.     case cycleException(es) => println(es)
  86.   }
  87. }
  88.  
  89.  
  90.  
  91. /*
  92. /usr/lib/jvm/java-7-openjdk-amd64/bin/java (...) com.intellij.rt.execution.application.AppMain MyMain
  93. KookyDAG(Vector(Edge(1,2)),Vector(Edge(1,2)))
  94. KookyDAG(Vector(Edge(1,2), Edge(2,3)),Vector(Edge(1,2), Edge(2,3), Edge(1,3)))
  95. KookyDAG(Vector(Edge(1,2), Edge(2,3), Edge(4,5)),Vector(Edge(1,2), Edge(2,3), Edge(1,3), Edge(4,5)))
  96. KookyDAG(Vector(Edge(1,2), Edge(2,3), Edge(4,5), Edge(1,5)),Vector(Edge(1,2), Edge(2,3), Edge(1,3), Edge(4,5), Edge(1,5)))
  97. KookyDAG(Vector(Edge(1,2), Edge(2,3), Edge(4,5), Edge(1,5), Edge(3,4)),Vector(Edge(1,2), Edge(2,3), Edge(1,3), Edge(4,5), Edge(1,5), Edge(3,4), Edge(3,5), Edge(2,4), Edge(2,5), Edge(1,4), Edge(1,5)))
  98. KookyDAG(Vector(Edge(1,2), Edge(2,3), Edge(4,5), Edge(1,5), Edge(3,4), Edge(2,4)),Vector(Edge(1,2), Edge(2,3), Edge(1,3), Edge(4,5), Edge(1,5), Edge(3,4), Edge(3,5), Edge(2,4), Edge(2,5), Edge(1,4), Edge(1,5), Edge(2,4), Edge(2,5), Edge(1,4), Edge(1,5)))
  99. KookyDAG(Vector(Edge(1,2), Edge(4,5), Edge(1,5), Edge(3,4), Edge(2,4)),Vector(Edge(1,2), Edge(4,5), Edge(3,4), Edge(3,5), Edge(1,5), Edge(2,4), Edge(2,5), Edge(1,4), Edge(1,5)))
  100. KookyDAG(Vector(Edge(1,2), Edge(1,5), Edge(3,4), Edge(2,4)),Vector(Edge(1,2), Edge(3,4), Edge(2,4), Edge(1,4), Edge(1,5)))
  101. KookyDAG(Vector(Edge(1,2), Edge(3,4), Edge(2,4)),Vector(Edge(1,2), Edge(3,4), Edge(2,4), Edge(1,4)))
  102. KookyDAG(Vector(Edge(1,2), Edge(2,4)),Vector(Edge(1,2), Edge(2,4), Edge(1,4)))
  103. KookyDAG(Vector(Edge(2,4)),Vector(Edge(2,4)))
  104. KookyDAG(Vector(),Vector())
  105. KookyDAG(Vector(Edge(1,2), Edge(2,3), Edge(1,3)),Vector(Edge(1,2), Edge(2,3), Edge(1,3), Edge(1,3)))
  106. This edge would close a cycle in the DAG
  107.  
  108. Process finished with exit code 0
  109. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement