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

scalax.collection.GraphDegree.scala Maven / Gradle / Ivy

The newest version!
package scalax.collection

import scala.language.postfixOps
import scala.collection.{SortedMap, SortedSet}
import scala.collection.mutable.{Map => MutableMap}

import scalax.collection.generic.Edge

/** Mixin for degree calculations.
  *
  * @tparam N the user type of the nodes (vertices) in this graph.
  * @tparam E the type of the edges in this graph.
  *
  * @author Peter Empen
  * @define DEGREEFUNCTION the degree function to apply to the nodes defaulting to `Degree`. Non-default predefined
  *         degree functions are `InDegree` and `OutDegree`.
  * @define DEGREEFILTER selects nodes to be included by their degree.
  */
trait GraphDegree[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphBase[X, Y, CC]] {
  this: GraphBase[N, E, CC] =>

  /** Decreasing ordering of nodes with respect to their degree.
    */
  final class DegreeOrdering(val f: DegreeFunction) extends Ordering[NodeT] {
    def compare(n1: NodeT, n2: NodeT): Int = n1.degree compare n2.degree
  }
  object DegreeOrdering {
    @inline final def apply(f: DegreeFunction) = new DegreeOrdering(f)
  }

  /** Decreasing ordering of integers.
    */
  object IntReverseOrdering extends Ordering[Int] {
    def compare(d1: Int, d2: Int): Int = d2 compare d1
  }

  trait DegreeFunction extends Function1[NodeT, Int]
  object Degree        extends DegreeFunction { def apply(n: NodeT): Int = n.degree    }
  object InDegree      extends DegreeFunction { def apply(n: NodeT): Int = n.inDegree  }
  object OutDegree     extends DegreeFunction { def apply(n: NodeT): Int = n.outDegree }

  trait Filter[T] extends Function1[T, Boolean]

  /** The total degree of this graph equaling to the sum
    * of the degrees over all nodes or `0` if this graph is empty.
    *
    * @param nodeDegree $DEGREEFUNCTION
    * @param degreeFilter $DEGREEFILTER
    */
  def totalDegree(implicit nodeDegree: DegreeFunction = Degree, degreeFilter: Int => Boolean = AnyDegree): Int =
    if (edges.maxArity <= 2 && degreeFilter == AnyDegree) edges.size * 2
    else {
      var deg = 0
      nodes foreach { n =>
        val nodeD = nodeDegree(n)
        if (degreeFilter(nodeD)) deg += nodeD
      }
      deg
    }

  /** The degree of the node having the least degree or `0` if
    * this graph is empty.
    *
    * @param $DEGREEFUNCTION
    * @param $DEGREEFILTER
    */
  def minDegree(implicit nodeDegree: DegreeFunction = Degree, degreeFilter: Int => Boolean = AnyDegree): Int =
    if (order == 0) 0
    else if (degreeFilter == AnyDegree)
      nodeDegree(nodes min DegreeOrdering(nodeDegree))
    else
      nodes.toList.view map nodeDegree filter degreeFilter min

  /** The degree of the node having the highest degree or `0` if
    * this graph is empty.
    *
    * @param $DEGREEFUNCTION
    * @param $DEGREEFILTER
    */
  def maxDegree(implicit nodeDegree: DegreeFunction = Degree, degreeFilter: Int => Boolean = AnyDegree): Int =
    if (order == 0) 0
    else if (degreeFilter == AnyDegree)
      nodeDegree(nodes max DegreeOrdering(nodeDegree))
    else
      nodes.toList.view map nodeDegree filter degreeFilter max

  /** The degree sequence of this graph, that is the non-increasing
    * sequence of degrees over all nodes.
    *
    * @param $DEGREEFUNCTION
    * @param $DEGREEFILTER
    */
  def degreeSeq(implicit nodeDegree: DegreeFunction = Degree, degreeFilter: Int => Boolean = AnyDegree): Seq[Int] = {
    val v = nodes.toList.view map nodeDegree sorted IntReverseOrdering
    if (degreeFilter == AnyDegree) v.toSeq
    else (v filter degreeFilter).toSeq
  }

  /** The degree set of this graph, that is the decreasing
    * set of unique degrees over all nodes. Same as degreeSeq without duplicates.
    *
    * @param $DEGREEFUNCTION
    * @param $DEGREEFILTER
    */
  def degreeSet(implicit
      nodeDegree: DegreeFunction = Degree,
      degreeFilter: Int => Boolean = AnyDegree
  ): SortedSet[Int] =
    SortedSet[Int]()(IntReverseOrdering) ++ (if (degreeFilter == AnyDegree) nodes map nodeDegree
                                             else nodes.view map nodeDegree filter degreeFilter)

  /** Type alias for entries in degree maps returned by `degreeSeqMap`.
    */
  type DegreeNodeSeqEntry = (Int, NodeT)

  /** The degree sequence of this graph projected onto a sequence of tuples.
    * The first elements of the tuples are the degrees in non-increasing order
    * while the second elements are the corresponding inner nodes.
    *
    * @param $DEGREEFUNCTION
    * @param $DEGREEFILTER
    */
  def degreeNodeSeq(implicit
      nodeDegree: DegreeFunction = Degree,
      degreeFilter: Int => Boolean = AnyDegree
  ): Seq[DegreeNodeSeqEntry] = {
    val r = (nodes.toList map (n => (nodeDegree(n), n))) sorted
      (new Ordering[DegreeNodeSeqEntry] {
        def compare(a: DegreeNodeSeqEntry, b: DegreeNodeSeqEntry): Int = b._1 compare a._1
      })
    if (degreeFilter == AnyDegree) r
    else r filter (t => degreeFilter(t._1))
  }

  /** The degree set of this graph projected onto a map.
    * The keys of the map are the degrees in decreasing order
    * while the values are sets of the corresponding inner nodes.
    *
    * @param $DEGREEFUNCTION
    * @param $DEGREEFILTER
    */
  def degreeNodesMap(implicit
      nodeDegree: DegreeFunction = Degree,
      degreeFilter: Int => Boolean = AnyDegree
  ): SortedMap[Int, AnySet[NodeT]] = {
    val r: SortedMap[Int, AnySet[NodeT]] =
      SortedMap[Int, AnySet[NodeT]]()(IntReverseOrdering) ++ (nodes groupBy nodeDegree)
    if (degreeFilter == AnyDegree) r
    else r filter (t => degreeFilter(t._1))
  }

  /** The degree set of this graph projected onto a map.
    * The keys of the map are the degrees in decreasing order
    * while the values are the number of inner nodes having
    * the degree of the corresponding key.
    *
    * @param $DEGREEFUNCTION
    * @param $DEGREEFILTER
    */
  def degreeCount(implicit
      nodeDegree: DegreeFunction = Degree,
      degreeFilter: Int => Boolean = AnyDegree
  ): SortedMap[Int, Int] =
    SortedMap[Int, Int]()(IntReverseOrdering) ++ {
      val m = MutableMap[Int, Int]()
      nodes foreach { n =>
        val degree = nodeDegree(n)
        if (degreeFilter(degree))
          m += degree -> (m.getOrElse(degree, 0) + 1)
      }
      m
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy