From c202da87a4ce75c34662cf471735dff5d7b14fd1 Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <ekneuss@gmail.com> Date: Tue, 2 Feb 2016 13:30:28 +0100 Subject: [PATCH] Print new graphs to graphviz format --- src/main/scala/leon/utils/GraphPrinters.scala | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 src/main/scala/leon/utils/GraphPrinters.scala diff --git a/src/main/scala/leon/utils/GraphPrinters.scala b/src/main/scala/leon/utils/GraphPrinters.scala new file mode 100644 index 000000000..b86882f2d --- /dev/null +++ b/src/main/scala/leon/utils/GraphPrinters.scala @@ -0,0 +1,215 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +package leon +package utils + +import Graphs._ + +object GraphPrinters { + abstract class Printer[N, E <: EdgeLike[N], G <: DiGraphLike[N, E, G]] { + + def asString(g: G): String + + def asFile(g: G, file: String) { + import java.io.{BufferedWriter, FileWriter} + val out = new BufferedWriter(new FileWriter(file)) + out.write(asString(g)) + out.close() + } + } + + case class DotNode(label: String, opts: Map[String, String] = Map()) { + def toOpts(dot: DotHelpers): String = { + s"""[label="${dot.escape(label)}"]""" + } + } + + class DotPrinter[N, E <: EdgeLike[N], G <: DiGraphLike[N, E, G]] extends Printer[N, E, G] { + + val dot = new DotHelpers + + private var nToLabel: N => String = { (n: N) => n.toString } + + private var nToOpts: Seq[N => Seq[(String, String)]] = Nil + + def setNodeLabel(f: N => String): Unit = { + nToLabel = f + } + + def colorize(f: N => Boolean, color: String) = { + nToOpts :+= { (n: N) => + if (f(n)) List(("color", color)) else Nil + } + } + + def highlight(f: N => Boolean) = colorize(f, "red") + + + def drawNode(n: N)(implicit res: StringBuffer): Unit = { + var opts = Map[String, String]() + opts += "label" -> ("\"" + dot.escape(nToLabel(n)) + "\"") + + for (f <- nToOpts) { + opts ++= f(n) + } + + res append (nToS(n) +" "+opts.map{ case (n, v) => s"$n=$v" }.mkString("[", ", ", "]")+";\n") + } + + def nToS(n: N): String = { + dot.uniqueName("n", n) + } + + def eToS(e: EdgeLike[N]): String = { + dot.uniqueName("e", e) + } + + def drawEdge(e: E)(implicit res: StringBuffer): Unit = { + e match { + case le: LabeledEdge[_, N] => + res append dot.box(eToS(e), le.l.toString) + res append dot.arrow(nToS(e._1), eToS(e)) + res append dot.arrow(eToS(e), nToS(e._2)) + case _ => + res append dot.arrow(nToS(e._1), nToS(e._2)) + } + } + + def asString(g: G): String = { + implicit val res = new StringBuffer() + + res append "digraph D {\n" + + g.N.foreach(drawNode) + + g.E.foreach(drawEdge) + + res append "}\n" + + res.toString + } + } + + class DotHelpers { + private var _nextName = 0 + private var _nextColor = 0 + + private def nextName = { + _nextName += 1 + _nextName.toString + } + + private var names = Map[Any, String]() + + def uniqueName(prefix: String, obj: Any) = { + if (!names.contains(obj)) { + names = names + (obj -> (prefix+nextName)) + } + + names(obj) + } + + val bgColors = List("bisque", "khaki", "mistyrose", "lightcyan", "mediumorchid", "aquamarine", "antiquewhite") + + def nextColor = { + _nextColor += 1 + val colornumber: String = if((_nextColor/bgColors.size)%3 == 0) "" else ((_nextColor/bgColors.size)%3)+""; + bgColors(_nextColor%bgColors.size)+colornumber + } + + val colors = List("khaki", "khaki1", "khaki2", "khaki3", + "khaki4", "lavender", "lavenderblush", "lavenderblush1", "lavenderblush2", + "lavenderblush3", "lavenderblush4", "lawngreen", "lemonchiffon", + "lemonchiffon1", "lemonchiffon2", "lemonchiffon3", "lemonchiffon4", + "lightblue", "lightblue1", "lightblue2", "lightblue3", "lightblue4", + "lightcoral", "lightcyan", "lightcyan1", "lightcyan2", "lightcyan3", + "lightcyan4", "lightgoldenrod", "lightgoldenrod1", "lightgoldenrod2", + "lightgoldenrod3", "lightgoldenrod4", "lightgoldenrodyellow", "lightgray", + "lightgrey", "lightpink", "lightpink1", "lightpink2", "lightpink3", + "lightpink4", "lightsalmon", "lightsalmon1", "lightsalmon2", "lightsalmon3", + "lightsalmon4", "lightseagreen", "lightskyblue", "lightskyblue1", + "lightskyblue2", "lightskyblue3", "lightskyblue4", "lightslateblue", + "lightslategray", "lightslategrey", "lightsteelblue", "lightsteelblue1", + "lightsteelblue2", "lightsteelblue3", "lightsteelblue4", "lightyellow", + "lightyellow1", "lightyellow2", "lightyellow3", "lightyellow4", "limegreen", + "linen", "magenta", "magenta1", "magenta2", "magenta3", "magenta4", "maroon", + "maroon1", "maroon2", "maroon3", "maroon4", "mediumaquamarine", "mediumblue", + "mediumorchid", "mediumorchid1", "mediumorchid2", "mediumorchid3", + "mediumorchid4", "mediumpurple", "mediumpurple1", "mediumpurple2", + "mediumpurple3", "mediumpurple4", "mediumseagreen", "mediumslateblue", + "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", + "mintcream", "mistyrose", "mistyrose1", "mistyrose2", "mistyrose3", + "mistyrose4", "moccasin", "navajowhite", "navajowhite1", "navajowhite2", + "navajowhite3", "navajowhite4", "navy", "navyblue", "none", "oldlace", + "olivedrab", "olivedrab1", "olivedrab2", "olivedrab3", "olivedrab4", "orange", + "orange1", "orange2", "orange3", "orange4", "orangered", "orangered1", + "orangered2", "orangered3", "orangered4", "orchid", "orchid1", "orchid2", + "orchid3", "orchid4", "palegoldenrod", "palegreen", "palegreen1", "palegreen2", + "palegreen3", "palegreen4", "paleturquoise", "paleturquoise1", + "paleturquoise2", "paleturquoise3", "paleturquoise4", "palevioletred", + "palevioletred1", "palevioletred2", "palevioletred3", "palevioletred4", + "papayawhip", "peachpuff", "peachpuff1", "peachpuff2", "peachpuff3", + "peachpuff4", "peru", "pink", "pink1", "pink2", "pink3", "pink4", "plum", + "plum1", "plum2", "plum3", "plum4", "powderblue", "purple", "purple1", + "purple2", "purple3", "purple4", "red", "red1", "red2", "red3", "red4", + "rosybrown", "rosybrown1", "rosybrown2", "rosybrown3", "rosybrown4", + "royalblue", "royalblue1", "royalblue2", "royalblue3", "royalblue4", + "saddlebrown", "salmon", "salmon1", "salmon2", "salmon3", "salmon4", + "sandybrown", "seagreen", "seagreen1", "seagreen2", "seagreen3", "seagreen4", + "seashell", "seashell1", "seashell2", "seashell3", "seashell4", "sienna", + "sienna1", "sienna2", "sienna3", "sienna4", "skyblue", "skyblue1", "skyblue2", + "skyblue3", "skyblue4", "slateblue", "slateblue1", "slateblue2", "slateblue3", + "slateblue4", "slategray", "slategray1", "slategray2", "slategray3", + "slategray4", "slategrey", "snow", "snow1", "snow2", "snow3", "snow4", + "springgreen", "springgreen1", "springgreen2", "springgreen3", "springgreen4", + "steelblue", "steelblue1", "steelblue2", "steelblue3", "steelblue4", "tan", + "tan1", "tan2", "tan3", "tan4", "thistle", "thistle1", "thistle2", "thistle3", + "thistle4", "tomato", "tomato1", "tomato2", "tomato3", "tomato4", + "transparent", "turquoise", "turquoise1", "turquoise2", "turquoise3", + "turquoise4", "violet", "violetred", "violetred1", "violetred2", "violetred3", + "violetred4", "wheat", "wheat1", "wheat2", "wheat3", "wheat4", "white", + "whitesmoke", "yellow", "yellow1", "yellow2", "yellow3", "yellow4", + "yellowgreen"); + + def randomColor = { + _nextColor += 1 + colors(_nextColor % colors.size) + } + + def escape(s: String) = + s.replaceAll("\\\\n", "__NEWLINE__") + .replaceAll("\\\\", "\\\\\\\\") + .replaceAll("\"", "\\\\\"") + .replaceAll("\\\n", "\\\\n") + .replaceAll("[^<>@a-zA-Z0-9;$.,!# \t=^:_\\\\\"'*+/&()\\[\\]{}\u03B5-]", "?") + .replaceAll("__NEWLINE__", "\\\\n") + + def escapeStrict(s: String) = s.replaceAll("[^a-zA-Z0-9_]", "_") + + def labeledArrow(x: String, label: String, y: String, options: List[String] = Nil) = + arrow(x, y, "label=\""+escape(label)+"\"" :: options) + + def labeledDashedArrow(x: String, label: String, y: String, options: List[String] = Nil) = + arrow(x, y, "label=\""+escape(label)+"\"" :: "style=dashed" :: options) + + def arrow(x: String, y: String, options: List[String] = Nil) = { + " "+x+" -> "+y+options.mkString(" [", " ", "]")+";\n" + } + + def box(id : String, name : String, options: List[String] = Nil) = { + node(id, name, "shape=box" :: "color=lightblue" :: "style=filled" :: options) + } + + def invisNode(id : String, name : String, options: List[String] = Nil) = { + node(id, name, "shape=none" :: options) + } + + def dashedNode(id : String, name : String, options: List[String] = Nil) = { + node(id, name, "style=dashed" :: options) + } + + def node(id: String, name: String, options: List[String] = Nil) = { + id +("label=\""+escape(name)+"\"" :: options).mkString(" [", ", ", "]")+";\n" + } + } +} -- GitLab