All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aiddl.common.scala.math.graph.Graph2Dot.scala Maven / Gradle / Ivy

package org.aiddl.common.scala.math.graph

import scala.collection.mutable.HashMap
import scala.collection.mutable
import org.aiddl.core.scala.function.Function
import org.aiddl.core.scala.function.Configurable
import org.aiddl.core.scala.representation.*
import org.aiddl.common.scala.math.graph.GraphType.*
import org.aiddl.common.scala.math.graph.Terms.*
import org.aiddl.common.scala.Common.NIL

import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path, Paths}
import sys.process.*
import scala.language.postfixOps

object Graph2Dot {

  def compileDefault(filename: String, fileType: String = "png"): Unit =
    s"dot -T$fileType $filename.dot -o $filename.$fileType" !

  def compileWithPos(filename: String, fileType: String = "png", scale: Int = 70): Unit =
    s"dot -Kfdp -s$scale -T$fileType $filename.dot -o $filename.$fileType" !
}

class Graph2Dot(t: GraphType) extends Function {
  import Terms._
  import GraphType._

  private val edgeStr = t match { case Directed => "->"  case Undirected => "--" }
  private val graphTypeStr = t match { case Directed => "digraph"  case Undirected => "graph" }


  def apply( args: Term ): Term = {
    Str(extract(new AdjacencyListGraph(args)))
  }

  def graph2file( args: Term, fileName: String ): Unit = {
    val graphStr = extract(new AdjacencyListGraph(args))
    Files.write(Paths.get(fileName), graphStr.getBytes(StandardCharsets.UTF_8))
  }

  def graph2file(args: Graph, fileName: String): Unit = {
    val graphStr = extract(args)
    Files.write(Paths.get(fileName), graphStr.getBytes(StandardCharsets.UTF_8))
  }

  def extract( g: Graph ): String = {
    val sb = new mutable.StringBuilder
    sb.append(s"$graphTypeStr {\n")

    val nodeMap = new HashMap[Term, Int]()
    var nextFree = 0

    g.nodes.foreach( u => {
      nextFree += 1
      nodeMap.put(u, nextFree)
      var label = u match {
        case Str(s) => s
        case t => t.toString
      }
      val additional = g.attributes(u) match {
        case Some(atts) => {
          var s = new mutable.StringBuilder
          s append (atts.get(Sym("pos")) match {
            case Some(pos) => s""", pos="${pos(0)},${pos(1)}!""""
            case None => ""
          })
          s append (atts.get(Sym("shape")) match {
            case Some(shape) => s""", shape="${shape}""""
            case None => ""
          })
          s append (atts.get(Sym("style")) match {
            case Some(shape) => s""", style="${shape}""""
            case None => ""
          })
          s append (atts.get(Sym("xlabel")) match {
            case Some(Str(xlabel)) => s""", xlabel="${xlabel}""""
            case Some(xlabel) => s""", xlabel="${xlabel}""""
            case None => ""
          })
          label = atts.get(Sym("label")) match {
            case Some(l) => if (l == NIL) "" else l match {
              case Str(s) => s
              case t => t.toString
            }
            case _ => label
          }
          s.toString
        }
        case None => ""
      }
      sb append s"""\tn$nextFree [label="$label"$additional];\n"""
    })
    sb.append("\n")

    g.edges.map(_.asList.toList).foreach( e => {
      val v1 = e(0)
      val v2 = e(1)
      val eb = new mutable.StringBuilder
      g.weight(v1, v2) match {
        case Some(w) => eb.append(w.toString)
        case None => {}
      }
      g.label(v1, v2) match {
        case Some(l) => {
          if (!eb.isEmpty) eb.append(", ")
          eb.append(if l.isInstanceOf[Str] then l.toString else s"\"$l\"")
        }
        case None => {}
      }
      val additional = g.edgeAttributes(v1, v2) match {
        case Some(atts) => {
          val s = new mutable.StringBuilder
          s append (atts.get(Sym("style")) match {
            case Some(shape) => s""", style="${shape}""""
            case None => ""
          })
          s.toString()
        }
        case None => ""
      }
      val config = if (eb.isEmpty) "" else " [label=" + eb.toString() + s"$additional]"
      sb.append( s"""\tn${nodeMap(v1)} $edgeStr n${nodeMap(v2)}$config;\n""" )
    })
    sb.append("}")
    sb.toString
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy