Skip to content

Commit

Permalink
isDirected, isHyper and isMulti now also consider the graph content a…
Browse files Browse the repository at this point in the history
…s opposed to solely checking the edge type parameter.
  • Loading branch information
Peter Empen committed Apr 3, 2016
1 parent fa651d9 commit e789d92
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 75 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ project/plugins/project/
.classpath
.settings/
.scala_dependencies
.cache
.cache*

# Mac OS specific
.DS_Store
Expand Down
23 changes: 17 additions & 6 deletions core/src/main/scala/scalax/collection/Graph.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,15 @@ trait GraphLike[N,
{ selfGraph: This[N,E] =>
protected type ThisGraph = this.type
implicit val edgeT: ClassTag[E[N]]

lazy val isDirected = classOf[DiHyperEdgeLike[_]].isAssignableFrom(edgeT.runtimeClass)
lazy val isHyper = ! classOf[UnDiEdge[_]] .isAssignableFrom(edgeT.runtimeClass)
lazy val isMulti = classOf[Keyed] .isAssignableFrom(edgeT.runtimeClass)

def isDirected = isDirectedT || edges.hasOnlyDiEdges
protected final val isDirectedT = classOf[DiHyperEdgeLike[_]].isAssignableFrom(edgeT.runtimeClass)

def isHyper = isHyperT && edges.hasAnyHyperEdge
protected final val isHyperT = ! classOf[UnDiEdge[_]].isAssignableFrom(edgeT.runtimeClass)

def isMulti = isMultiT || edges.hasAnyMultiEdge
protected final val isMultiT = classOf[Keyed].isAssignableFrom(edgeT.runtimeClass)

/** The companion object of `This`. */
val graphCompanion: GraphCompanion[This]
Expand Down Expand Up @@ -156,7 +161,8 @@ trait GraphLike[N,
else this.asInstanceOf[NodeSetT]
/**
* removes `node` from this node set leaving the edge set unchanged.
* @param node the node to be removed from the node set.
*
* @param node the node to be removed from the node set.
*/
protected def minus(node: NodeT): Unit
/**
Expand Down Expand Up @@ -186,7 +192,12 @@ trait GraphLike[N,
protected def handleNotGentlyRemovable = false
}
type EdgeSetT <: EdgeSet
trait EdgeSet extends super.EdgeSet
trait EdgeSet extends super.EdgeSet {
def hasOnlyDiEdges: Boolean
def hasAnyHyperEdge: Boolean
def hasAnyMultiEdge: Boolean
}

/** Checks whether a given node or edge is contained in this graph.
*
* @param elem the node or edge the existence of which is to be checked
Expand Down
17 changes: 13 additions & 4 deletions core/src/main/scala/scalax/collection/GraphBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,22 @@ trait GraphBase[N, E[X] <: EdgeLikeIn[X]]
* because `Graph` is also `SetLike` with set elements being nodes or edges.
*/
def graphSize = edges.size

/** Whether all edges of this graph are directed. */
def isDirected: Boolean
/** Whether this graph contains at least one hyperedges. */
def isHyper: Boolean
/** Whether this graph contains at least one multi-edge. We defnie multi-edges by
* a. two or more directed edges having the same source and target
* a. two or more undirected edges connecting the same nodes
* a. two or more (directed) hyperedges that, after being decomposed into (directed) edges,
yield any multy-edge as stipulated above.
*/
def isMulti: Boolean

type NodeFilter = NodeT => Boolean
type EdgeFilter = EdgeT => Boolean

// Must be val since eq does not work for def.
/** Default node filter letting traverse all nodes (non-filter). */
final val anyNode: NodeFilter = _ => true
Expand Down Expand Up @@ -105,7 +114,7 @@ trait GraphBase[N, E[X] <: EdgeLikeIn[X]]
def edges: ExtSet[EdgeT]
/** Synonym for `edges`. */
@inline final def ~ = edges

/**
* All edges connecting this node with `other` including outgoing and incoming edges.
* This method is useful in case of multigraphs.
Expand Down Expand Up @@ -664,7 +673,7 @@ trait GraphBase[N, E[X] <: EdgeLikeIn[X]]
final def draw(random: Random) = (nodes draw random).edges draw random
final def findEntry[B](other: B, correspond: (EdgeT, B) => Boolean): EdgeT = {
def find(edge: E[N]): EdgeT = correspond match {
case c: ((EdgeT, E[N]) => Boolean) => nodes.lookup(edge._1).edges findEntry (edge, c)
case c: ((EdgeT, E[N]) => Boolean) @unchecked => nodes.lookup(edge._1).edges findEntry (edge, c)
case _ => throw new IllegalArgumentException
}
other match {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package scalax.collection
package immutable

import language.higherKinds
import scala.language.higherKinds
import scala.annotation.unchecked.uncheckedVariance
import scala.collection.{Set => AnySet}
import scala.collection.mutable.Buffer
import scala.util.Random

import scala.collection.EqSetFacade
Expand All @@ -26,7 +27,7 @@ trait AdjacencyListBase[N,
+This[X, Y[X]<:EdgeLikeIn[X]]
<: GraphLike[X,Y,This] with AnySet[Param[X,Y]] with SimpleGraph[X,Y]]
extends GraphLike[N,E,This]
{ this: This[N,E] =>
{ selfGraph: This[N,E] =>
protected type Config <: GraphConfig with AdjacencyListArrayConfig

@inline final protected
Expand Down Expand Up @@ -190,9 +191,9 @@ trait AdjacencyListBase[N,
edges count edgePred
}

@inline final protected[collection] def +=(edge: EdgeT): this.type = {
edges add edge; this
}
@inline protected[collection] def add(edge: EdgeT): Boolean = edges add edge

@inline final protected[collection] def +=(edge: EdgeT): this.type = { add(edge); this }
}
@inline final protected def newNode(n: N) = newNodeWithHints(n, config.adjacencyListHints)
protected def newNodeWithHints(node: N, hints: ArraySet.Hints): NodeT
Expand Down Expand Up @@ -294,13 +295,42 @@ trait AdjacencyListBase[N,
type EdgeSetT <: EdgeSet
trait EdgeSet extends super.EdgeSet {
protected[AdjacencyListBase] def addEdge(edge: EdgeT): Unit
final override def contains(node: NodeT): Boolean =
nodes find node exists (_.edges.nonEmpty)
final override def find(elem: E[N] ): Option[EdgeT] =
nodes find elem._1 flatMap (_.edges find (_.edge == elem))
final def contains(edge: EdgeT): Boolean =
nodes find edge.edge._1 exists (_.edges contains edge)

final override def contains(node: NodeT): Boolean = nodes find node exists (_.edges.nonEmpty)

final override def find(elem: E[N] ): Option[EdgeT] = nodes find elem._1 flatMap (_.edges find (_.edge == elem))

final def contains(edge: EdgeT): Boolean = nodes find edge.edge._1 exists (_.edges contains edge)

final def iterator: Iterator[EdgeT] = edgeIterator

private[this] var nrEdges = 0

private[this] var nrDi = if (selfGraph.isDirectedT) -1 else 0
final def hasOnlyDiEdges = nrDi == -1 || nrDi == nrEdges

private[this] var nrHyper = if (selfGraph.isHyperT) 0 else -1
final def hasAnyHyperEdge = nrHyper > 0

protected final def statistics(edge: EdgeT, plus: Boolean): Boolean = {
val add = if (plus) 1 else -1
nrEdges += add
if (nrDi != -1 && edge.isDirected) nrDi += add
if (nrHyper != -1 && edge.isHyperEdge) nrHyper += add
true
}

override def size = nrEdges

def hasAnyMultiEdge = selfGraph.nodes exists { node: NodeT =>
val (di: Buffer[EdgeT @unchecked], unDi: Buffer[EdgeT @unchecked]) = {
if (selfGraph.isDirected) (node.edges.toBuffer[EdgeT], Buffer.empty)
else node.edges.toBuffer partition (_.isDirected)
}
val diTargets, unDiTargets = MSet.empty[NodeT]
di .exists((e: EdgeT) => e.hasSource((n: NodeT) => n eq node) && ! e.targets.forall(diTargets add _)) ||
unDi.exists((e: EdgeT) => (e.n1 eq node) && ! e.iterator.drop(1).forall((n: NodeT) => unDiTargets add n))
}
}

def edgeIterator = new GroupIterator[EdgeT] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,16 @@ trait AdjacencyListGraph[N,
if (coll contains node) this
else {val c = copy; c.coll += node; c }

protected[collection] def +=(edge: EdgeT): this.type = {
protected[AdjacencyListGraph] def add(edge: EdgeT): Boolean = {
var added = false
edge foreach { n =>
val inColl = coll findEntry n getOrElse {coll += n; n}
inColl += edge
added = (inColl add edge) || added
}
this
added
}

protected[collection] def +=(edge: EdgeT): this.type = { add(edge); this }
}
override val nodes: NodeSetT

Expand All @@ -67,15 +70,18 @@ trait AdjacencyListGraph[N,
if (edges ne null)
edges foreach (this += Edge(_))
}
final override lazy val size = super.size

@inline final protected[AdjacencyListGraph] def +=(edge: EdgeT): this.type = {
nodes += edge
if (nodes add edge) statistics(edge, plus = true) else false
this
}

@inline final protected[immutable] def addEdge(edge: EdgeT) { +=(edge) }
@inline final def +(edge: EdgeT): Set[EdgeT] = toSet + edge
@inline final def -(edge: EdgeT): Set[EdgeT] = toSet - edge
@inline final override lazy val maxArity = super.maxArity

@inline final override lazy val maxArity = super.maxArity
@inline final override lazy val hasAnyMultiEdge = super.hasAnyMultiEdge
}
override val edges: EdgeSetT

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ trait AdjacencyListGraph[N,
final override val edges: ArraySet[EdgeT] = ArraySet.emptyWithHints[EdgeT](hints)
import Adj._

protected[AdjacencyListGraph] def add(edge: EdgeT): Boolean =
if (edges.add(edge)) {
override protected[collection] final def add(edge: EdgeT): Boolean =
if (super.add(edge)) {
if (selfGraph.edges.initialized) addDiSuccOrHook(edge)
true
} else false
Expand Down Expand Up @@ -130,37 +130,24 @@ trait AdjacencyListGraph[N,
initialized = true
}

override def add(edge: EdgeT) =
if (nodes add edge) {
nrEdges += 1
true
} else false
override def add(edge: EdgeT): Boolean =
if (nodes add edge) statistics(edge, plus = true) else false

@inline final protected[collection] def addEdge(edge: EdgeT) { add(edge) }
@inline final protected[collection] def addEdge(edge: EdgeT): Unit = add(edge)

def upsert(edge: EdgeT): Boolean = {
if (nodes upsert edge) {
nrEdges += 1
true
} else false
}
def upsert(edge: EdgeT): Boolean =
if (nodes upsert edge) statistics(edge, plus = true) else false

override def remove(edge: EdgeT) =
if (nodes remove edge) {
nrEdges -= 1
true
} else false
override def remove(edge: EdgeT): Boolean =
if (nodes remove edge) statistics(edge, plus = false) else false

def removeWithNodes(edge: EdgeT) = {
val privateNodes = edge.privateNodes
if (remove(edge)) {
nodes --= privateNodes
true
} else false

}
private var nrEdges = 0
override def size = nrEdges

@inline final override def maxArity: Int = super.maxArity
}
Expand Down
Loading

0 comments on commit e789d92

Please sign in to comment.