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

com.github.mdr.ascii.layout.cycles.CycleRemovalInfo.scala Maven / Gradle / Ivy

The newest version!
package com.github.mdr.ascii.layout.cycles

import scala.collection.immutable.SortedMap
import scala.annotation.tailrec
import com.github.mdr.ascii.graph.Graph

/**
 * Tracks information useful during cycle removal algorithm:
 *   - vertices which have been deleted from the graph
 *   - sources and sinks
 *   - vertices, ranked by the difference between their out-degree and in-degree
 */
class CycleRemovalInfo[V](graph: Graph[V]) {

  private var sources: Set[V] = graph.sources.toSet

  private var sinks: Set[V] = graph.sinks.toSet

  /**
   * For each vertex v, the difference between the out- and in-degrees: outDegree(v) - inDegree(v)
   */
  private var verticesToDegreeDiff: Map[V, Int] = Map()

  /**
   * Inverse of verticesToDegreeDiff.
   */
  private var degreeDiffToVertices: SortedMap[Int, List[V]] = SortedMap() // out degree - in degree

  private var deletedVertices: Set[V] = Set()

  // Initialise
  for (v ← graph.vertices)
    addVertexToDegreeDiffMaps(v, graph.outDegree(v) - graph.inDegree(v))

  def getSources: Set[V] = sources

  def getSinks: Set[V] = sinks

  def getLargestDegreeDiffVertex: Option[V] = degreeDiffToVertices.lastOption.flatMap(_._2.headOption)

  def removeVertex(v: V) {
    deletedVertices += v
    if (sinks contains v)
      sinks -= v
    if (sources contains v)
      sources -= v
    removeVertexFromDegreeDiffMaps(v)

    for (outVertex ← getOutVertices(v)) {
      adjustDegreeDiff(outVertex, +1)
      if (getInVertices(outVertex).isEmpty)
        sources += outVertex
    }
    for (inVertex ← getInVertices(v)) {
      adjustDegreeDiff(inVertex, -1)
      if (getOutVertices(inVertex).isEmpty)
        sinks += inVertex
    }
  }

  private def getInVertices(v: V): List[V] = graph.inVertices(v).filterNot(deletedVertices)

  private def getOutVertices(v: V): List[V] = graph.outVertices(v).filterNot(deletedVertices)

  private def adjustDegreeDiff(v: V, delta: Int) = {
    val previousDegreeDiff = removeVertexFromDegreeDiffMaps(v)
    addVertexToDegreeDiffMaps(v, previousDegreeDiff + delta)
  }

  private def addVertexToDegreeDiffMaps(v: V, degreeDiff: Int) = {
    degreeDiffToVertices += degreeDiff -> (v :: degreeDiffToVertices.getOrElse(degreeDiff, Nil))
    verticesToDegreeDiff += v -> degreeDiff
  }

  private def removeVertexFromDegreeDiffMaps(v: V): Int = {
    val degreeDiff = verticesToDegreeDiff(v)
    val vertices = degreeDiffToVertices(degreeDiff)
    val updatedVertices = vertices.filterNot(_ == v)
    if (updatedVertices.isEmpty)
      degreeDiffToVertices -= degreeDiff
    else
      degreeDiffToVertices += degreeDiff -> updatedVertices
    verticesToDegreeDiff -= v
    degreeDiff
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy