LARA

/* 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
  }
}