src/Tools/Graphview/layout.scala
author wenzelm
Sat, 03 Jan 2015 20:22:27 +0100
changeset 59245 be4180f3c236
parent 59240 e411afcfaa29
child 59257 a73d2b67897c
permissions -rw-r--r--
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge; misc tuning; tuned signature;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
59232
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
     1
/*  Title:      Tools/Graphview/layout.scala
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     2
    Author:     Markus Kaiser, TU Muenchen
59240
e411afcfaa29 tuned headers;
wenzelm
parents: 59232
diff changeset
     3
    Author:     Makarius
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     4
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     5
Pendulum DAG layout algorithm.
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     6
*/
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     7
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     8
package isabelle.graphview
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     9
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    10
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    11
import isabelle._
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    12
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    13
59232
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
    14
final case class Layout(
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
    15
  nodes: Layout.Coordinates,
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    16
  dummies: Map[Graph_Display.Edge, List[Layout.Point]])
59232
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
    17
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
    18
object Layout
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    19
{
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    20
  type Key = Graph_Display.Node
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    21
  type Point = (Double, Double)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    22
  type Coordinates = Map[Key, Point]
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    23
  type Level = List[Key]
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    24
  type Levels = List[Level]
50469
wenzelm
parents: 50468
diff changeset
    25
59232
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
    26
  val empty = Layout(Map.empty, Map.empty)
50470
wenzelm
parents: 50469
diff changeset
    27
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    28
  val pendulum_iterations = 10
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    29
  val minimize_crossings_iterations = 40
50469
wenzelm
parents: 50468
diff changeset
    30
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    31
  def make(graph: Graph_Display.Graph, box_distance: Double, box_height: Int => Double): Layout =
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    32
  {
59232
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
    33
    if (graph.is_empty) empty
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    34
    else {
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    35
      val initial_levels = level_map(graph)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    36
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    37
      val (dummy_graph, dummies, dummy_levels) =
56372
fadb0fef09d7 more explicit iterator terminology, in accordance to Scala 2.8 library;
wenzelm
parents: 50474
diff changeset
    38
        ((graph, Map.empty[(Key, Key), List[Key]], initial_levels) /: graph.keys_iterator) {
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    39
          case ((graph, dummies, levels), from) =>
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    40
            ((graph, dummies, levels) /: graph.imm_succs(from)) {
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    41
              case ((graph, dummies, levels), to) =>
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    42
                if (levels(to) - levels(from) <= 1) (graph, dummies, levels)
50469
wenzelm
parents: 50468
diff changeset
    43
                else {
wenzelm
parents: 50468
diff changeset
    44
                  val (next, ds, ls) = add_dummies(graph, from, to, levels)
wenzelm
parents: 50468
diff changeset
    45
                  (next, dummies + ((from, to) -> ds), ls)
wenzelm
parents: 50468
diff changeset
    46
                }
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    47
            }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    48
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    49
50469
wenzelm
parents: 50468
diff changeset
    50
      val levels = minimize_crossings(dummy_graph, level_list(dummy_levels))
wenzelm
parents: 50468
diff changeset
    51
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    52
      val initial_coordinates: Coordinates =
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    53
        (((Map.empty[Key, Point], 0.0) /: levels) {
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    54
          case ((coords1, y), level) =>
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    55
            ((((coords1, 0.0) /: level) {
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    56
              case ((coords2, x), key) => (coords2 + (key -> (x, y)), x + box_distance)
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    57
            })._1, y + box_height(level.length))
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    58
        })._1
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    59
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    60
      val coords = pendulum(dummy_graph, box_distance, levels, initial_coordinates)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    61
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    62
      val dummy_coords =
50467
wenzelm
parents: 49746
diff changeset
    63
        (Map.empty[(Key, Key), List[Point]] /: dummies.keys) {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    64
          case (map, key) => map + (key -> dummies(key).map(coords(_)))
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    65
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    66
50470
wenzelm
parents: 50469
diff changeset
    67
      Layout(coords, dummy_coords)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    68
    }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    69
  }
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    70
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    71
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    72
  def add_dummies(graph: Graph_Display.Graph, from: Key, to: Key, levels: Map[Key, Int])
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    73
    : (Graph_Display.Graph, List[Key], Map[Key, Int]) =
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    74
  {
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    75
    val ds =
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    76
      ((levels(from) + 1) until levels(to)).map(l => {
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    77
          // FIXME !?
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    78
          val ident = "%s$%s$%d".format(from.ident, to.ident, l)
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    79
          Graph_Display.Node(ident, ident)
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    80
        }).toList
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    81
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    82
    val ls =
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    83
      (levels /: ((levels(from) + 1) until levels(to)).zip(ds)) {
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    84
        case (ls, (l, d)) => ls + (d -> l)
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    85
      }
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    86
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    87
    val graph1 = (graph /: ds)(_.new_node(_, Nil))
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    88
    val graph2 =
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    89
      (graph1.del_edge(from, to) /: (from :: ds ::: List(to)).sliding(2)) {
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    90
        case (g, List(x, y)) => g.add_edge(x, y)
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    91
      }
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    92
    (graph2, ds, ls)
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    93
  }
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    94
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    95
  def level_map(graph: Graph_Display.Graph): Map[Key, Int] =
50467
wenzelm
parents: 49746
diff changeset
    96
    (Map.empty[Key, Int] /: graph.topological_order) {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    97
      (levels, key) => {
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    98
        val lev = 1 + (-1 /: graph.imm_preds(key)) { case (m, key) => m max levels(key) }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    99
        levels + (key -> lev)
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   100
      }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   101
    }
50469
wenzelm
parents: 50468
diff changeset
   102
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   103
  def level_list(map: Map[Key, Int]): Levels =
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   104
  {
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   105
    val max_lev = (-1 /: map) { case (m, (_, l)) => m max l }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   106
    val buckets = new Array[Level](max_lev + 1)
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   107
    for (l <- 0 to max_lev) { buckets(l) = Nil }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   108
    for ((key, l) <- map) { buckets(l) = key :: buckets(l) }
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   109
    buckets.iterator.map(_.sorted(Graph_Display.Node.Ordering)).toList
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   110
  }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   111
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   112
  def count_crossings(graph: Graph_Display.Graph, levels: Levels): Int =
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   113
  {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   114
    def in_level(ls: Levels): Int = ls match {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   115
      case List(top, bot) =>
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   116
        top.iterator.zipWithIndex.map {
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   117
          case (outer_parent, outer_parent_index) =>
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   118
            graph.imm_succs(outer_parent).iterator.map(bot.indexOf(_))
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   119
            .map(outer_child =>
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   120
              (0 until outer_parent_index)
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   121
              .map(inner_parent =>
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   122
                graph.imm_succs(top(inner_parent)).iterator.map(bot.indexOf(_))
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   123
                .filter(inner_child => outer_child < inner_child)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   124
                .size
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   125
              ).sum
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   126
            ).sum
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   127
        }.sum
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   128
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   129
      case _ => 0
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   130
    }
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   131
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   132
    levels.iterator.sliding(2).map(ls => in_level(ls.toList)).sum
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   133
  }
50469
wenzelm
parents: 50468
diff changeset
   134
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   135
  def minimize_crossings(graph: Graph_Display.Graph, levels: Levels): Levels =
49745
083accbfa77d more conventional Double constants;
wenzelm
parents: 49744
diff changeset
   136
  {
50469
wenzelm
parents: 50468
diff changeset
   137
    def resort_level(parent: Level, child: Level, top_down: Boolean): Level =
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   138
      child.map(k => {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   139
          val ps = if (top_down) graph.imm_preds(k) else graph.imm_succs(k)
50469
wenzelm
parents: 50468
diff changeset
   140
          val weight =
50468
7a2a4b84c5ee tuned min/max;
wenzelm
parents: 50467
diff changeset
   141
            (0.0 /: ps) { (w, p) => w + (0 max parent.indexOf(p)) } / (ps.size max 1)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   142
          (k, weight)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   143
      }).sortBy(_._2).map(_._1)
50469
wenzelm
parents: 50468
diff changeset
   144
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   145
    def resort(levels: Levels, top_down: Boolean) = top_down match {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   146
      case true =>
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   147
        (List[Level](levels.head) /: levels.tail) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   148
          (tops, bot) => resort_level(tops.head, bot, top_down) :: tops
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   149
        }.reverse
50469
wenzelm
parents: 50468
diff changeset
   150
wenzelm
parents: 50468
diff changeset
   151
      case false =>
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   152
        (List[Level](levels.reverse.head) /: levels.reverse.tail) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   153
          (bots, top) => resort_level(bots.head, top, top_down) :: bots
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   154
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   155
      }
50469
wenzelm
parents: 50468
diff changeset
   156
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   157
    ((levels, count_crossings(graph, levels), true) /: (1 to minimize_crossings_iterations)) {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   158
      case ((old_levels, old_crossings, top_down), _) => {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   159
          val new_levels = resort(old_levels, top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   160
          val new_crossings = count_crossings(graph, new_levels)
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   161
          if (new_crossings < old_crossings)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   162
            (new_levels, new_crossings, !top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   163
          else
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   164
            (old_levels, old_crossings, !top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   165
      }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   166
    }._1
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   167
  }
50469
wenzelm
parents: 50468
diff changeset
   168
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   169
  def pendulum(graph: Graph_Display.Graph, box_distance: Double,
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
   170
    levels: Levels, coords: Map[Key, Point]): Coordinates =
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   171
  {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   172
    type Regions = List[List[Region]]
50469
wenzelm
parents: 50468
diff changeset
   173
wenzelm
parents: 50468
diff changeset
   174
    def iteration(regions: Regions, coords: Coordinates, top_down: Boolean)
wenzelm
parents: 50468
diff changeset
   175
      : (Regions, Coordinates, Boolean) =
wenzelm
parents: 50468
diff changeset
   176
    {
wenzelm
parents: 50468
diff changeset
   177
      val (nextr, nextc, moved) =
50467
wenzelm
parents: 49746
diff changeset
   178
      ((List.empty[List[Region]], coords, false) /:
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   179
       (if (top_down) regions else regions.reverse)) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   180
        case ((tops, coords, prev_moved), bot) => {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   181
            val nextb = collapse(coords, bot, top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   182
            val (nextc, this_moved) = deflect(coords, nextb, top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   183
            (nextb :: tops, nextc, prev_moved || this_moved)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   184
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   185
      }
50469
wenzelm
parents: 50468
diff changeset
   186
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   187
      (nextr.reverse, nextc, moved)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   188
    }
50469
wenzelm
parents: 50468
diff changeset
   189
wenzelm
parents: 50468
diff changeset
   190
    def collapse(coords: Coordinates, level: List[Region], top_down: Boolean): List[Region] =
wenzelm
parents: 50468
diff changeset
   191
    {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   192
      if (level.size <= 1) level
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   193
      else {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   194
        var next = level
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   195
        var regions_changed = true
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   196
        while (regions_changed) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   197
          regions_changed = false
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   198
          for (i <- (next.length to 1)) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   199
            val (r1, r2) = (next(i-1), next(i))
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   200
            val d1 = r1.deflection(coords, top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   201
            val d2 = r2.deflection(coords, top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   202
50469
wenzelm
parents: 50468
diff changeset
   203
            if (// Do regions touch?
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
   204
                r1.distance(coords, r2) <= box_distance &&
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   205
                // Do they influence each other?
50469
wenzelm
parents: 50468
diff changeset
   206
                (d1 <= 0 && d2 < d1 || d2 > 0 && d1 > d2 || d1 > 0 && d2 < 0))
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   207
            {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   208
              regions_changed = true
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   209
              r1.nodes = r1.nodes ::: r2.nodes
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   210
              next = next.filter(next.indexOf(_) != i)
50469
wenzelm
parents: 50468
diff changeset
   211
            }
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   212
          }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   213
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   214
        next
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   215
      }
50469
wenzelm
parents: 50468
diff changeset
   216
    }
wenzelm
parents: 50468
diff changeset
   217
wenzelm
parents: 50468
diff changeset
   218
    def deflect(coords: Coordinates, level: List[Region], top_down: Boolean)
wenzelm
parents: 50468
diff changeset
   219
        : (Coordinates, Boolean) =
wenzelm
parents: 50468
diff changeset
   220
    {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   221
      ((coords, false) /: (0 until level.length)) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   222
        case ((coords, moved), i) => {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   223
            val r = level(i)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   224
            val d = r.deflection(coords, top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   225
            val offset = {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   226
              if (i == 0 && d <= 0) d
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   227
              else if (i == level.length - 1 && d >= 0) d
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   228
              else if (d < 0) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   229
                val prev = level(i-1)
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
   230
                (-(r.distance(coords, prev) - box_distance)) max d
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   231
              }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   232
              else {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   233
                val next = level(i+1)
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
   234
                (r.distance(coords, next) - box_distance) min d
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   235
              }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   236
            }
50469
wenzelm
parents: 50468
diff changeset
   237
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   238
            (r.move(coords, offset), moved || (d != 0))
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   239
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   240
      }
50469
wenzelm
parents: 50468
diff changeset
   241
    }
wenzelm
parents: 50468
diff changeset
   242
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   243
    val regions = levels.map(level => level.map(new Region(graph, _)))
50469
wenzelm
parents: 50468
diff changeset
   244
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   245
    ((regions, coords, true, true) /: (1 to pendulum_iterations)) {
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   246
      case ((regions, coords, top_down, moved), _) =>
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   247
        if (moved) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   248
          val (nextr, nextc, m) = iteration(regions, coords, top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   249
          (nextr, nextc, !top_down, m)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   250
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   251
        else (regions, coords, !top_down, moved)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   252
    }._2
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   253
  }
50469
wenzelm
parents: 50468
diff changeset
   254
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   255
  private class Region(val graph: Graph_Display.Graph, node: Key)
50469
wenzelm
parents: 50468
diff changeset
   256
  {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   257
    var nodes: List[Key] = List(node)
50469
wenzelm
parents: 50468
diff changeset
   258
wenzelm
parents: 50468
diff changeset
   259
    def left(coords: Coordinates): Double = nodes.map(coords(_)._1).min
wenzelm
parents: 50468
diff changeset
   260
    def right(coords: Coordinates): Double = nodes.map(coords(_)._1).max
wenzelm
parents: 50468
diff changeset
   261
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   262
    def distance(coords: Coordinates, to: Region): Double =
50468
7a2a4b84c5ee tuned min/max;
wenzelm
parents: 50467
diff changeset
   263
      math.abs(left(coords) - to.left(coords)) min
7a2a4b84c5ee tuned min/max;
wenzelm
parents: 50467
diff changeset
   264
      math.abs(right(coords) - to.right(coords))
50469
wenzelm
parents: 50468
diff changeset
   265
wenzelm
parents: 50468
diff changeset
   266
    def deflection(coords: Coordinates, use_preds: Boolean) =
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   267
      nodes.map(k => (coords(k)._1,
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   268
                      if (use_preds) graph.imm_preds(k).toList  // FIXME iterator
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   269
                      else graph.imm_succs(k).toList))
50468
7a2a4b84c5ee tuned min/max;
wenzelm
parents: 50467
diff changeset
   270
      .map({ case (x, as) => as.map(coords(_)._1 - x).sum / (as.length max 1) })
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   271
      .sum / nodes.length
50469
wenzelm
parents: 50468
diff changeset
   272
wenzelm
parents: 50468
diff changeset
   273
    def move(coords: Coordinates, by: Double): Coordinates =
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   274
      (coords /: nodes) {
50469
wenzelm
parents: 50468
diff changeset
   275
        case (cs, node) =>
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   276
          val (x, y) = cs(node)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   277
          cs + (node -> (x + by, y))
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   278
      }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   279
  }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   280
}