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

com.github.mdr.ascii.graph.Graph.scala Maven / Gradle / Ivy

The newest version!
package com.github.mdr.ascii.graph

import scala.PartialFunction.cond

import com.github.mdr.ascii.diagram.Diagram
import com.github.mdr.ascii.layout.GraphLayout
import com.github.mdr.ascii.util.Utils
import com.github.mdr.ascii.util.Utils._

object Graph {

  def fromDiagram(s: String): Graph[String] = fromDiagram(Diagram(s))

  def fromDiagram(diagram: Diagram): Graph[String] = DiagramToGraphConvertor.toGraph(diagram)

}

/**
 * A directed graph, allowing multi-edges and loops.
 *
 * Two vertex objects are considered indistinguishable if they compare the same via .equals().
 *
 * @param edges, vertices in the edges must be present in the vertices.
 */
case class Graph[V](vertices: Set[V], edges: List[(V, V)]) {

  val outMap: Map[V, List[V]] = edges.groupBy(_._1).map { case (k, vs) ⇒ (k, vs.map(_._2)) }

  val inMap: Map[V, List[V]] = edges.groupBy(_._2).map { case (k, vs) ⇒ (k, vs.map(_._1)) }

  require(outMap.keys.forall(vertices.contains))

  require(inMap.keys.forall(vertices.contains))

  def isEmpty = vertices.isEmpty

  def inEdges(v: V): List[(V, V)] = edges.filter(_._2 == v)

  def outEdges(v: V): List[(V, V)] = edges.filter(_._1 == v)

  def inVertices(v: V): List[V] = inMap.getOrElse(v, Nil)

  def outVertices(v: V): List[V] = outMap.getOrElse(v, Nil)

  def outDegree(v: V): Int = outVertices(v).size

  def inDegree(v: V): Int = inVertices(v).size

  def sources: List[V] = vertices.toList.filter(inDegree(_) == 0)

  def sinks: List[V] = vertices.toList.filter(outDegree(_) == 0)

  def removeEdge(edge: (V, V)): Graph[V] = copy(edges = Utils.removeFirst(edges, edge))

  def removeVertex(v: V): Graph[V] =
    Graph(vertices.filterNot(_ == v), edges.filterNot { case (v1, v2) ⇒ v1 == v || v2 == v })

  def map[U](f: V ⇒ U): Graph[U] =
    Graph(vertices.map(f), edges.map { case (v1, v2) ⇒ (f(v1), f(v2)) })

  override lazy val hashCode = vertices.## + edges.##

  override def equals(obj: Any): Boolean = cond(obj) {
    case other: Graph[V] ⇒
      multisetCompare(vertices.toList, other.vertices.toList) &&
        multisetCompare(edges, other.edges)
  }

  private def singletonVertices = vertices.filter(v ⇒ inDegree(v) == 0 && outDegree(v) == 0)

  private def asVertexList: String =
    singletonVertices.mkString("\n") + "\n" +
      edges.map(e ⇒ e._1 + "," + e._2).mkString("\n")

  override def toString =
    try
      "\n" + GraphLayout.renderGraph(this) // + "\n" + asVertexList
    catch {
      case t: Throwable ⇒ asVertexList
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy