/* Mutable Directed Graph with Labels */ abstract trait LabDiGraph[Label] { type Vertex type Edge def V : Set[Vertex] def E : Set[Edge] def newVertex : Vertex def += (from : Vertex, lab : Label, to : Vertex) def inEdges(v : Vertex) : Set[Edge] def outEdges(v : Vertex) : Set[Edge] def -= (from : Vertex, lab : Label, to : Vertex) def labelMap[NewLabel](f : Label => NewLabel) : LabDiGraph[NewLabel] } case class LVertex[L](name : String) { var in : Set[LEdge[L]] = Set[LEdge[L]]() var out : Set[LEdge[L]] = Set[LEdge[L]]() override def toString = name } object EdgeCounter { var count = 0 def getNew : String = { count = count + 1 ("e" + count) } } case class LEdge[L](v1 : LVertex[L], lab : L, v2 : LVertex[L]) { val name = EdgeCounter.getNew override def toString = name + ":" + v1 + "-" + lab + "-" + v2 } /* One Implementation of LabDiGraph */ class LabDiGraphImp[Label] extends LabDiGraph[Label] { type Vertex = LVertex[Label] type Edge = LEdge[Label] private var vertices : Set[Vertex] = Set[Vertex]() private var edges : Set[Edge] = Set[Edge]() def V = vertices def E = edges var counter = 0 def newVertex = { counter = counter + 1 new Vertex("v" + counter) } def +=(from : Vertex, lab : Label, to : Vertex) = { val edge = new LEdge[Label](from,lab,to) edges += edge vertices += from vertices += to from.out += edge to.in += edge } def -=(from : Vertex, lab : Label, to : Vertex) = { val edge = new LEdge[Label](from,lab,to) edges -= edge vertices -= from vertices -= to from.out -= edge to.in -= edge } def inEdges(v : Vertex) = v.in def outEdges(v : Vertex) = v.out def labelMap[NewLabel](f : Label => NewLabel) : LabDiGraphImp[NewLabel] = { val g = new LabDiGraphImp[NewLabel] var vertexMap = Map[Vertex, g.Vertex]() for (v <- vertices) { vertexMap += ((v, g.newVertex)) } for (e <- edges) { g += (vertexMap(e.v1), f(e.lab), vertexMap(e.v2)) } g } // --------------------------------------------- // ----------- Visualization ------------------- // --------------------------------------------- override def toString : String = { var res = "{"; var sep = ""; var comma = ", " for (edge <- edges) { res += sep; res += edge; sep = comma } res += "}"; res } def toDotString : String = { var res : StringBuffer = new StringBuffer() def emit(s : String) = res.append(s) def arrow(x : String, y : String) = { emit(" "); emit(x); emit(" -> "); emit(y); emit(";\n") } def makeBoxed(id : String, name : String) = { emit(id); emit("[shape=box,color=lightblue,style=filled,label=\""); emit(name); emit("\"];\n") } emit("digraph D {\n") for (edge <- edges) { val labS = edge.name arrow(edge.v1.name, labS) arrow(labS, edge.v2.name) makeBoxed(labS, edge.lab.toString) } emit("}\n") res.toString } private def exec(command : String) : Unit = { val _ = Runtime.getRuntime.exec(command) () } private def writeTo(fname : String, content : String) : Unit = { import java.io.{BufferedWriter, FileWriter} val out = new BufferedWriter(new FileWriter(fname)) out.write(content) out.close() } val dotFileName = "graph.dot" val psFileName = "graph.ps" def dotGvView : Unit = { writeTo(dotFileName, toDotString) exec("dot " + dotFileName + " -Tps -o" + psFileName) exec("gv " + psFileName) } def dottyView : Unit = { writeTo(dotFileName, toDotString) exec("dotty " + dotFileName) } } object DigraphTest { def main(args : Array[String]) = { val g = new LabDiGraphImp[String] var v1 = g.newVertex var v2 = g.newVertex var v3 = g.newVertex g += (v1,"A",v2) g += (v1,"B",v3) g += (v3,"C",v1) g += (v1,"D",v2) //println(g) //println(g.toDotString) g.dottyView } }