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

org.opalj.graphs.Graph.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package graphs

import scala.language.implicitConversions
import scala.reflect.ClassTag
import scala.collection.mutable.LinkedHashMap
import scala.collection.mutable.Set
import scala.collection.mutable.HashMap
import scala.collection.{Map ⇒ AMap}
import org.opalj.collection.IntIterator
import org.opalj.collection.immutable.Chain
import org.opalj.collection.immutable.Naught

/**
 * Represents a mutable (multi-)graph with ordered edges.
 *
 * ==Thread Safety==
 * This class is not thread-safe!
 *
 * @author Michael Eichberg
 */
class Graph[@specialized(Int) N: ClassTag] private (
        val vertices:     Set[N],
        val successors:   LinkedHashMap[N, Chain[N]],
        val predecessors: LinkedHashMap[N, Chain[N]]
) extends AbstractGraph[N] {

    def apply(s: N): Chain[N] = successors.getOrElse(s, Naught)

    def asTraversable: N ⇒ Traversable[N] = (n: N) ⇒ { this(n).toTraversable }

    /**
     * Adds a new vertice.
     */
    def +=(n: N): this.type = {
        vertices += n
        this
    }

    /**
     * Adds a new edge between the given vertices.
     *
     * (If the vertices were not previously added, they will be added.)
     */
    def +=(e: (N, N)): this.type = {
        val (s, t) = e
        this += (s, t)
    }

    /**
     * Adds a new edge between the given vertices.
     *
     * (If the vertices were not previously added, they will be added.)
     */
    def +=(s: N, t: N): this.type = {
        vertices += s += t
        successors += ((s, t :&: successors.getOrElse(s, Naught)))
        predecessors += ((t, s :&: predecessors.getOrElse(t, Naught)))
        this
    }

    /**
     * Removes the given vertice from this graph.
     */
    def -=(v: N): this.type = {
        vertices -= v
        val oldSuccessorsOpt = successors.get(v)
        oldSuccessorsOpt.foreach(_ foreach { s ⇒ predecessors(s) = predecessors(s) filter (_ != v) })
        val oldPredecessorsOpt = predecessors.get(v)
        oldPredecessorsOpt.foreach(_ foreach { s ⇒ successors(s) = successors(s) filter (_ != v) })
        successors -= v
        predecessors -= v
        this
    }

    def --=(vs: TraversableOnce[N]): this.type = { vs foreach { v ⇒ this -= v }; this }

    /**
     * All nodes which only have incoming dependencies/which have no successors.
     */
    def leafNodes: Set[N] = vertices.filter(v ⇒ !successors.contains(v) || successors(v).isEmpty)

    def sccs(filterSingletons: Boolean = false): Iterator[Iterator[N]] = {
        val size = vertices.size
        val indexToN = new Array[N](size)
        val nToIndex = new HashMap[N, Int] { override def initialSize = size }
        for {
            e ← vertices.iterator.zipWithIndex // Scalac 2.12.2 will issue an incorrect warning for e @ (n, index)
        } {
            val (n, index) = e
            indexToN(index) = n
            nToIndex += e
        }
        val es: Int ⇒ IntIterator = (index: Int) ⇒ {
            successors.get(indexToN(index)) match {
                case Some(successors) ⇒ successors.mapToIntIterator(nToIndex)
                case None             ⇒ IntIterator.empty
            }
        }

        org.opalj.graphs.sccs(size, es, filterSingletons).toIterator.map { scc ⇒
            scc.toIterator.map(indexToN)
        }
    }
}

/**
 * Defines factory methods to create simple graphs.
 */
object Graph {

    implicit def intToInteger(i: Int): Integer = Integer.valueOf(i)

    implicit def AnyRefToAnyRef(o: AnyRef): AnyRef = o

    def empty[N: ClassTag]: Graph[N] = {
        new Graph[N](Set.empty, LinkedHashMap.empty, LinkedHashMap.empty)
    }

    def apply[N: ClassTag](edges: AMap[N, List[N]]): Graph[N] = {
        val g = Graph.empty[N]
        edges foreach { e ⇒
            val (s, ts) = e
            ts foreach { t ⇒
                g += (s → t)
            }
        }
        g
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy