
scalax.collection.constrained.constraints.Acyclic.scala Maven / Gradle / Ivy
The newest version!
package scalax.collection.constrained
package constraints
import scala.collection.Set
import scala.collection.mutable.{Set => MutableSet}
import scalax.collection.GraphPredef._,
scalax.collection.GraphEdge._
import scalax.collection.{Graph => SimpleGraph}
import PreCheckFollowUp._
/** Ensures that the underlying `Graph` is acyclic at any time. */
class Acyclic[N, E[X] <: EdgeLikeIn[X]] (override val self: Graph[N,E])
extends Constraint[N,E] (self)
with ConstraintHandlerMethods[N,E]
{
override def preCreate(nodes: collection.Iterable[N],
edges: collection.Iterable[E[N]]) = PreCheckResult(PostCheck)
/** Adding a single node cannot produce a cycle. */
override def preAdd(node: N) = PreCheckResult(Complete)
/**
* When inserting an edge with a source contained in the graph
* a cycle is produced if there exists a target node of this edge such that
* there is a path from the target node to the source node.
*/
def preAdd(edge: E[N]) = PreCheckResult.complete(
edge.nonLooping &&
{ val isUndirected = edge.isUndirected
val checkFrom, checkTo = MutableSet.empty[self.NodeT]
def find(n: N) = self find n
def add1(n: N) {
find(n) map { inner =>
checkFrom += inner
if (isUndirected) checkTo += inner
}
}
def add2(toSet: MutableSet[self.NodeT], n: N, nUndi: N) {
find(n) map (inner => toSet += inner)
find(nUndi) map {inner => if(isUndirected) toSet += inner }
}
add2(checkTo, edge._1, edge._2)
add2(checkFrom, edge._2, edge._1)
for (n <- edge.iterator.drop(2))
add1(n)
! ((for (from <- checkFrom; to <- checkTo) yield (from, to)
) exists (t => t._1 hasSuccessor t._2))
}
)
/** This class makes it possible to carry over nodes that are passed to a pre-check and
* are already contained in the graph to `postAdd`. Thus we can limit the number of start
* nodes for cycle detection in the post-check to these passed over docking nodes.
*/
protected class Result (followUp: PreCheckFollowUp,
val dockingNodes: Set[self.NodeT])
extends PreCheckResult(followUp)
protected object Result extends PreCheckResultCompanion {
def apply(followUp: PreCheckFollowUp) = new Result(followUp, Set.empty[self.NodeT])
def apply(followUp: PreCheckFollowUp,
nodesToCheck: Set[self.NodeT] ) = new Result(followUp, nodesToCheck)
def unapply(result: Result): Option[Set[self.NodeT]] = Some(result.dockingNodes)
}
/** If `elems` is relatively small, preventively ensure that there is no cycle
* within the new elements.
*/
override def preAdd(elems: GraphParamIn[N,E]*) =
if (elems.size * 10 < self.size) {
val p: GraphParam.Partitions[N,E] = elems
val graphAdd = SimpleGraph.from(
p.toOuterNodes, p.toOuterEdges)(
self.edgeManifest, self.config.asInstanceOf[SimpleGraph.Config])
if (graphAdd.isCyclic)
PreCheckResult(Abort)
else {
val found = (for (n <- p.toOuterNodes) yield self find n) filter (_.isDefined)
val dockingNodes = Set()
Result(PostCheck, (found map (_.get)) toSet)
}
} else PreCheckResult(PostCheck)
override def postAdd (newGraph: Graph[N,E],
passedNodes: Iterable[N],
passedEdges: Iterable[E[N]],
preCheck : PreCheckResult) = preCheck match {
case Result(docking) => ! (docking exists (_.findCycle.isDefined))
case _ => newGraph.isAcyclic
}
override def preSubtract(node: self.NodeT, forced: Boolean) = PreCheckResult(Complete)
override def preSubtract(edge: self.EdgeT, forced: Boolean) = PreCheckResult(Complete)
override def preSubtract(nodes: => Set[self.NodeT],
edges: => Set[self.EdgeT],
simple: Boolean) = PreCheckResult(Complete)
}
object Acyclic extends ConstraintCompanion[Acyclic] {
def apply [N, E[X] <: EdgeLikeIn[X]] (self: Graph[N,E]) = new Acyclic[N,E] (self)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy