diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 7bac7092..a6d22c7f 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -6,3 +6,6 @@ c8ea894cd1f40ce3cc10f61a05be3b4c9ff11516
# Scala Steward: Reformat with scalafmt 3.8.2
643a4d6a4a8c546f5dba789f9c81961d944f051c
+
+# Scala Steward: Reformat with scalafmt 3.8.6
+832cfd7b56fad7cdf1d4976c19ee1a527487f842
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6383cdf5..e626d91b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,26 +1,25 @@
name: CI
on: [ push, pull_request ]
-
jobs:
- build:
+ cross-build:
strategy:
fail-fast: false
matrix:
- scala: [ "2.13.15", "3.3.0" ]
- project: [ "core", "dot", "json" ]
+ scala: [ '2.13.16', '3.3.5' ]
+ project: [ core, dot, json ]
exclude:
- - scala: "3.3.0"
- project: "json"
+ - scala: '3.3.5'
+ project: json
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: JDK with SBT caching
uses: actions/setup-java@v4
with:
- java-version: '17'
- distribution: 'temurin'
- cache: 'sbt'
+ java-version: 17
+ distribution: temurin
+ cache: sbt
+ - uses: sbt/setup-sbt@v1
- name: Test
run: |
sbt ++${{ matrix.scala }} ${{ matrix.project }}/test scalafmtCheckAll
- sbt "project coreTestScala3" test Test/scalafmt
diff --git a/.scalafmt.conf b/.scalafmt.conf
index 5472f6b8..8511b0ae 100644
--- a/.scalafmt.conf
+++ b/.scalafmt.conf
@@ -1,4 +1,4 @@
-version=3.8.2
+version=3.8.6
runner.dialect = scala213
align.preset = more
diff --git a/README.md b/README.md
index a44419ca..fc7891fb 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
This is the source code repository and issue tracker for [Graph for Scala](http://www.scala-graph.org).
[Questions or any feedback](https://groups.google.com/forum/#!forum/scala-graph) are appreciated.
-Please use GitHub issues for proven issues or enhancement requests but not for questions.
+Please use GitHub issues for proven issues or enhancement requests, not for questions.
You are also welcome as a co-contributor.
@@ -13,22 +13,15 @@ Peter
## Branches
-**1.x** started in 2011. It has evolved by paying high attention to version compatibility.
+**1.x** started in 2011, is now superseeded by 2.x. It evolved by paying high attention to version compatibility.
-**2.x** started in 2019 to make some significant improvements that also need new, simplified signatures.
-New features include
+**2.x**, the **default** branch, started in 2019 to make some significant improvements that also needed new, simplified signatures.
+The new features include
* multiple sources for directed hyperedges
-* easy edge class definition using case classes thus easy definition of ADTs of edges
+* easy edge class definition using case classes, thus easy definition of ADTs for edges
* improved functional graph handling.
-Shipment is due shortly after Scala 2.13.11 is published because
-this fix will help to further simplify user code.
+2.0 was released in May 2023.
-## Roadmap
-
-* Complete migration of random graphs for 2.x.
-* Investigate whether and how the JSON module should be retained and migrated to 2.x or dropped. Migrate it if needed.
-* Remove internal State
by possibly also changing node references to IDs.
-* Add support for algorithms by enrichment that use fluent properties.
-* Reimplement immutable graphs to be based on a persistent data structure.
+**persistent** opened in January 2024 with the aim of implementing a persistent data structure.
diff --git a/build.sbt b/build.sbt
index ea96e671..d700e959 100644
--- a/build.sbt
+++ b/build.sbt
@@ -29,21 +29,6 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
)
)
-lazy val coreTestScala3 = project
- .in(file("coreTestScala3"))
- .dependsOn(core.jvm)
- .settings(
- defaultSettings_3 ++ Seq(
- libraryDependencies ++= Seq(
- "org.scalatest" %% "scalatest" % "3.2.19" % Test,
- "org.scalatestplus" %% "scalacheck-1-18" % "3.2.19.0" % Test exclude (
- "org.scalacheck",
- "scalacheck_3"
- )
- )
- )
- )
-
lazy val dot = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Pure)
@@ -73,7 +58,7 @@ val unusedImports = "-Wunused:imports"
lazy val defaultSettings_cross = Defaults.coreDefaultSettings ++ Seq(
scalaVersion := Version.compiler_2_13,
- crossScalaVersions := Seq(Version.compiler_2_13, Version.compiler_3_fallback)
+ crossScalaVersions := Seq(Version.compiler_2_13, Version.compiler_3)
) ++
defaultSettings ++
defaultTestLibSettings
diff --git a/constrained/src/main/scala/scalax/collection/constrained/ConstraintOp.scala b/constrained/src/main/scala/scalax/collection/constrained/ConstraintOp.scala
index 29b6ad56..5f1efed3 100644
--- a/constrained/src/main/scala/scalax/collection/constrained/ConstraintOp.scala
+++ b/constrained/src/main/scala/scalax/collection/constrained/ConstraintOp.scala
@@ -60,14 +60,12 @@ class ConstraintBinaryOp[N, E <: Edge[N], G <: Graph[N, E]](
case Or => rightFollowUp
}
if (followUp == Abort) PreCheckResult(Abort)
- else {
- if (rightDone) {
- leftResult match {
- case r: PreCheckResults => r += (right, rightResult)
- case _ => new PreCheckResults(min(leftFollowUp, rightFollowUp), left, leftResult) += (right, rightResult)
- }
- } else leftResult
- }
+ else if (rightDone)
+ leftResult match {
+ case r: PreCheckResults => r += (right, rightResult)
+ case _ => new PreCheckResults(min(leftFollowUp, rightFollowUp), left, leftResult) += (right, rightResult)
+ }
+ else leftResult
}
protected def eval[V <: ConstraintViolation](left: Either[V, G], right: => Either[V, G]): Either[V, G] =
diff --git a/constrained/src/main/scala/scalax/collection/constrained/mutable/GraphLike.scala b/constrained/src/main/scala/scalax/collection/constrained/mutable/GraphLike.scala
index 988bd041..a04df7af 100644
--- a/constrained/src/main/scala/scalax/collection/constrained/mutable/GraphLike.scala
+++ b/constrained/src/main/scala/scalax/collection/constrained/mutable/GraphLike.scala
@@ -32,7 +32,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y[+X] <: EdgeLikeIn[X]] <: GraphLike[X,
case Complete => Right(remove)
case PostCheck =>
val incidentEdges = node.edges.toIterable
- if (remove) {
+ if (remove)
postSubtract(selfGraph, Set(node), Set.empty[E[N]], preCheckResult).fold(
failure => {
withoutChecks {
@@ -43,7 +43,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y[+X] <: EdgeLikeIn[X]] <: GraphLike[X,
},
_ => Right(true)
)
- } else Right(false)
+ else Right(false)
case Abort => Left(preCheckResult)
}
}
@@ -98,7 +98,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y[+X] <: EdgeLikeIn[X]] <: GraphLike[X,
if (preCheckResult.abort) Some(preCheckResult)
else {
add
- if (preCheckResult.postCheck) {
+ if (preCheckResult.postCheck)
postAdd(this, newNodes, newEdges, preCheckResult).fold(
failure => {
withoutChecks {
@@ -109,7 +109,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y[+X] <: EdgeLikeIn[X]] <: GraphLike[X,
},
_ => None
)
- } else None
+ else None
}
}
(elems match {
diff --git a/core/src/main/scala/scala/collection/Facades.scala b/core/src/main/scala/scala/collection/Facades.scala
index 4828dc73..e1e4f4e9 100644
--- a/core/src/main/scala/scala/collection/Facades.scala
+++ b/core/src/main/scala/scala/collection/Facades.scala
@@ -32,6 +32,7 @@ final class EqSetFacade[A <: AnyRef](i: Iterable[A]) extends immutable.Set[A] {
def incl(elem: A) = i.toSet - elem
def excl(elem: A) = i.toSet + elem
+ override def knownSize: Int = i.knownSize
override def size: Int = i.size
override def contains(elem: A) = i exists (_ eq elem)
}
diff --git a/core/src/main/scala/scala/collection/mutable/ExtHashSet.scala b/core/src/main/scala/scala/collection/mutable/ExtHashSet.scala
index b67fdbdc..ff0ea192 100644
--- a/core/src/main/scala/scala/collection/mutable/ExtHashSet.scala
+++ b/core/src/main/scala/scala/collection/mutable/ExtHashSet.scala
@@ -9,7 +9,7 @@
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
-/* Extended version of https://github.com/scala/scala/blob/2.13.x/src/library/scala/collection/mutable/ExtHashSet.scala
+/* Extended version of https://github.com/scala/scala/blob/2.13.x/src/library/scala/collection/mutable/HashSet.scala
*/
package scala.collection
@@ -105,11 +105,9 @@ final class ExtHashSet[A](initialCapacity: Int, loadFactor: Double)
}
}
- override def subtractAll(xs: IterableOnce[A]): this.type = {
- if (size == 0) {
- return this
- }
-
+ override def subtractAll(xs: IterableOnce[A]): this.type =
+ if (size == 0) this
+ else
xs match {
case hs: immutable.HashSet[A] =>
hs.foreachWithHashWhile { (k, h) =>
@@ -119,15 +117,13 @@ final class ExtHashSet[A](initialCapacity: Int, loadFactor: Double)
this
case hs: ExtHashSet[A] =>
val iter = hs.nodeIterator
- while (iter.hasNext) {
+ while (iter.hasNext && size > 0) {
val next = iter.next()
remove(next.key, next.hash)
- if (size == 0) return this
}
this
case _ => super.subtractAll(xs)
}
- }
/** Adds an element to this set
*
@@ -139,21 +135,29 @@ final class ExtHashSet[A](initialCapacity: Int, loadFactor: Double)
table(idx) match {
case null =>
table(idx) = new Node(elem, hash, null)
+ contentSize += 1
+ true
case old =>
var prev: Node[A] = null
var n = old
- while((n ne null) && n.hash <= hash) {
- if(n.hash == hash && elem == n.key) return false
- prev = n
- n = n.next
+ var duplicate = false
+ while((n ne null) && !duplicate && n.hash <= hash) {
+ if(n.hash == hash && elem == n.key) duplicate = true
+ else {
+ prev = n
+ n = n.next
+ }
+ }
+ if (duplicate) false
+ else {
+ if (prev eq null)
+ table(idx) = new Node(elem, hash, old)
+ else
+ prev.next = new Node(elem, hash, prev.next)
+ contentSize += 1
+ true
}
- if(prev eq null)
- table(idx) = new Node(elem, hash, old)
- else
- prev.next = new Node(elem, hash, prev.next)
}
- contentSize += 1
- true
}
private[this] def remove(elem: A, hash: Int): Boolean = {
@@ -169,16 +173,18 @@ final class ExtHashSet[A](initialCapacity: Int, loadFactor: Double)
// find an element that matches
var prev = nd
var next = nd.next
- while((next ne null) && next.hash <= hash) {
+ var found = false
+ while((next ne null) && !found && next.hash <= hash) {
if(next.hash == hash && next.key == elem) {
prev.next = next.next
contentSize -= 1
- return true
+ found = true
+ } else {
+ prev = next
+ next = next.next
}
- prev = next
- next = next.next
}
- false
+ found
}
}
@@ -194,12 +200,16 @@ final class ExtHashSet[A](initialCapacity: Int, loadFactor: Double)
def hasNext: Boolean = {
if(node ne null) true
else {
- while(i < len) {
+ var found = false
+ while(!found && i < len) {
val n = table(i)
i += 1
- if(n ne null) { node = n; return true }
+ if(n ne null) {
+ node = n
+ found = true
+ }
}
- false
+ found
}
}
diff --git a/core/src/main/scala/scala/util/compat/Boundary.scala b/core/src/main/scala/scala/util/compat/Boundary.scala
new file mode 100644
index 00000000..e2e812f4
--- /dev/null
+++ b/core/src/main/scala/scala/util/compat/Boundary.scala
@@ -0,0 +1,30 @@
+package scala.util.compat
+
+/** Used for cross compilation, this is close to Scala 3's scala.util.boundary that does not work for Scala 2.13.
+ */
+final class Boundary {
+ import Boundary.*
+
+ private val label = new Boundary.Label
+
+ def break[T](value: T): Nothing = throw new Break(label, value)
+
+ def apply[T](body: (T => Nothing) => T): T =
+ try body(break[T])
+ catch {
+ case ex: Break[T] @unchecked =>
+ if (ex.label eq label) ex.value
+ else throw ex
+ }
+}
+
+object Boundary {
+ def boundary: Boundary = new Boundary
+
+ final private class Break[T] private[Boundary] (val label: Label, val value: T)
+ extends RuntimeException(
+ /*message*/ null, /*cause*/ null, /*enableSuppression=*/ false, /*writableStackTrace*/ false
+ )
+
+ final private class Label
+}
diff --git a/core/src/main/scala/scalax/collection/AnyGraph.scala b/core/src/main/scala/scalax/collection/AnyGraph.scala
index cc218b52..aaa78684 100644
--- a/core/src/main/scala/scalax/collection/AnyGraph.scala
+++ b/core/src/main/scala/scalax/collection/AnyGraph.scala
@@ -88,6 +88,14 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y, CC] wit
false
}
+ override def hashCode: Int = {
+ import scala.util.hashing.MurmurHash3.{finalizeHash, mix, mixLast, productSeed}
+ var h = productSeed
+ h = mix(h, this.nodes.##)
+ h = mixLast(h, this.edges.##)
+ finalizeHash(h, 2)
+ }
+
type NodeT <: GraphInnerNode
trait GraphInnerNode extends BaseInnerNode with TraverserInnerNode { this: NodeT =>
@@ -394,7 +402,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y, CC] wit
nodes foreach { n =>
val newNodes = fNode(n)
nMap put (n, newNodes)
- b ++= newNodes
+ b addNodes newNodes
}
(nMap, b)
}
@@ -513,7 +521,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y, CC] wit
flatMapNodes[NN, EC](fNode) match {
case (nMap, builder) =>
edges foreach { case e @ InnerEdge(AnyEdge(n1: NodeT @unchecked, n2: NodeT @unchecked), _) =>
- builder ++= (edges = fEdge(e, nMap(n1), nMap(n2)))
+ builder addEdges fEdge(e, nMap(n1), nMap(n2))
}
builder.result
}
@@ -538,7 +546,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y, CC] wit
case e @ InnerEdge(AnyEdge(n1: NodeT @unchecked, n2: NodeT @unchecked), _) =>
val nn1s = nMap(n1)
val nn2s = nMap(n2)
- builder ++= (edges = fEdge.fold(fHyperEdge(e, nn1s ++ nn2s))(_(e, nn1s, nn2s)))
+ builder addEdges fEdge.fold(fHyperEdge(e, nn1s ++ nn2s))(_(e, nn1s, nn2s))
case e @ InnerEdge(
AnyDiHyperEdge(sources: OneOrMore[NodeT @unchecked], targets: OneOrMore[NodeT @unchecked]),
@@ -546,12 +554,10 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y, CC] wit
) =>
val newSources = sources.flatMap(nMap)
val newTargets = targets.flatMap(nMap)
- builder ++= (edges =
- fDiHyperEdge.fold(fHyperEdge(e, newSources ++ newTargets))(_(e, newSources, newTargets))
- )
+ builder addEdges fDiHyperEdge.fold(fHyperEdge(e, newSources ++ newTargets))(_(e, newSources, newTargets))
case e @ InnerEdge(AnyHyperEdge(ends: Several[NodeT @unchecked]), _) =>
- builder ++= (edges = fHyperEdge(e, ends.flatMap(nMap)))
+ builder addEdges fHyperEdge(e, ends.flatMap(nMap))
}
builder.result
}
@@ -574,7 +580,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y, CC] wit
case e @ InnerEdge(AnyEdge(n1: NodeT @unchecked, n2: NodeT @unchecked), _) =>
val nn1s = nMap(n1)
val nn2s = nMap(n2)
- builder ++= (edges = fEdge.fold(fDiHyperEdge(e, nn1s, nn2s))(_(e, nn1s, nn2s)))
+ builder addEdges fEdge.fold(fDiHyperEdge(e, nn1s, nn2s))(_(e, nn1s, nn2s))
case e @ InnerEdge(
AnyDiHyperEdge(sources: OneOrMore[NodeT @unchecked], targets: OneOrMore[NodeT @unchecked]),
@@ -582,7 +588,7 @@ trait GraphLike[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y, CC] wit
) =>
val newSources = sources.flatMap(nMap)
val newTargets = targets.flatMap(nMap)
- builder ++= (edges = fDiHyperEdge(e, newSources, newTargets))
+ builder addEdges fDiHyperEdge(e, newSources, newTargets)
}
builder.result
}
diff --git a/core/src/main/scala/scalax/collection/ForeachBasedDetachingIterable.scala b/core/src/main/scala/scalax/collection/ForeachBasedDetachingIterable.scala
index 044d96aa..43281b85 100644
--- a/core/src/main/scala/scalax/collection/ForeachBasedDetachingIterable.scala
+++ b/core/src/main/scala/scalax/collection/ForeachBasedDetachingIterable.scala
@@ -14,7 +14,8 @@ package scalax.collection
import scala.collection.immutable.VectorBuilder
import scala.collection.{Factory, Iterable, IterableFactory}
-import scala.util.chaining._
+import scala.util.compat.Boundary.boundary
+import scala.util.chaining.*
/** Substitute for Scala 2.12 `Traversable` to continue support for collections that cannot implement `hasNext`/`next` easily.
* The methods of Scala 2.13's `IterableOnce` are implemented in terms of `foreach`.
@@ -70,25 +71,29 @@ trait ForeachBasedDetachingIterable[+A] extends Iterable[A] {
final override def head: A = headOption.get
- final override def headOption: Option[A] = {
- for (x <- this) return Some(x)
- None
- }
+ final override def headOption: Option[A] =
+ boundary { break =>
+ for (x <- this)
+ break(Some(x))
+ None
+ }
- final override def find(p: A => Boolean): Option[A] = {
- for (x <- this)
- if (p(x)) return Some(x)
- None
- }
+ final override def find(p: A => Boolean): Option[A] =
+ boundary { break =>
+ for (x <- this)
+ if (p(x)) break(Some(x))
+ None
+ }
- final override def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = {
- val sentinel: A => Any = _ => this
- for (x <- this) {
- val r = pf.applyOrElse(x, sentinel)
- if (r.asInstanceOf[AnyRef] ne sentinel) return Some(r.asInstanceOf[B])
+ final override def collectFirst[B](pf: PartialFunction[A, B]): Option[B] =
+ boundary { break =>
+ val sentinel: A => Any = _ => this
+ for (x <- this) {
+ val r = pf.applyOrElse(x, sentinel)
+ if (r.asInstanceOf[AnyRef] ne sentinel) break(Some(r.asInstanceOf[B]))
+ }
+ None
}
- None
- }
// Subcollections
@@ -110,22 +115,25 @@ trait ForeachBasedDetachingIterable[+A] extends Iterable[A] {
final override def slice(from: Int, until: Int): CC[A] =
math.max(from, 0) pipe { from =>
def block(b: Builder[A]): Unit =
- if (until > from) {
- var i = 0
- for (x <- this) {
- if (i >= from) b += x
- i += 1
- if (i >= until) return
+ if (until > from)
+ boundary[Unit] { break =>
+ var i = 0
+ for (x <- this) {
+ if (i >= from) b += x
+ i += 1
+ if (i >= until) break(())
+ }
}
- }
withBuilder(block)
}
final override def takeWhile(p: A => Boolean): CC[A] = {
def block(b: Builder[A]): Unit =
- for (x <- this) {
- if (!p(x)) return
- b += x
+ boundary[Unit] { break =>
+ for (x <- this) {
+ if (!p(x)) break(())
+ b += x
+ }
}
withBuilder(block)
}
@@ -168,17 +176,19 @@ trait ForeachBasedDetachingIterable[+A] extends Iterable[A] {
// Element Conditions
- final override def forall(p: A => Boolean): Boolean = {
- for (x <- this)
- if (!p(x)) return false
- true
- }
+ final override def forall(p: A => Boolean): Boolean =
+ boundary { break =>
+ for (x <- this)
+ if (!p(x)) break(false)
+ true
+ }
- final override def exists(p: A => Boolean): Boolean = {
- for (x <- this)
- if (p(x)) return true
- false
- }
+ final override def exists(p: A => Boolean): Boolean =
+ boundary { break =>
+ for (x <- this)
+ if (p(x)) break(true)
+ false
+ }
final override def count(p: A => Boolean): Int = {
var i = 0
diff --git a/core/src/main/scala/scalax/collection/GraphBase.scala b/core/src/main/scala/scalax/collection/GraphBase.scala
index 10885bb3..51f18a30 100644
--- a/core/src/main/scala/scalax/collection/GraphBase.scala
+++ b/core/src/main/scala/scalax/collection/GraphBase.scala
@@ -70,7 +70,7 @@ trait GraphBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphBase[X, Y, CC]]
@inline final def isCustomEdgeFilter(f: EdgePredicate) = f ne anyEdge
type NodeT <: BaseInnerNode with Serializable
- trait Node extends Serializable
+ trait Node extends Serializable
trait BaseInnerNode extends Node with InnerNode {
/** All edges at this node - commonly denoted as E(v).
@@ -108,9 +108,9 @@ trait GraphBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphBase[X, Y, CC]]
*/
def isIndependentOf(that: NodeT): Boolean
- /** All direct successors of this node, also called ''successor set'' or
- * ''open out-neighborhood'': target nodes of directed incident edges and / or
- * adjacent nodes of undirected incident edges excluding this node.
+ /** All direct successors of this node, also called ''successor set'':
+ * target nodes of directed incident edges and / or adjacent nodes of undirected incident edges.
+ * This node itself is also included if a loop exists.
* @return set of all direct successors of this node.
*/
def diSuccessors: Set[NodeT]
@@ -118,14 +118,16 @@ trait GraphBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphBase[X, Y, CC]]
/** Whether this node has any successors. */
def hasSuccessors: Boolean
- protected[collection] def addDiSuccessors(edge: EdgeT, add: NodeT => Unit): Unit
+ protected[collection] def addOutNeighbors(edge: EdgeT, add: NodeT => Unit): Unit
- /** Synonym for `diSuccessors`. */
- @inline final def outNeighbors: Set[NodeT] = diSuccessors
+ /** Like `diSuccessors` except that this node is excluded even if a loop exists.
+ * Also called ''open out-neighborhood''.
+ */
+ def outNeighbors: Set[NodeT]
- /** All direct predecessors of this node, also called ''predecessor set'' or
- * ''open in-neighborhood'': source nodes of directed incident edges and / or
- * adjacent nodes of undirected incident edges excluding this node.
+ /** All direct predecessors of this node, also called ''predecessor set'':
+ * source nodes of directed incident edges and / or adjacent nodes of undirected incident edges.
+ * This node itself is also included if a loop exists.
* @return set of all direct predecessors of this node.
*/
def diPredecessors: Set[NodeT]
@@ -133,16 +135,19 @@ trait GraphBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphBase[X, Y, CC]]
/** Whether this node has any predecessors. */
def hasPredecessors: Boolean
- protected[collection] def addDiPredecessors(edge: EdgeT, add: NodeT => Unit): Unit
+ protected[collection] def addInNeighbors(edge: EdgeT, add: NodeT => Unit): Unit
- /** Synonym for `diPredecessors`. */
- @inline final def inNeighbors = diPredecessors
+ /** Like `diPredecessors` except that this node is excluded even if a loop exists.
+ * Also called ''open in-neighborhood''.
+ */
+ def inNeighbors: Set[NodeT]
/** All adjacent nodes (direct successors and predecessors) of this node,
* also called ''open neighborhood'' excluding this node.
* @return set of all neighbors.
*/
def neighbors: Set[NodeT]
+
protected[collection] def addNeighbors(edge: EdgeT, add: NodeT => Unit): Unit
/** All edges outgoing from this node.
@@ -251,10 +256,10 @@ trait GraphBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphBase[X, Y, CC]]
def apply(node: N) = newNode(node)
def unapply(n: NodeT) = Some(n)
- @inline final protected[collection] def addDiSuccessors(node: NodeT, edge: EdgeT, add: NodeT => Unit): Unit =
- node.addDiSuccessors(edge, add)
- @inline final protected[collection] def addDiPredecessors(node: NodeT, edge: EdgeT, add: NodeT => Unit): Unit =
- node.addDiPredecessors(edge, add)
+ @inline final protected[collection] def addOutNeighbors(node: NodeT, edge: EdgeT, add: NodeT => Unit): Unit =
+ node.addOutNeighbors(edge, add)
+ @inline final protected[collection] def addInNeighbors(node: NodeT, edge: EdgeT, add: NodeT => Unit): Unit =
+ node.addInNeighbors(edge, add)
@inline final protected[collection] def addNeighbors(node: NodeT, edge: EdgeT, add: NodeT => Unit): Unit =
node.addNeighbors(edge, add)
@@ -350,7 +355,7 @@ trait GraphBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphBase[X, Y, CC]]
def adjacencyListsToString: String =
(for (n <- this)
- yield n.outer.toString + ": " + ((for (a <- n.diSuccessors) yield a.outer) mkString ",")) mkString "\n"
+ yield n.outer.toString + ": " + ((for (a <- n.outNeighbors) yield a.outer) mkString ",")) mkString "\n"
def draw(random: Random): NodeT
diff --git a/core/src/main/scala/scalax/collection/GraphTraversal.scala b/core/src/main/scala/scalax/collection/GraphTraversal.scala
index 8e564750..c69e967e 100644
--- a/core/src/main/scala/scalax/collection/GraphTraversal.scala
+++ b/core/src/main/scala/scalax/collection/GraphTraversal.scala
@@ -176,10 +176,11 @@ trait GraphTraversal[N, E <: Edge[N]] extends GraphBase[N, E, GraphTraversal] {
}
/** Layers of a topological order of a graph or of an isolated graph component.
- * The layers of a topological sort can roughly be defined as follows:
- * a. layer 0 contains all nodes having no predecessors,
- * a. layer n contains those nodes that have only predecessors in ancestor layers
- * with at least one of them contained in layer n - 1
+ *
+ * The layers of a topological sort can roughly be defined as follows:
+ * a. layer 0 contains all nodes having no predecessors
+ * a. layer n contains those nodes that have only predecessors in ancestor layers
+ * with at least one of them contained in layer n - 1
* @tparam A one of `NodeT`, `N`
*/
final class LayeredTopologicalOrder[+A] protected[collection] (
@@ -478,9 +479,9 @@ trait GraphTraversal[N, E <: Edge[N]] extends GraphBase[N, E, GraphTraversal] {
/** Represents a cycle in this graph listing the nodes and connecting edges on it
* with the following syntax:
- *
+ * {{{
* `cycle ::= ''start-end-node'' { ''edge'' ''node'' } ''edge'' ''start-end-node''`
- *
+ * }}}
* All nodes and edges on the path are distinct except the start and end nodes that
* are equal. A cycle contains at least a start node followed by any number of
* consecutive pairs of an edge and a node and the end node equaling to the start node.
@@ -511,12 +512,16 @@ trait GraphTraversal[N, E <: Edge[N]] extends GraphBase[N, E, GraphTraversal] {
* only if the cycles contain the same elements in the same order, this comparison
* returns also `true` if the elements of `that` cycle can be shifted and optionally
* reversed such that their elements have the same order. For instance, given
- *
- * `c1 = Cycle(1-2-3-1)`, `c2 = Cycle(2-3-1-2)` and `c3 = Cycle(2-1-3-2)`
- *
+ * {{{
+ * c1 = Cycle(1-2-3-1)
+ * c2 = Cycle(2-3-1-2)
+ * c3 = Cycle(2-1-3-2)
+ * }}}
* the following expressions hold:
- *
- * `c1 != c2`, `c1 != c3` but `c1 sameAs c2` and `c1 sameAs c3`.
+ * {{{
+ * `c1 != c2`, `c1 != c3` but
+ * `c1 sameAs c2` and `c1 sameAs c3`
+ * }}}
*/
final def sameAs(that: GraphTraversal[N, E]#Cycle): Boolean =
this == that || (that match {
@@ -556,7 +561,7 @@ trait GraphTraversal[N, E <: Edge[N]] extends GraphBase[N, E, GraphTraversal] {
*/
def isComplete = {
val orderLessOne = order - 1
- nodes forall (_.diSuccessors.size == orderLessOne)
+ nodes forall (_.outNeighbors.size == orderLessOne)
}
/** An arbitrary edge between `from` and `to` that is available most efficiently.
@@ -880,8 +885,6 @@ trait GraphTraversal[N, E <: Edge[N]] extends GraphBase[N, E, GraphTraversal] {
abstract protected class TraverserMethods[A, +CC <: TraverserMethods[A, CC]] extends FluentProperties[CC] {
this: CC with Properties =>
- def root: NodeT
-
protected def nodeVisitor[U](f: A => U): (NodeT) => U
protected def edgeVisitor[U](f: A => U): (EdgeT) => U
@@ -1428,7 +1431,6 @@ trait GraphTraversal[N, E <: Edge[N]] extends GraphBase[N, E, GraphTraversal] {
* the number of consecutive child visits before siblings are visited for DFS.
* `0` - the default - indicates that the traversal should have
* an unlimited depth.
- * @author Peter Empen
*/
object GraphTraversal {
diff --git a/core/src/main/scala/scalax/collection/GraphTraversalImpl.scala b/core/src/main/scala/scalax/collection/GraphTraversalImpl.scala
index 354dc74a..2c316a62 100644
--- a/core/src/main/scala/scalax/collection/GraphTraversalImpl.scala
+++ b/core/src/main/scala/scalax/collection/GraphTraversalImpl.scala
@@ -1,8 +1,10 @@
package scalax.collection
import scala.annotation.{switch, tailrec}
-import scala.collection.{AbstractIterable, EqSetFacade, IndexedSeq, Seq}
+import scala.collection.{mutable, AbstractIterable, EqSetFacade, IndexedSeq, Seq}
import scala.collection.mutable.{ArrayBuffer, Buffer, Map => MMap, Stack}
+import scala.util.compat.Boundary.boundary
+
import scalax.collection.generic.Edge
import scalax.collection.mutable.{EqHashMap, EqHashSet}
@@ -27,7 +29,7 @@ trait GraphTraversalImpl[N, E <: Edge[N]] extends GraphTraversal[N, E] with Trav
): Option[Cycle] =
maybeStart map { start =>
new AnyEdgeLazyCycle(
- new ReverseStackTraversable[DfsElem](stack, None, Array[Option[DfsElem]](None, Some(DfsElem(start)))),
+ new CycleNodes[DfsElem](stack, None, prefix = None, postfix = DfsElem(start)),
edgeFilter
)
}
@@ -35,14 +37,18 @@ trait GraphTraversalImpl[N, E <: Edge[N]] extends GraphTraversal[N, E] with Trav
final protected def cycle(results: Option[(NodeT, Stack[CycleStackElem])], edgeFilter: EdgePredicate): Option[Cycle] =
results match {
case Some((start, stack)) =>
- val reverse = new ReverseStackTraversable[CycleStackElem](
- stack,
- Some((elem: CycleStackElem) => elem.node ne start),
- Array.fill[Option[CycleStackElem]](2)(Some(CycleStackElem(start)))
- )
+ val iterable = {
+ val affix = CycleStackElem(start)
+ new CycleNodes[CycleStackElem](
+ stack,
+ Some((elem: CycleStackElem) => elem.node ne start),
+ Some(affix),
+ affix
+ )
+ }
Some(
- if (thisGraph.isDirected) new AnyEdgeLazyCycle(reverse, edgeFilter)
- else new MultiEdgeLazyCycle(reverse, edgeFilter)
+ if (thisGraph.isDirected) new AnyEdgeLazyCycle(iterable, edgeFilter)
+ else new MultiEdgeLazyCycle(iterable, edgeFilter)
)
case _ => None
}
@@ -288,20 +294,21 @@ trait GraphTraversalImpl[N, E <: Edge[N]] extends GraphTraversal[N, E] with Trav
def findCycle[U](implicit visitor: InnerElem => U = Visitor.empty): Option[Cycle] =
if (order == 0) None
- else {
- val traverser = innerElemTraverser
- withHandles(2) { handles =>
- implicit val visitedHandle: State.Handle = handles(0)
- for (node <- nodes if !node.visited && subgraphNodes(node)) {
- val nodeTraverser: InnerElemTraverserImpl =
- traverser.withRoot(node) // TODO not sure why this declaration is needed
- val res = nodeTraverser.Runner(noNode, visitor).dfsWGB(handles)
- if (res.isDefined)
- return cycle(res, subgraphEdges)
+ else
+ boundary { break =>
+ val traverser = innerElemTraverser
+ withHandles(2) { handles =>
+ implicit val visitedHandle: State.Handle = handles(0)
+ for (node <- nodes if !node.visited && subgraphNodes(node)) {
+ val nodeTraverser: InnerElemTraverserImpl =
+ traverser.withRoot(node) // TODO not sure why this declaration is needed
+ val res = nodeTraverser.Runner(noNode, visitor).dfsWGB(handles)
+ if (res.isDefined)
+ break(cycle(res, subgraphEdges))
+ }
}
+ None
}
- None
- }
final def topologicalSort[U](implicit visitor: InnerElem => U = Visitor.empty): TopologicalSort =
innerElemTraverser
@@ -638,59 +645,38 @@ trait GraphTraversalImpl[N, E <: Edge[N]] extends GraphTraversal[N, E] with Trav
): OuterNodeDownUpTraverser =
OuterNodeDownUpTraverserImpl(root, parameters, subgraphNodes, subgraphEdges, ordering, maxWeight)
- /** Efficient reverse `foreach` overcoming `Stack`'s deficiency not to overwrite `reverseIterator`.
- */
- // TODO is this still needed? Stack now _does_ override `reverseIterator`.
- final protected class ReverseStackTraversable[S <: NodeElement](
- s: IndexedSeq[S],
- takeWhile: Option[S => Boolean] = None,
- enclosed: Array[Option[S]] = Array[Option[S]](None, None)
+ final protected class CycleNodes[S <: NodeElement](
+ stack: mutable.Stack[S],
+ strip: Option[S => Boolean] = None,
+ prefix: Option[S],
+ postfix: S
) extends Iterable[NodeT] {
override def iterator = source.map(_.node).iterator
final override protected def className = "Nodes"
- private[this] var _size: Option[Int] = None
- @inline override val size: Int = _size getOrElse super.size
-
- @inline override def last: NodeT = enclosed(1).fold(ifEmpty = s.head.node)(_.node)
-
- // TODO unreachable?
- def reverse: Iterable[NodeT] = new AbstractIterable[NodeT] {
- override def iterator: Iterator[NodeT] = ???
- /* TODO replace foreach with iterator
- def foreach[U](f: NodeT => U): Unit = {
- def fT(elem: S): Unit = f(elem.node)
- def end(i: Int): Unit = enclosed(i) foreach fT
- end(1)
- s foreach fT
- end(0)
- }
- */
+ private val skipCount: Int = strip.fold(ifEmpty = 1) { pred =>
+ val it = stack.reverseIterator
+ var i = 1
+ while (it.hasNext && pred(it.next())) i += 1
+ i
}
- private lazy val upper: Int = takeWhile.fold(ifEmpty = s.size) { pred =>
- var i = s.size - 1
- while (i >= 0 && pred(s(i))) i -= 1
- if (i < 0) 0 else i
- }
+ @inline override val size: Int = stack.size - skipCount + prefix.fold(0)(_ => 1) + 1
+ @inline override val last: NodeT = postfix.node
- private[GraphTraversalImpl] lazy val source: Iterable[S] = new AbstractIterable[S] {
+ private[GraphTraversalImpl] def source: Iterable[S] = new AbstractIterable[S] {
override def iterator = {
val buffer = ArrayBuffer[S]()
foreach(buffer += _)
buffer.iterator
}
+
override def foreach[U](f: S => U): Unit = {
- enclosed(0) foreach f
- var i = upper
- while (i > 0) {
- i -= 1
- f(s(i))
- }
- enclosed(1) foreach f
- if (_size.isEmpty) _size = Some(upper + enclosed.count(_.isDefined))
+ prefix foreach f
+ stack.reverseIterator.drop(skipCount) foreach f
+ f(postfix)
}
}
}
@@ -734,7 +720,8 @@ trait GraphTraversalImpl[N, E <: Edge[N]] extends GraphTraversal[N, E] with Trav
that.toArray[AnyGraph#InnerElem].sameElements(toArray[InnerElem])
case _ => false
}
- override def hashCode: Int = nodes.## + 27 * edges.##
+
+ final override def hashCode: Int = nodes.## + 27 * edges.##
}
/** `LazyPath` with deferred edges selection.
@@ -785,7 +772,7 @@ trait GraphTraversalImpl[N, E <: Edge[N]] extends GraphTraversal[N, E] with Trav
/** `LazyPath` with edge selection such that there exists no duplicate edge in the path.
*/
protected class MultiEdgeLazyPath(
- override val nodes: ReverseStackTraversable[CycleStackElem],
+ override val nodes: CycleNodes[CycleStackElem],
edgeFilter: EdgePredicate
) extends LazyPath(nodes) {
@@ -826,7 +813,7 @@ trait GraphTraversalImpl[N, E <: Edge[N]] extends GraphTraversal[N, E] with Trav
with Cycle
protected class MultiEdgeLazyCycle(
- override val nodes: ReverseStackTraversable[CycleStackElem],
+ override val nodes: CycleNodes[CycleStackElem],
edgeFilter: EdgePredicate
) extends MultiEdgeLazyPath(nodes, edgeFilter)
with Cycle
diff --git a/core/src/main/scala/scalax/collection/TraverserImpl.scala b/core/src/main/scala/scalax/collection/TraverserImpl.scala
index 2f2f3a8e..114c1ffe 100644
--- a/core/src/main/scala/scalax/collection/TraverserImpl.scala
+++ b/core/src/main/scala/scalax/collection/TraverserImpl.scala
@@ -4,6 +4,7 @@ import scala.annotation.{switch, tailrec}
import scala.collection.{FilterableSet, FilteredSet}
import scala.collection.mutable.{ArrayBuffer, Map => MMap, PriorityQueue, Queue, Stack}
import scala.reflect.ClassTag
+import scala.util.compat.Boundary.boundary
import scalax.collection.generic.Edge
import scalax.collection.immutable.SortedArraySet
@@ -43,9 +44,9 @@ trait TraverserImpl[N, E <: Edge[N]] {
): Option[Path] =
requireSuccessors {
Runner[U](pred, visitor).dfsStack() match {
- case (target, path) =>
+ case (target, stack) =>
target map { _ =>
- new AnyEdgeLazyPath(new ReverseStackTraversable[DfsInformer.Element](path), subgraphEdges)
+ new AnyEdgeLazyPath(Iterable.from(stack.reverseIterator.map(_.node)), subgraphEdges)
}
}
}
@@ -98,8 +99,8 @@ trait TraverserImpl[N, E <: Edge[N]] {
final protected class Runner[U] private (stopAt: StopCondition, visitor: A => U) {
private[this] val addMethod = parameters.direction match {
- case Successors => Node.addDiSuccessors _
- case Predecessors => Node.addDiPredecessors _
+ case Successors => Node.addOutNeighbors _
+ case Predecessors => Node.addInNeighbors _
case AnyConnected => Node.addNeighbors _
}
@@ -278,7 +279,7 @@ trait TraverserImpl[N, E <: Edge[N]] {
if (withEdgeFiltering)
filtered(node, nodeFilter, filteredEdges(node.outgoing, cumWeight), reverse)
else {
- val succ = node.diSuccessors
+ val succ = node.outNeighbors
filtered(succ, succ.size, nodeFilter, reverse)
}
@@ -291,7 +292,7 @@ trait TraverserImpl[N, E <: Edge[N]] {
if (withEdgeFiltering)
filtered(node, nodeFilter, filteredEdges(node.incoming, cumWeight), reverse)
else
- filtered(node.diPredecessors, -estimatedNrOfNodes(node), nodeFilter, reverse)
+ filtered(node.inNeighbors, -estimatedNrOfNodes(node), nodeFilter, reverse)
private[this] def filteredNeighbors(
node: NodeT,
@@ -425,22 +426,24 @@ trait TraverserImpl[N, E <: Edge[N]] {
}
visit(root)
- while (q.nonEmpty) {
- val Element(prevNode, prevDepth, cumWeight) = q.dequeue()
- if (prevDepth < untilDepth) {
- depth = prevDepth + 1
- for (n <- filteredNodes(prevNode, nonVisited, cumWeight, false)) {
- visit(n)
- if (stopAt(n, nodeCnt, depth)) return Some(n)
- q enqueue Element(
- n,
- depth,
- maxWeight.fold(ifEmpty = 0d)(w => cumWeight + minWeight(prevNode, n, cumWeight))
- )
+ boundary { break =>
+ while (q.nonEmpty) {
+ val Element(prevNode, prevDepth, cumWeight) = q.dequeue()
+ if (prevDepth < untilDepth) {
+ depth = prevDepth + 1
+ for (n <- filteredNodes(prevNode, nonVisited, cumWeight, false)) {
+ visit(n)
+ if (stopAt(n, nodeCnt, depth)) break(Some(n))
+ q enqueue Element(
+ n,
+ depth,
+ maxWeight.fold(ifEmpty = 0d)(w => cumWeight + minWeight(prevNode, n, cumWeight))
+ )
+ }
}
}
+ None
}
- None
}
@inline protected[collection] def dfs[U](maybeHandle: Option[Handle] = None): Option[NodeT] =
@@ -697,41 +700,45 @@ trait TraverserImpl[N, E <: Edge[N]] {
def mixedCycle(blackSuccessors: Iterable[NodeT]): Option[(NodeT, Stack[CycleStackElem])] =
withHandle() { handle =>
- val visitedBlackHandle = Some(handle)
- for (n <- blackSuccessors)
- thisImpl
- .withRoot(n)
- .withSubgraph(n => subgraphNodes(n) && !isWhite(n) && (n ne current), subgraphEdges)
- .pathUntil_(isGray, maybeHandle = visitedBlackHandle)
- .foreach { missingPath =>
- val start = missingPath.endNode
- val shortenedPath = {
- var found = false
- path takeWhile { case CycleStackElem(n, _) =>
- if (n eq start) {
- found = true
- true
- } else !found
- }
- }
- if (
- mustContain.forall { n =>
- missingPath.nodes.exists(_ eq n) ||
- shortenedPath.exists { case CycleStackElem(pn, _) => pn eq n }
+ boundary { break =>
+ val visitedBlackHandle = Some(handle)
+ for (n <- blackSuccessors)
+ thisImpl
+ .withRoot(n)
+ .withSubgraph(n => subgraphNodes(n) && !isWhite(n) && (n ne current), subgraphEdges)
+ .pathUntil_(isGray, maybeHandle = visitedBlackHandle)
+ .foreach { missingPath =>
+ val start = missingPath.endNode
+ val shortenedPath = {
+ var found = false
+ path takeWhile { case CycleStackElem(n, _) =>
+ if (n eq start) {
+ found = true
+ true
+ } else !found
+ }
}
- ) {
- missingPath.foldLeft((missingPath.nodes.head connectionsWith shortenedPath.head.node).head) {
- case (edge, inner: InnerNode) =>
- val n = inner.asInstanceOf[NodeT]
- if (isBlack(n))
- shortenedPath.push(new CycleStackElem(n, Set(edge)))
- edge
- case (_, InnerEdge(e, _)) => e
+ if (
+ mustContain.forall { n =>
+ missingPath.nodes.exists(_ eq n) ||
+ shortenedPath.exists { case CycleStackElem(pn, _) => pn eq n }
+ }
+ ) {
+ missingPath.foldLeft(
+ (missingPath.nodes.head connectionsWith shortenedPath.head.node).head
+ ) {
+ case (edge, inner: InnerNode) =>
+ val n = inner.asInstanceOf[NodeT]
+ if (isBlack(n))
+ shortenedPath.push(new CycleStackElem(n, Set(edge)))
+ edge
+ case (_, InnerEdge(e, _)) => e
+ }
+ break(Some(start, shortenedPath))
}
- return Some(start, shortenedPath)
}
- }
- None
+ None
+ }
}
def cycle(graySuccessors: Iterable[NodeT]): Option[(NodeT, Stack[CycleStackElem])] =
diff --git a/core/src/main/scala/scalax/collection/generator/RandomGraph.scala b/core/src/main/scala/scalax/collection/generator/RandomGraph.scala
index afd675d9..e36ccfb8 100644
--- a/core/src/main/scala/scalax/collection/generator/RandomGraph.scala
+++ b/core/src/main/scala/scalax/collection/generator/RandomGraph.scala
@@ -1,13 +1,14 @@
package scalax.collection
package generator
+import scala.annotation.tailrec
import scala.collection.mutable.{ArrayBuffer, Set => MSet}
import scala.util.Random
import scala.reflect.ClassTag
import scalax.collection.config.GraphConfig
-import scalax.collection.edges._
-import scalax.collection.generic._
+import scalax.collection.edges.*
+import scalax.collection.generic.*
/* TODO L
import edge.WBase.{WEdgeCompanion, WHyperEdgeCompanion}
import edge.LBase.{LEdgeCompanion, LHyperEdgeCompanion}
@@ -40,7 +41,7 @@ class RandomGraph[N, E <: Edge[N], G[X, Y <: Edge[X]] <: AnyGraph[X, Y] with Gra
weightFactory: Option[() => Long] = None,
labelFactory: Option[() => Any] = None
)(implicit nodeTag: ClassTag[N]) {
- require(order > 0)
+ require(order > 0, s"Requested random graph order must be strictly positive, not $order")
if (connected) require(nodeDegree.min >= 2)
implicit val graphConfig: GraphConfig = graphCompanion.defaultConfig
@@ -87,27 +88,20 @@ class RandomGraph[N, E <: Edge[N], G[X, Y <: Edge[X]] <: AnyGraph[X, Y] with Gra
}
private def addExact[A](nrToAdd: Int, add: => Boolean, infiniteMsg: String, gentle: Boolean): Boolean = {
- val checkInfiniteAt = math.pow(math.log(nrToAdd), 2).ceil.toInt + 10
- val infiniteFactor = 5
+ val assumeInfiniteAt = (nrToAdd * 3) + math.log(nrToAdd * 10).ceil.toInt
- var added, lastAdded = 0
- var trials = 0
- while (added < nrToAdd) {
- if (add) added += 1
+ @tailrec def loop(added: Int, missed: Int): Boolean =
+ if (added < nrToAdd)
+ if (missed > assumeInfiniteAt) {
+ traceln(s"gentle=$gentle, added=$added, missed=$missed, ")
- trials += 1
- if (trials == checkInfiniteAt) {
- if ((added - lastAdded) * infiniteFactor < trials) {
- traceln(s"gentle=$gentle trials=$trials, lastAdded=$lastAdded, added=$added")
-
- if (gentle) return false
+ if (gentle) false
else throw new IllegalArgumentException(infiniteMsg)
- }
- trials = 0
- lastAdded = added
- }
- }
- true
+ } else if (add) loop(added + 1, missed)
+ else loop(added, missed + 1)
+ else true
+
+ loop(0, 0)
}
final protected[RandomGraph] class Degrees {
diff --git a/core/src/main/scala/scalax/collection/generic/edgeBase.scala b/core/src/main/scala/scalax/collection/generic/edgeBase.scala
index d6e675ea..6c97b2fa 100644
--- a/core/src/main/scala/scalax/collection/generic/edgeBase.scala
+++ b/core/src/main/scala/scalax/collection/generic/edgeBase.scala
@@ -61,7 +61,7 @@ sealed trait Edge[+N] extends Equals {
*/
def isLooping: Boolean
- /** Same as `! looping`. */
+ /** Same as `! isLooping`. */
@inline final def nonLooping: Boolean = !isLooping
/** The weight of this edge with a default of 1.
diff --git a/core/src/main/scala/scalax/collection/immutable/AdjacencyListBase.scala b/core/src/main/scala/scalax/collection/immutable/AdjacencyListBase.scala
index 2c1226d1..79b090c9 100644
--- a/core/src/main/scala/scalax/collection/immutable/AdjacencyListBase.scala
+++ b/core/src/main/scala/scalax/collection/immutable/AdjacencyListBase.scala
@@ -2,12 +2,13 @@ package scalax.collection
package immutable
import java.io.{ObjectInputStream, ObjectOutputStream}
+
import scala.annotation.unchecked.{uncheckedVariance => uV}
import scala.collection.{AbstractIterable, AbstractIterator, EqSetFacade}
import scala.collection.mutable.{ArrayBuffer, ExtHashSet}
import scala.util.Random
+
import scalax.collection.generic.Edge
-import scalax.collection.AnyGraph
import scalax.collection.mutable.{ArraySet, EqHashMap, EqHashSet}
import scalax.collection.config.{AdjacencyListArrayConfig, GraphConfig}
@@ -30,49 +31,58 @@ trait AdjacencyListBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y,
def edges: ArraySet[EdgeT]
@inline final protected def nodeEqThis = (n: NodeT) => n eq this
- protected[collection] object Adj extends Serializable { // lazy adjacents
- @transient protected[collection] var _aHook: Option[(NodeT, EdgeT)] = _
- final def aHook: Option[(NodeT, EdgeT)] = {
- if (_aHook eq null) diSucc
+
+ protected[collection] object Lazy extends Serializable {
+ @transient protected[collection] var _aHook: Option[EdgeT] = _
+ @transient private var outN: EqHashMap[NodeT, EdgeT] = _
+
+ def aHook: Option[EdgeT] = {
+ if (_aHook eq null) outNeighborsToSomeEdge
_aHook
}
- @transient private var _diSucc: EqHashMap[NodeT, EdgeT] = _
- final def diSucc: EqHashMap[NodeT, EdgeT] =
+ def outNeighborsToSomeEdge: EqHashMap[NodeT, EdgeT] =
if (edges eq null)
new EqHashMap[NodeT, EdgeT]
else {
- if (_diSucc eq null) {
+ if (outN eq null) {
val m = new EqHashMap[NodeT, EdgeT](edges.size)
_aHook = None
edges foreach { e =>
- if (e.matches(nodeEqThis, nodeEqThis) && aHook.isEmpty)
- _aHook = Some(thisNode -> e)
- addDiSuccessors(e, (n: NodeT) => m put (n, e))
+ if (aHook.isEmpty && e.matches(nodeEqThis, nodeEqThis))
+ _aHook = Some(e)
+ addOutNeighbors(e, (n: NodeT) => m put (n, e))
}
- _diSucc = m
+ outN = m
}
- _diSucc
+ outN
}
+
+ def diSuccessors: Set[NodeT] = new EqSetFacade(
+ aHook.fold(outNeighborsToSomeEdge.keys)(_ => Iterable.single(thisNode) ++ outNeighborsToSomeEdge.keys)
+ )
}
- import Adj._
+ import Lazy.{aHook, outNeighborsToSomeEdge}
final def connectionsWith(other: NodeT) = edges withSetFilter (_.isAt(other))
- final def hasOnlyHooks = diSucc.isEmpty && aHook.isDefined
+ final def hasOnlyHooks = outNeighbors.isEmpty && aHook.isDefined
+
+ final def hook: Option[EdgeT] = aHook
- final def hook: Option[EdgeT] = aHook map (_._2)
+ final def outNeighbors: Set[NodeT] = new immutable.EqSet(outNeighborsToSomeEdge)
- final def isDirectPredecessorOf(that: NodeT): Boolean =
- diSucc contains that
+ final def diSuccessors: Set[NodeT] = Lazy.diSuccessors
+
+ final def isDirectPredecessorOf(that: NodeT): Boolean = diSuccessors contains that
final def isIndependentOf(that: NodeT): Boolean =
if (this eq that) edges forall (_.nonLooping)
else edges forall (!_.isAt((_: NodeT) eq that))
- final def hasSuccessors: Boolean = diSuccessors exists (_ ne this)
+ final def hasSuccessors: Boolean = diSuccessors.nonEmpty
- final protected[collection] def addDiSuccessors(edge: EdgeT, add: (NodeT) => Unit): Unit = {
+ final protected[collection] def addOutNeighbors(edge: EdgeT, add: (NodeT) => Unit): Unit = {
val filter =
if (edge.isHyperEdge && edge.isDirected) edge.hasSource((_: NodeT) eq this)
else true
@@ -80,17 +90,29 @@ trait AdjacencyListBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y,
}
final def diPredecessors: Set[NodeT] = {
- val m = new EqHashMap[NodeT, EdgeT](edges.size)
+ val m = new EqHashSet[NodeT](edges.size)
+ var selfAdded = false
edges foreach { e =>
- addDiPredecessors(e, (n: NodeT) => m put (n, e))
+ addInNeighbors(e, m += _)
+ if (!selfAdded)
+ if (e.matches(nodeEqThis, nodeEqThis)) {
+ m += thisNode
+ selfAdded = true
+ }
}
- new EqSet(m)
+ new EqSetFacade(m)
}
final def hasPredecessors: Boolean = edges exists (_.hasSource((n: NodeT) => n ne this))
- final protected[collection] def addDiPredecessors(edge: EdgeT, add: NodeT => Unit): Unit =
- edge.sources foreach (n => if (n ne this) add(n))
+ @inline final protected[collection] def addInNeighbors(edge: EdgeT, add: NodeT => Unit): Unit =
+ edge withSources (n => if (n ne this) add(n))
+
+ def inNeighbors: Set[NodeT] = {
+ val m = new EqHashSet[NodeT](edges.size)
+ edges foreach (addInNeighbors(_, m += _))
+ new EqSetFacade(m)
+ }
final def neighbors: Set[NodeT] = {
val m = new EqHashSet[NodeT](edges.size)
@@ -105,6 +127,7 @@ trait AdjacencyListBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y,
if (e.isDirected) e.hasSource((_: NodeT) eq this)
else true
)
+
@inline private[this] def isOutgoingTo(e: EdgeT, to: NodeT): Boolean =
if (e.isDirected)
e matches ((_: NodeT) eq this, (_: NodeT) eq to)
@@ -114,13 +137,14 @@ trait AdjacencyListBase[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: GraphLike[X, Y,
final def outgoingTo(to: NodeT) = edges withSetFilter (isOutgoingTo(_, to))
final def findOutgoingTo(to: NodeT): Option[EdgeT] =
- if (to eq this) aHook map (_._2)
- else diSucc get to
+ if (to eq this) aHook
+ else outNeighborsToSomeEdge get to
final def incoming = edges withSetFilter (e =>
if (e.isDirected) e.hasTarget((_: NodeT) eq this)
else true
)
+
@inline final private[this] def isIncomingFrom(e: EdgeT, from: NodeT): Boolean =
if (e.isDirected)
e matches ((_: NodeT) eq from, (_: NodeT) eq this)
diff --git a/core/src/main/scala/scalax/collection/immutable/AdjacencyListGraph.scala b/core/src/main/scala/scalax/collection/immutable/AdjacencyListGraph.scala
index ef386b03..5b695aad 100644
--- a/core/src/main/scala/scalax/collection/immutable/AdjacencyListGraph.scala
+++ b/core/src/main/scala/scalax/collection/immutable/AdjacencyListGraph.scala
@@ -19,13 +19,7 @@ trait AdjacencyListGraph[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: AdjacencyListG
abstract class InnerNodeImpl(val outer: N, hints: ArraySet.Hints) extends NodeBase with AdjacendyListBaseInnerNode {
this: NodeT =>
- final override val edges: ArraySet[EdgeT] = ArraySet.emptyWithHints[EdgeT](hints)
- @transient protected var _diSuccessors: immutable.EqSet[NodeT] = _
-
- final def diSuccessors: Set[NodeT] = {
- if (_diSuccessors eq null) _diSuccessors = new immutable.EqSet(Adj.diSucc)
- _diSuccessors
- }
+ final override val edges: ArraySet[EdgeT] = ArraySet.emptyWithHints[EdgeT](hints)
}
type NodeSetT = AdjacencyListNodeSet
diff --git a/core/src/main/scala/scalax/collection/immutable/EqSet.scala b/core/src/main/scala/scalax/collection/immutable/EqSet.scala
index 7f8772f2..5220d22d 100644
--- a/core/src/main/scala/scalax/collection/immutable/EqSet.scala
+++ b/core/src/main/scala/scalax/collection/immutable/EqSet.scala
@@ -5,9 +5,9 @@ import scala.collection.immutable.Set
import scalax.collection.mutable.EqHashMap
/** Wrapper class mimicking a `scala.collection.immutable.Set`
- * without copying the contents of the underlying `EqHashMap`.
+ * without copying the contents of the underlying `EqHashMap`.
*
- * @define ON Creates a new `Set` as an O(N) operation
+ * @define ON Creates a new `Set` as an O(N) operation
*/
final class EqSet[K <: AnyRef](map: EqHashMap[K, _]) extends Set[K] {
diff --git a/core/src/main/scala/scalax/collection/immutable/SortedArraySet.scala b/core/src/main/scala/scalax/collection/immutable/SortedArraySet.scala
index 614f6959..fe96a208 100644
--- a/core/src/main/scala/scalax/collection/immutable/SortedArraySet.scala
+++ b/core/src/main/scala/scalax/collection/immutable/SortedArraySet.scala
@@ -65,23 +65,24 @@ class SortedArraySet[A](array: Array[A] = new Array[AnyRef](0).asInstanceOf[Arra
if (found == -1) None else Some(found)
}
- def rangeImpl(from: Option[A], until: Option[A]): SortedArraySet[A] = {
- if (size == 0 || from == None && until == None) return this
- val idxFrom = from flatMap (search(_, ordering.lt)) getOrElse 0
- val idxTill = (until flatMap (e =>
- search(e, ordering.lt) orElse (
- if (ordering.gt(e, array(size - 1))) Some(size)
- else Some(-1)
- )
- ) getOrElse size) - 1
- if (idxFrom > idxTill) empty
+ def rangeImpl(from: Option[A], until: Option[A]): SortedArraySet[A] =
+ if (size == 0 || from == None && until == None) this
else {
- val newSize = idxTill - idxFrom + 1
- val newArr: Array[AnyRef] = new Array(newSize)
- arraycopy(array, idxFrom, newArr, 0, newSize)
- new SortedArraySet(newArr.asInstanceOf[Array[A]])
+ val idxFrom = from flatMap (search(_, ordering.lt)) getOrElse 0
+ val idxTill = (until flatMap (e =>
+ search(e, ordering.lt) orElse (
+ if (ordering.gt(e, array(size - 1))) Some(size)
+ else Some(-1)
+ )
+ ) getOrElse size) - 1
+ if (idxFrom > idxTill) empty
+ else {
+ val newSize = idxTill - idxFrom + 1
+ val newArr: Array[AnyRef] = new Array(newSize)
+ arraycopy(array, idxFrom, newArr, 0, newSize)
+ new SortedArraySet(newArr.asInstanceOf[Array[A]])
+ }
}
- }
def find(elem: A): Option[A] = {
val i = array.indexOf(elem)
diff --git a/core/src/main/scala/scalax/collection/mutable/AdjacencyListGraph.scala b/core/src/main/scala/scalax/collection/mutable/AdjacencyListGraph.scala
index a37f6284..5d9b70d3 100644
--- a/core/src/main/scala/scalax/collection/mutable/AdjacencyListGraph.scala
+++ b/core/src/main/scala/scalax/collection/mutable/AdjacencyListGraph.scala
@@ -21,7 +21,7 @@ trait AdjacencyListGraph[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: AdjacencyListG
with AdjacendyListBaseInnerNode { this: NodeT =>
final override val edges: ArraySet[EdgeT] = ArraySet.emptyWithHints[EdgeT](hints)
- import Adj._
+ import Lazy._
final override protected[collection] def add(edge: EdgeT): Boolean =
if (super.add(edge)) {
@@ -37,23 +37,23 @@ trait AdjacencyListGraph[N, E <: Edge[N], +CC[X, Y <: Edge[X]] <: AdjacencyListG
final protected def addDiSuccOrHook(edge: EdgeT): Unit = {
if (edge.matches(nodeEqThis, nodeEqThis) && aHook.isEmpty)
- _aHook = Some(this -> edge)
- addDiSuccessors(edge, (n: NodeT) => diSucc put (n, edge))
+ _aHook = Some(edge)
+ addOutNeighbors(edge, (n: NodeT) => outNeighborsToSomeEdge put (n, edge))
}
- final def diSuccessors: Set[NodeT] = new immutable.EqSet(diSucc)
-
protected[collection] def remove(edge: EdgeT): Boolean =
if (edges.remove(edge)) {
if (selfGraph.edges.initialized) {
def onLooping(): Unit =
- edges.find((e: EdgeT) => e.isLooping).fold(ifEmpty = _aHook = None)((e: EdgeT) => _aHook = Some(this -> e))
+ edges.find((e: EdgeT) => e.isLooping).fold(ifEmpty = _aHook = None)((e: EdgeT) => _aHook = Some(e))
def onNonLooping(): Unit = edge.targets foreach (t =>
edges
.find((e: EdgeT) => e.hasTarget((n: NodeT) => n eq t))
- .fold[Unit](ifEmpty = diSucc remove t)((e: EdgeT) => if (e hasSource this) diSucc put (t, e))
+ .fold[Unit](ifEmpty = outNeighborsToSomeEdge remove t)((e: EdgeT) =>
+ if (e hasSource this) outNeighborsToSomeEdge put (t, e)
+ )
)
if (edge.isHyperEdge)
diff --git a/core/src/main/scala/scalax/collection/mutable/EqHash.scala b/core/src/main/scala/scalax/collection/mutable/EqHash.scala
index 4ab3af21..28c57fb5 100644
--- a/core/src/main/scala/scalax/collection/mutable/EqHash.scala
+++ b/core/src/main/scala/scalax/collection/mutable/EqHash.scala
@@ -2,6 +2,7 @@ package scalax.collection.mutable
import scala.collection.Util.nextPositivePowerOfTwo
import scala.collection.mutable.Growable
+import scala.util.compat.Boundary.boundary
trait EqHash[A, C <: EqHash[A, C]] {
this: IterableOnce[A] with Growable[A] with Equals =>
@@ -45,15 +46,15 @@ trait EqHash[A, C <: EqHash[A, C]] {
else nextPositivePowerOfTwo(min)
}
- protected def index(maskedKey: AnyRef, keyHash: Int, tabLength: Int): Int = {
+ protected def index(maskedKey: AnyRef, keyHash: Int, tabLength: Int): Int = boundary { break =>
val tab = table
var i = keyHash
while (true) {
val item = tab(i)
if (item eq maskedKey)
- return i
+ break(i)
else if (item eq null)
- return ~i
+ break(~i)
else
i = nextKeyIndex(i, tabLength)
}
@@ -120,14 +121,14 @@ trait EqHash[A, C <: EqHash[A, C]] {
private[this] var lastReturnedIndex = -1
private[this] var indexValid = false
- def hasNext: Boolean = {
+ def hasNext: Boolean = boundary { break =>
val s = step
var i = index
while (i < len) {
if (tab(i) ne null) {
index = i
indexValid = true
- return true
+ break(true)
}
i += s
}
@@ -141,7 +142,7 @@ trait EqHash[A, C <: EqHash[A, C]] {
indexValid = false
lastReturnedIndex = index
index += step
- return lastReturnedIndex
+ lastReturnedIndex
}
}
diff --git a/core/src/main/scala/scalax/collection/mutable/ExtBitSet.scala b/core/src/main/scala/scalax/collection/mutable/ExtBitSet.scala
index 93bd1ffd..016e590f 100644
--- a/core/src/main/scala/scalax/collection/mutable/ExtBitSet.scala
+++ b/core/src/main/scala/scalax/collection/mutable/ExtBitSet.scala
@@ -1,10 +1,12 @@
package scalax.collection
package mutable
+import java.lang.Long.{bitCount, lowestOneBit => jLowestOneBit, toBinaryString}
+import scala.annotation.tailrec
import scala.collection.mutable.BitSet
import State.Handle
-import ExtBitSet._
+import ExtBitSet.*
final protected[collection] class ExtBitSet(words: Array[Long]) extends BitSet(words) {
def this(initWords: Int = incrWords) = this(new Array[Long](initWords))
@@ -22,11 +24,11 @@ final protected[collection] class ExtBitSet(words: Array[Long]) extends BitSet(w
/** All bits of all words. */
override def toString =
- (elems map (w => "%64s".format(java.lang.Long.toBinaryString(w)).replace(' ', '0'))).mkString(" ")
+ (elems map (w => "%64s".format(toBinaryString(w)).replace(' ', '0'))).mkString(" ")
/** Summary of the words each of which formatted as :. */
def summary: String =
- elems.zipWithIndex.map(zWord => "%2d:%2d" format (zWord._2, java.lang.Long.bitCount(zWord._1))) mkString " "
+ elems.zipWithIndex.map(zWord => "%2d:%2d" format (zWord._2, bitCount(zWord._1))) mkString " "
@inline def apply(idx: Int, mask: Long): Boolean =
(word(idx) & mask) != 0
@@ -64,23 +66,25 @@ final protected[collection] class ExtBitSet(words: Array[Long]) extends BitSet(w
}
def onOrFindUnset(other: ExtBitSet): Option[Handle] = {
- var idx = 0
- while (idx < nwords) {
- val or = elems(idx) | other.word(idx)
- if (or == ~0) idx += 1
- else return Some(new Handle(idx, java.lang.Long.lowestOneBit(~or)))
- }
- None
+ @tailrec def loop(idx: Int): Option[Handle] =
+ if (idx < nwords) {
+ val or = elems(idx) | other.word(idx)
+ if (or == ~0) loop(idx + 1)
+ else Some(new Handle(idx, jLowestOneBit(~or)))
+ } else None
+
+ loop(0)
}
def lowestOneBit: Option[Handle] = {
- var idx = 0
- while (idx < nwords) {
- val bit = java.lang.Long.lowestOneBit(elems(idx))
- if (bit == 0) idx += 1
- else return Some(new Handle(idx, bit))
- }
- None
+ @tailrec def loop(idx: Int): Option[Handle] =
+ if (idx < nwords) {
+ val bit = jLowestOneBit(elems(idx))
+ if (bit == 0) loop(idx + 1)
+ else Some(new Handle(idx, bit))
+ } else None
+
+ loop(0)
}
private def expand(mustHaveIdx: Int): Unit = {
diff --git a/core/src/main/scala/scalax/collection/mutable/Growable.scala b/core/src/main/scala/scalax/collection/mutable/Growable.scala
index 73fd02e8..7f1f31b6 100644
--- a/core/src/main/scala/scalax/collection/mutable/Growable.scala
+++ b/core/src/main/scala/scalax/collection/mutable/Growable.scala
@@ -39,7 +39,6 @@ trait Growable[-N, -E <: Edge[N @uV]] {
}
/** Adds all elements produced by `outer` to this graph.
- * For a graph see also `unionInPlace`.
*/
def addAll(xs: Iterable[OuterElem[N, E]]): this.type = { xs foreach addOuter; this }
@@ -47,11 +46,18 @@ trait Growable[-N, -E <: Edge[N @uV]] {
def ++=(xs: Iterable[OuterElem[N, E]]): this.type = { xs foreach addOuter; this }
/** Adds all passed nodes and edges to this graph.
- * For a mutable Graph see also `unionInPlace`.
*/
- def ++=(nodes: Iterable[N] = Nil, edges: Iterable[E @uV] = Nil): this.type = {
+ def addAll(nodes: Iterable[N], edges: Iterable[E @uV]): this.type = {
nodes foreach addOne
edges foreach +=
this
}
+
+ /** Adds all `nodes` to this graph.
+ */
+ def addNodes(nodes: Iterable[N]): this.type = { nodes foreach addOne; this }
+
+ /** Adds all `edges` to this graph. Nodes being ends of `edges` are also added if not yet present.
+ */
+ def addEdges(edges: Iterable[E]): this.type = { edges foreach +=; this }
}
diff --git a/core/src/main/scala/scalax/collection/mutable/SimpleArraySet.scala b/core/src/main/scala/scalax/collection/mutable/SimpleArraySet.scala
index 4d041b19..3f9f3e58 100644
--- a/core/src/main/scala/scalax/collection/mutable/SimpleArraySet.scala
+++ b/core/src/main/scala/scalax/collection/mutable/SimpleArraySet.scala
@@ -1,6 +1,7 @@
package scalax.collection
package mutable
+import scala.annotation.tailrec
import scala.collection.mutable.{ExtHashSet, GrowableBuilder}
import scala.collection.{IterableFactory, IterableFactoryDefaults, SortedSet, StrictOptimizedIterableOps}
import scala.util.Random
@@ -60,11 +61,9 @@ final class SimpleArraySet[A](override val hints: ArraySet.Hints)
protected[collection] def +=!(elem: A): this.type = {
if (isHash) hashSet add elem
+ else if (nextFree == capacity && resizedToHash)
+ add(elem)
else {
- if (nextFree == capacity)
- if (resizedToHash) {
- add(elem); return this
- }
arr(nextFree) = elem
nextFree += 1
}
@@ -128,20 +127,24 @@ final class SimpleArraySet[A](override val hints: ArraySet.Hints)
resizeArray(capacity, nextFree)
protected def indexOf[B](elem: B, pred: (A, B) => Boolean): Int = {
- var i = 0
- while (i < nextFree)
- if (pred(arr(i), elem)) return i
- else i += 1
- -1
+ @tailrec def loop(i: Int): Int =
+ if (i < nextFree)
+ if (pred(arr(i), elem)) i
+ else loop(i + 1)
+ else -1
+
+ loop(0)
}
/* Optimized 'arr contains c'. */
protected def indexOf(elem: A): Int = {
- var i = 0
- while (i < nextFree)
- if (arr(i) == elem) return i
- else i += 1
- -1
+ @tailrec def loop(i: Int): Int =
+ if (i < nextFree)
+ if (arr(i) == elem) i
+ else loop(i + 1)
+ else -1
+
+ loop(0)
}
override def contains(elem: A): Boolean =
@@ -157,14 +160,10 @@ final class SimpleArraySet[A](override val hints: ArraySet.Hints)
override def add(elem: A): Boolean =
if (isHash) hashSet add elem
+ else if (nextFree == capacity && resizedToHash)
+ add(elem)
+ else if (indexOf(elem) >= 0) false
else {
- if (nextFree == capacity)
- if (resizedToHash)
- return add(elem)
- var i = 0
- while (i < nextFree)
- if (arr(i) == elem) return false
- else i += 1
arr(nextFree) = elem
nextFree += 1
true
diff --git a/core/src/test/scala-2/scalax/collection/EditingTypedSpec.scala b/core/src/test/scala-2/scalax/collection/EditingTypedSpec.scala
index 901bcbb3..c0603d14 100644
--- a/core/src/test/scala-2/scalax/collection/EditingTypedSpec.scala
+++ b/core/src/test/scala-2/scalax/collection/EditingTypedSpec.scala
@@ -94,7 +94,7 @@ private class EditingTyped[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[
madrid ~> rio :++ (flightNo, outer.departures, outer.duration) shouldBe outer
}
- def `extractor ` : Unit = {
+ def `extractor `: Unit = {
val g = typedFactory.empty.asAnyGraph
g.nodes foreach { case g.InnerNode(inner, Airport(code)) =>
diff --git a/core/src/test/scala-3/scalax/collection/EditingTypedSpec.scala b/core/src/test/scala-3/scalax/collection/EditingTypedSpec.scala
index 7ca909af..e080d440 100644
--- a/core/src/test/scala-3/scalax/collection/EditingTypedSpec.scala
+++ b/core/src/test/scala-3/scalax/collection/EditingTypedSpec.scala
@@ -94,7 +94,7 @@ private class EditingTyped[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[
madrid ~> rio :++ (flightNo, outer.departures, outer.duration) shouldBe outer
}
- def `extractor ` : Unit = {
+ def `extractor `: Unit = {
val g = typedFactory.empty.asAnyGraph
g.nodes foreach { case g.InnerNode(inner, Airport(code)) =>
diff --git a/core/src/test/scala/demo/EditingDemoSpec.scala b/core/src/test/scala/demo/EditingDemoSpec.scala
index da246edc..8df0121c 100644
--- a/core/src/test/scala/demo/EditingDemoSpec.scala
+++ b/core/src/test/scala/demo/EditingDemoSpec.scala
@@ -39,7 +39,7 @@ final class EditingDemoSpec extends RefSpec with Matchers {
(Graph[Int, AnyEdge](1, 2 ~ 3) += 3 ~> 1) shouldBe Graph[Int, AnyEdge](1, 2 ~ 3, 3 ~> 1)
}
- def `equality ` : Unit = {
+ def `equality `: Unit = {
val g = immutable.Graph(1 ~ 2)
(g get 1).outer shouldBe 1
g get 1 ~ 2 shouldBe 2 ~ 1
@@ -47,7 +47,7 @@ final class EditingDemoSpec extends RefSpec with Matchers {
g get 1 ~ 2 should not be 2 ~ 2
}
- def `union, diff, intersect ` : Unit = {
+ def `union, diff, intersect `: Unit = {
import immutable.Graph
val g = Graph(1 ~ 2, 2 ~ 3, 2 ~ 4, 3 ~ 5, 4 ~ 5)
val h = Graph(3 ~ 4, 3 ~ 5, 4 ~ 6, 5 ~ 6)
@@ -58,7 +58,7 @@ final class EditingDemoSpec extends RefSpec with Matchers {
g & h shouldBe Graph(4, 3 ~ 5)
}
- def `endpoints ` : Unit = {
+ def `endpoints `: Unit = {
val uE = 3 ~ 4 // UnDiEdge[Int]
uE.node1 * uE.node2 shouldBe 12
@@ -80,7 +80,7 @@ final class EditingDemoSpec extends RefSpec with Matchers {
hE.ends.iterator.sum shouldBe 26
}
- def `neighbors ` : Unit = {
+ def `neighbors `: Unit = {
import immutable.Graph
val g = Graph[Int, AnyEdge](0, 1 ~ 3, 3 ~> 2)
@@ -96,7 +96,7 @@ final class EditingDemoSpec extends RefSpec with Matchers {
n(3) findOutgoingTo n(2) shouldBe Some(e(3 ~> 2))
}
- def `querying ` : Unit = {
+ def `querying `: Unit = {
import immutable.Graph
val g = Graph[Int, AnyEdge](2 ~> 3, 3 ~ 1, 5)
@@ -107,7 +107,7 @@ final class EditingDemoSpec extends RefSpec with Matchers {
g.edges filter (_ contains 4) shouldBe Symbol("empty")
}
- def `measuring ` : Unit = {
+ def `measuring `: Unit = {
import immutable.Graph
import scalax.collection.edges.labeled._
val g = Graph[Int, AnyEdge](
@@ -129,7 +129,7 @@ final class EditingDemoSpec extends RefSpec with Matchers {
g.degreeNodesMap(degreeFilter = _ > 3) should contain only (4 -> Set(3, 4))
}
- def `classifying ` : Unit = {
+ def `classifying `: Unit = {
import immutable.Graph
val g = Graph(1, 2 ~> 3)
g.isConnected shouldBe false
diff --git a/core/src/test/scala/scalax/collection/CycleSpec.scala b/core/src/test/scala/scalax/collection/CycleSpec.scala
index 5413290b..7aaf574f 100644
--- a/core/src/test/scala/scalax/collection/CycleSpec.scala
+++ b/core/src/test/scala/scalax/collection/CycleSpec.scala
@@ -127,6 +127,16 @@ private class Cycle[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, C
}
}
+ def `cycles may be compared by 'sameAs'`(): Unit = {
+ val g1 = factory(1 ~> 2, 2 ~> 1).asAnyGraph
+ (g1 get 1 findCycle, g1 get 2 findCycle) match {
+ case (Some(c1), Some(c2)) =>
+ c1.startNode shouldNot be(c2.startNode)
+ c1 sameAs c2 shouldBe true
+ case (x, y) => fail(s"Cycles expected, got ($x, $y ) instead.")
+ }
+ }
+
def `the cycle returned by 'findCycleContaining' contains the expected nodes`: Unit = {
withGraph(acyclic_1) { g =>
g.findCycleContaining(g get 1) should be(None)
diff --git a/core/src/test/scala/scalax/collection/EditingHyperSpec.scala b/core/src/test/scala/scalax/collection/EditingHyperSpec.scala
index 48d6ae52..13347851 100644
--- a/core/src/test/scala/scalax/collection/EditingHyperSpec.scala
+++ b/core/src/test/scala/scalax/collection/EditingHyperSpec.scala
@@ -77,7 +77,7 @@ private class EditingHyper[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[
g.contains(h) shouldBe true
}
- def `isHyper ` : Unit = {
+ def `isHyper `: Unit = {
def test(g: CC[Int, AnyHyperEdge[Int]], expected: Boolean): Unit = g.isHyper should be(expected)
test(factory.from[Int, AnyHyperEdge](List(1 ~> 2, 1 ~~ 2 ~~ 3)), true)
@@ -94,17 +94,19 @@ private class EditingHyper[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[
single ~~> more(4, 9)
)
- object `diSuccessors ` {
+ object `diSuccessors, outNeighbors` {
def `for DiHyper`: Unit = {
- (hDi get 1).diSuccessors shouldEqual Set(2, 3, 4, 5, 9)
+ (hDi get 1).outNeighbors shouldEqual Set(2, 3, 4, 5, 9)
+ (hDi get 1).diSuccessors shouldEqual Set(1, 2, 3, 4, 5, 9)
(hDi get 2).diSuccessors shouldEqual Set.empty
(hDi get 5).diSuccessors shouldEqual Set.empty
}
}
- object `diPredecessors ` {
+ object `diPredecessors, inNeighbors` {
def `for DiHyper`: Unit = {
- (hDi get 1).diPredecessors should be(Set.empty)
+ (hDi get 1).inNeighbors should be(Set.empty)
+ (hDi get 1).diPredecessors should be(Set(1))
(hDi get 2).diPredecessors should be(Set(1))
(hDi get 5).diPredecessors should be(Set(1))
}
@@ -149,12 +151,14 @@ private class EditingHyperMutable extends RefSpec with Matchers {
val (n1, n2) = (g get 1, g get 2)
n2.diSuccessors shouldBe empty
- n1.diSuccessors should be(Set(2, 3))
+ n1.outNeighbors should be(Set(2, 3))
+ n1.diSuccessors should be(Set(1, 2, 3))
n1 findOutgoingTo n1 should be(Some(_1_to_1_2))
g subtractOne _1_to_2_3
g shouldEqual Graph(_1_to_1_2, 3)
- n1.diSuccessors should be(Set(2))
+ n1.outNeighbors should be(Set(2))
+ n1.diSuccessors should be(Set(1, 2))
n1 findOutgoingTo n1 should be(Some(_1_to_1_2))
g subtractOne 2
@@ -164,7 +168,8 @@ private class EditingHyperMutable extends RefSpec with Matchers {
g += _1_to_1_2
g shouldEqual Graph(_1_to_1_2, 3)
- n1.diSuccessors should be(Set(2))
+ n1.outNeighbors should be(Set(2))
+ n1.diSuccessors should be(Set(1, 2))
n1 findOutgoingTo n1 should be(Some(_1_to_1_2))
}
}
diff --git a/core/src/test/scala/scalax/collection/EditingSpec.scala b/core/src/test/scala/scalax/collection/EditingSpec.scala
index fb871e3a..0ba47541 100644
--- a/core/src/test/scala/scalax/collection/EditingSpec.scala
+++ b/core/src/test/scala/scalax/collection/EditingSpec.scala
@@ -48,7 +48,7 @@ class EditingImmutable extends RefSpec with Matchers {
val gString_A = Graph[String, AnyEdge]("A")
- def `- ` : Unit = {
+ def `- `: Unit = {
val g_1 = gString_A - "B"
g_1.order should be(1)
@@ -63,13 +63,13 @@ class EditingImmutable extends RefSpec with Matchers {
h - 2 should be(Graph(1, 3))
}
- def `-- ` : Unit = {
+ def `-- `: Unit = {
val g = Graph(1, 2 ~ 3, 3 ~ 4)
g -- (List(2), List(3 ~ 3)) should be(Graph(1, 3 ~ 4))
g -- (List(2), List(3 ~ 4)) should be(Graph(1, 3, 4))
}
- def `+ String ` : Unit = {
+ def `+ String `: Unit = {
val g = gString_A + "B"
g.elementCount shouldBe 2
g.nodes should contain("A")
@@ -106,7 +106,7 @@ private class EditingMutable extends RefSpec with Matchers {
g should be(Symbol("empty"))
}
- def `+ String ` : Unit = {
+ def `+ String `: Unit = {
val g = Graph("A") addOne "B"
g.elementCount shouldBe 2
g.contains("A") shouldBe true
@@ -119,7 +119,7 @@ private class EditingMutable extends RefSpec with Matchers {
h.elementCount should be(3)
}
- def `serve -= properly (2)` : Unit = {
+ def `serve -= properly (2)`: Unit = {
val g = Graph(1 ~ 2, 2 ~ 3)
g subtractOne 2 should be(Graph(1, 3))
g.size should be(0)
@@ -137,7 +137,7 @@ private class EditingMutable extends RefSpec with Matchers {
g.clear(); directed(false)
}
- def `serve 'diSuccessors' when directed`: Unit = {
+ def `serve 'diSuccessors', 'outNeighbors' when directed`: Unit = {
val (one, two, oneOne, oneTwo) = (1, 2, 1 ~> 1, 1 ~> 2)
val g = Graph(oneOne, oneTwo, one ~> 3, one ~> 4)
val (n1, n2) = (g get one, g get two)
@@ -145,25 +145,29 @@ private class EditingMutable extends RefSpec with Matchers {
g subtractOne 1 ~> 4 // Graph(oneOne, oneTwo, one~>3)
n2.diSuccessors shouldBe empty
- n1.diSuccessors.map(_.outer) shouldBe Set(two, 3)
+ n1.diSuccessors.map(_.outer) shouldBe Set(one, two, 3)
+ n1.outNeighbors.map(_.outer) shouldBe Set(two, 3)
n1 findOutgoingTo n1 should be(Some(e11))
g subtractOne oneTwo // Graph(oneOne, one~>3)
- n1.diSuccessors should be(Set(3))
+ n1.diSuccessors should be(Set(one, 3))
+ n1.outNeighbors should be(Set(3))
n1 findOutgoingTo n1 should be(Some(e11))
g subtractOne oneOne // Graph(one~>3)
n1.diSuccessors should be(Set(3))
+ n1.outNeighbors should be(Set(3))
n1 findOutgoingTo n1 should be(None)
- g ++= (edges = List(oneOne, oneTwo)) // Graph(oneOne, oneTwo, one~>3)
- n1.diSuccessors should be(Set(two, 3))
+ g addEdges List(oneOne, oneTwo) // Graph(oneOne, oneTwo, one~>3)
+ n1.diSuccessors should be(Set(one, two, 3))
+ n1.outNeighbors should be(Set(two, 3))
n1 findOutgoingTo n1 should be(Some(e11))
}
def `serve ++=, unionInPlace`: Unit = {
val (gBefore, gAfter) = (Graph(1, 2 ~ 3), Graph(0, 1 ~ 2, 2 ~ 3))
- (gBefore ++= (0 :: Nil, List(1 ~ 2, 2 ~ 3))) should equal(gAfter)
+ (gBefore addAll (0 :: Nil, List(1 ~ 2, 2 ~ 3))) should equal(gAfter)
(gBefore |= Graph(0, 1 ~ 2)) should equal(gAfter)
(gBefore |= Graph[Int, UnDiEdge](0) |= Graph(1 ~ 2)) should equal(gAfter)
}
@@ -183,13 +187,13 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
private val gString_A = factory("A")
object `graph editing` {
- def `empty ` : Unit = {
+ def `empty `: Unit = {
val eg = factory.empty[Nothing, Nothing]
eg shouldBe empty
eg should have size 0
}
- def `apply ` : Unit = {
+ def `apply `: Unit = {
gInt_1_3 should not be empty
gInt_1_3.order should be(2)
gInt_1_3(0) shouldBe false
@@ -205,14 +209,14 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
factory(N1() ~> N2(), N1() ~> N1()): CC[Node, DiEdge[Node]] // should typeCheck
}
- def `isDirected ` : Unit = {
+ def `isDirected `: Unit = {
def directed(g: CC[Int, AnyEdge[Int]], expected: Boolean): Unit = g.isDirected should be(expected)
directed(factory(1 ~ 2), false)
directed(factory(1 ~> 2), true)
}
- def `from ` : Unit = {
+ def `from `: Unit = {
val (n_start, n_end) = (11, 20)
val nodes = List.range(n_start, n_end)
val edges = List[DiEdge[Int]](14 ~> 16, 16 ~> 18, 18 ~> 20, 20 ~> 22)
@@ -221,17 +225,17 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
g.edges.size should be(edges.size)
}
- def `contains ` : Unit = {
+ def `contains `: Unit = {
seq_1_3 foreach (n => gInt_1_3 contains n should be(true))
gInt_1_3.iterator.next() shouldBe a[gInt_1_3.InnerNode]
}
- def `toString ` : Unit = {
+ def `toString `: Unit = {
gInt_1_3.toString shouldBe "Graph(NodeSet(1, 3), EdgeSet())"
gString_A.toString shouldBe """Graph(NodeSet(A), EdgeSet())"""
}
- def `render ` : Unit = {
+ def `render `: Unit = {
import ToString._
gInt_1_3.render(SetElemsOnSeparateLines()) shouldBe
"""Graph(
@@ -258,7 +262,7 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
| 1 ~ 2)""".stripMargin
}
- def `from inner ` : Unit = {
+ def `from inner `: Unit = {
val gn = factory(2, 3)
factory.from[Int, Nothing](gn.nodes.outerIterable, Nil) should equal(gn)
@@ -267,7 +271,7 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
factory.from(g.edges.outerIterable) should equal(g)
}
- def `NodeSet ` : Unit = {
+ def `NodeSet `: Unit = {
val o = Vector.range(0, 4)
val g = factory(o(1) ~ o(2), o(2) ~ o(3))
val n = o map (g.nodes find _ getOrElse g.nodes.head)
@@ -286,7 +290,7 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
restored.find(_ == n(1)).get.edges should have size 1
}
- def `EdgeAssoc ` : Unit = {
+ def `EdgeAssoc `: Unit = {
val e = 1 ~ 2
e shouldBe an[UnDiEdge[_]]
@@ -319,13 +323,28 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
private val gDi = factory(1 ~> 1, 1 ~> 2, 1 ~> 3, 1 ~> 4)
private val gMixed = factory[Int, AnyEdge](1 ~> 2, 2 ~> 3, 4 ~ 3)
+ object `outNeighbors ` {
+ def `for UnDi`: Unit = {
+ (gUnDi get 1).outNeighbors should be(Set(2, 3, 4))
+ (gUnDi get 2).outNeighbors should be(Set(1))
+ }
+ def `for Di`: Unit = {
+ (gDi get 1).outNeighbors should be(Set(2, 3, 4))
+ (gDi get 2).outNeighbors should be(Set.empty)
+ }
+ def `for mixed`: Unit = {
+ (gMixed get 2).outNeighbors should be(Set(3))
+ (gMixed get 3).outNeighbors should be(Set(4))
+ }
+ }
+
object `diSuccessors ` {
def `for UnDi`: Unit = {
- (gUnDi get 1).diSuccessors should be(Set(2, 3, 4))
+ (gUnDi get 1).diSuccessors should be(Set(1, 2, 3, 4))
(gUnDi get 2).diSuccessors should be(Set(1))
}
def `for Di`: Unit = {
- (gDi get 1).diSuccessors should be(Set(2, 3, 4))
+ (gDi get 1).diSuccessors should be(Set(1, 2, 3, 4))
(gDi get 2).diSuccessors should be(Set.empty)
}
def `for mixed`: Unit = {
@@ -334,19 +353,26 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
}
}
- object `diPredecessors ` {
- def `for UnDi`: Unit = {
- (gUnDi get 1).diPredecessors should be(Set(2, 3, 4))
- (gUnDi get 2).diSuccessors should be(Set(1))
+ object `inNeighbors ` {
+ def `for UnDi`: Unit =
+ (gUnDi get 1).inNeighbors should be(Set(2, 3, 4))
+ def `for Di`: Unit = {
+ (gDi get 1).inNeighbors should be(Set.empty)
+ (gDi get 2).inNeighbors should be(Set(1))
}
+ def `for mixed`: Unit =
+ (gMixed get 2).diPredecessors should be(Set(1))
+ }
+
+ object `diPredecessors ` {
+ def `for UnDi`: Unit =
+ (gUnDi get 1).diPredecessors should be(Set(1, 2, 3, 4))
def `for Di`: Unit = {
- (gDi get 1).diPredecessors should be(Set.empty)
+ (gDi get 1).diPredecessors should be(Set(1))
(gDi get 2).diPredecessors should be(Set(1))
}
- def `for mixed`: Unit = {
+ def `for mixed`: Unit =
(gMixed get 2).diPredecessors should be(Set(1))
- (gMixed get 3).diSuccessors should be(Set(4))
- }
}
object `neighbors ` {
@@ -367,13 +393,13 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
n(1) findOutgoingTo n(1) should be(Some(1 ~> 1))
}
- def `degree ` : Unit = {
+ def `degree `: Unit = {
val g = factory(1 ~ 1, 1 ~ 2, 1 ~ 3, 1 ~ 4)
(g get 1).degree should be(5)
(g get 2).degree should be(1)
}
- def `incoming ` : Unit = {
+ def `incoming `: Unit = {
val uEdges = Seq(1 ~ 1, 1 ~ 2, 1 ~ 3, 1 ~ 4)
val g = factory(uEdges(0), uEdges(1), uEdges(2), uEdges(3))
(g get 1).incoming should be(uEdges.toSet)
@@ -391,17 +417,17 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
(g get 1 ~ 2).adjacents should be(Set[AnyEdge[Int]](1 ~> 3, 1 ~ 5, 2 ~ 3))
}
- def `filter ` : Unit = {
+ def `filter `: Unit = {
val g: AnyGraph[Int, DiEdge[Int]] = factory(2 ~> 3, 3 ~> 1, 5)
g filter (_ > 1) should be(factory(2 ~> 3, 5))
g filter (_ < 2) should be(factory(1))
g filter (_ < 2) should be(factory(1))
g filter (_ >= 2) should be(factory(2 ~> 3, 5))
- g filter (edgeP = _.node1.outer == 2) should be(factory(1, 5, 2 ~> 3))
- g filter (nodeP = _ <= 3, edgeP = _ contains 2) should be(factory(1, 2 ~> 3))
+ g.filter(edgeP = _.node1.outer == 2) should be(factory(1, 5, 2 ~> 3))
+ g.filter(nodeP = _ <= 3, edgeP = _ contains 2) should be(factory(1, 2 ~> 3))
}
- def `match ` : Unit = {
+ def `match `: Unit = {
val di = 1 ~> 2
(di match { case DiEdge(src, _) => src }) should be(1)
(di match { case src ~> trg => src + trg }) should be(3)
@@ -411,7 +437,7 @@ private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
(unDi match { case n1 ~ n2 => n1 + n2 }) should be(3)
}
- def `foldLeft, foldLeftOuter ` : Unit = {
+ def `foldLeft, foldLeftOuter `: Unit = {
val g = factory(1 ~> 2, 2 ~> 3, 7)
val sumOfNodes = 13
diff --git a/core/src/test/scala/scalax/collection/EqualityHyperSpec.scala b/core/src/test/scala/scalax/collection/EqualityHyperSpec.scala
index 367a5623..27872dff 100644
--- a/core/src/test/scala/scalax/collection/EqualityHyperSpec.scala
+++ b/core/src/test/scala/scalax/collection/EqualityHyperSpec.scala
@@ -6,7 +6,7 @@ import scalax.collection.generic.AbstractDiHyperEdge
class EqualityHyperSpec extends RefSpec with Matchers {
- def `hyperedges, bag like ` : Unit = {
+ def `hyperedges, bag like `: Unit = {
import scalax.collection.hyperedges._
val nodes = List('A', 'B', 'C', 'C')
@@ -19,7 +19,7 @@ class EqualityHyperSpec extends RefSpec with Matchers {
hEdge.node(i) shouldBe nodes(i)
}
- def `hyperedges, ordered ` : Unit = {
+ def `hyperedges, ordered `: Unit = {
import scalax.collection.hyperedges.ordered._
val nodes = List('A', 'B', 'C', 'C')
diff --git a/core/src/test/scala/scalax/collection/EqualitySpec.scala b/core/src/test/scala/scalax/collection/EqualitySpec.scala
index df0d472c..6f1f97c5 100644
--- a/core/src/test/scala/scalax/collection/EqualitySpec.scala
+++ b/core/src/test/scala/scalax/collection/EqualitySpec.scala
@@ -20,12 +20,13 @@ private class Equality[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E
val factory: GenericGraphCoreFactory[CC]
) extends RefSpec
with Matchers {
+ info(factory.getClass.getPackage.toString)
private val seq_1_3 = Seq(1, 3)
private val gInt_1_3 = factory(seq_1_3.toOuterElems[DiEdge[Int]]: _*)
private val gString_A = factory("A")
- def `Eq ` : Unit = {
+ def `Graph equals`: Unit = {
factory[Int, Nothing]() shouldEqual factory[Int, DiEdge]()
gInt_1_3 shouldEqual factory(1, 3)
gString_A shouldEqual factory("A")
@@ -36,6 +37,20 @@ private class Equality[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E
gInt_1_3 shouldEqual immutable.Graph(1) + 3
}
+
+ def `Graph hashCode`(): Unit = {
+ factory(1).hashCode shouldBe factory(1).hashCode
+ factory(1).hashCode shouldNot be(factory(2).hashCode)
+
+ factory(1 ~> 2).hashCode shouldBe factory(1 ~> 2).hashCode
+ factory(1 ~> 2).hashCode shouldNot be(factory(2 ~> 1).hashCode)
+
+ factory(1 ~ 2).hashCode shouldBe factory(1 ~ 2).hashCode
+ factory(1 ~ 2).hashCode shouldNot be(factory(1 ~ 3).hashCode)
+
+ factory(1 ~ 2, 2 ~ 3).hashCode shouldBe factory(1 ~ 2, 2 ~ 3).hashCode
+ factory(1 ~ 2, 2 ~ 3).hashCode shouldNot be(factory(1 ~ 2, 3 ~ 3).hashCode)
+ }
}
private class EqualityMixed extends RefSpec with Matchers {
diff --git a/core/src/test/scala/scalax/collection/SetOpsSpec.scala b/core/src/test/scala/scalax/collection/SetOpsSpec.scala
index 916a4dae..313297ab 100644
--- a/core/src/test/scala/scalax/collection/SetOpsSpec.scala
+++ b/core/src/test/scala/scalax/collection/SetOpsSpec.scala
@@ -46,7 +46,7 @@ private class SetOps[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
with IntelliJ[CC]
with Visualizer {
- def `concat ` : Unit = {
+ def `concat `: Unit = {
factory(1 ~ 2).asAnyGraph concat List(1 ~ 2)
factory(1 ~ 2).asAnyGraph concat List(1 ~> 2)
factory(1 ~ 2).asAnyGraph ++ List(1 ~ 2)
@@ -58,13 +58,13 @@ private class SetOps[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E,
factory(1 ~ 2).asAnyGraph ++ (List('x'), List('a' ~ 'b'))
}
- def `union ` : Unit =
+ def `union `: Unit =
g union h shouldEqual Expected.g_union_h
- def `difference ` : Unit =
+ def `difference `: Unit =
g diff h shouldEqual Expected.g_diff_h
- def `intersection ` : Unit = {
+ def `intersection `: Unit = {
val expected = factory(3 ~ 5, 4)
withGraph(g intersect h)(_ shouldEqual expected)
withGraph(g & h)(_ shouldEqual expected)
@@ -81,17 +81,17 @@ private class SetOpsMutable extends RefSpec with Matchers with SetOpExamples[mut
private val iH = immutable.Graph.from(hEdges)
- def `unionInPlace ` : Unit = {
+ def `unionInPlace `: Unit = {
(g |= h) shouldEqual Expected.g_union_h
(g |= iH) shouldEqual Expected.g_union_h
}
- def `--= ` : Unit = {
+ def `--= `: Unit = {
(g --= h) shouldEqual Expected.g_diff_h
(g --= iH) shouldEqual Expected.g_diff_h
}
- def `&= ` : Unit = {
+ def `&= `: Unit = {
val expected = factory(3 ~ 5, 4)
(g &= h) shouldEqual expected
diff --git a/core/src/test/scala/scalax/collection/TopologicalSortSpec.scala b/core/src/test/scala/scalax/collection/TopologicalSortSpec.scala
index 225e2338..f7dd9a04 100644
--- a/core/src/test/scala/scalax/collection/TopologicalSortSpec.scala
+++ b/core/src/test/scala/scalax/collection/TopologicalSortSpec.scala
@@ -49,7 +49,7 @@ final private class TopologicalSort[G[N, E <: Edge[N]] <: AnyGraph[N, E] with Gr
def checkOrder(seq: OrderedInnerNodes, ignorePredecessorsOf: Option[graph.NodeT]): Unit =
seq.foldLeft(predecessors(ignorePredecessorsOf)) { (allowedPredecessors, innerNode) =>
- if (!innerNode.diPredecessors.forall(allowedPredecessors.contains))
+ if (!innerNode.inNeighbors.forall(allowedPredecessors.contains))
fail(s"$innerNode is misplaced in $seq")
allowedPredecessors + innerNode
}
diff --git a/core/src/test/scala/scalax/collection/mutable/ArraySetSpec.scala b/core/src/test/scala/scalax/collection/mutable/ArraySetSpec.scala
index 437ffbf9..7d501581 100644
--- a/core/src/test/scala/scalax/collection/mutable/ArraySetSpec.scala
+++ b/core/src/test/scala/scalax/collection/mutable/ArraySetSpec.scala
@@ -114,7 +114,7 @@ class ArraySetSpec extends RefSpec with Matchers {
sorted.range(-10, -4) shouldBe SortedArraySet.empty[Int]
}
- def `supports ++` : Unit = {
+ def `supports ++`: Unit = {
val a = ArraySet.empty[Int]
val b = ArraySet(1)
val c = ArraySet(2)
diff --git a/coreTestScala3/src/test/scala/WastelandSpec.scala b/coreTestScala3/src/test/scala/WastelandSpec.scala
deleted file mode 100644
index 9f74519c..00000000
--- a/coreTestScala3/src/test/scala/WastelandSpec.scala
+++ /dev/null
@@ -1,89 +0,0 @@
-import scala.annotation.tailrec
-
-import scalax.collection.OneOrMore
-import scalax.collection.generic.AbstractDiHyperEdge
-import scalax.collection.immutable.Graph
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-/** Directed hyperedge to represent nodes of the network https://adventofcode.com/2023/day/8.
- * Each line of the input file like `AAA = (BBB, CCC)` corresponds to one instance.
- */
-case class Fork(source: String, leftTarget: String, rightTarget: String)
- extends AbstractDiHyperEdge[String](
- sources = OneOrMore.one(source),
- targets = OneOrMore(leftTarget, rightTarget)
- )
-
-object Fork:
- def hook(source: String) = Fork(source, source, source)
-
-type Wasteland = Graph[String, Fork]
-
-enum Direction:
- case Left, Right
-
-/** The claim is not to be complete but to demonstrate the use-case specific graph walk.
- */
-def solve(wasteland: Wasteland, startingFork: String, instructions: Iterable[Direction]): Either[String, Int] =
- @tailrec def traverse(
- current: wasteland.NodeT,
- instructions: Iterator[Direction],
- count: Int
- ): Option[Int] =
- /** Uses inner node `fork` to navigate to the next node. Thus we can avoid repeated node lookup.
- */
- def target(fork: wasteland.NodeT, direction: Direction): Option[wasteland.NodeT] =
- fork.outgoing.headOption.map { e =>
- import Direction._
- direction match
- case Left => e.targets(0)
- case Right => e.targets(1)
- }
-
- instructions.nextOption match
- case Some(instruction) =>
- target(current, instruction) match
- case Some(fork) => traverse(fork, instructions, count + 1)
- case None => None
- case None => Some(count)
-
- wasteland.find(startingFork) match
- case Some(root) =>
- traverse(root, instructions.iterator, 0) match
- case Some(count) => Right(count)
- case None => Left("Node without successors.")
- case None =>
- Left(s"Fork '$startingFork' does not exist in wasteland.")
-
-final class WastelandSpec extends RefSpec with Matchers:
-
- /** @see diagram https://github.com/scala-graph/scala-graph/issues/300#issuecomment-1854583980
- */
- val wasteland: Wasteland = Graph.from(
- nodes = Nil,
- edges = List(
- Fork("A", "B", "C"),
- Fork("B", "D", "E"),
- Fork.hook("D"),
- Fork.hook("E"),
- Fork("C", "Z", "G"),
- Fork.hook("Z"),
- Fork.hook("G")
- )
- )
-
- def instructions(chars: String): Iterable[Direction] =
- import Direction._
- chars.flatMap {
- case 'L' | 'l' => Left :: Nil
- case 'R' | 'r' => Right :: Nil
- case _ => Nil
- }
-
- def `start at A`: Unit =
- solve(wasteland, "A", instructions("LR")) shouldBe Right(2)
-
- def `pass some non-existing fork`: Unit =
- solve(wasteland, "/", instructions("LR")).isLeft shouldBe true
diff --git a/coreTestScala3/src/test/scala/demo/EdgeADTDemo.scala b/coreTestScala3/src/test/scala/demo/EdgeADTDemo.scala
deleted file mode 100644
index 32f1c072..00000000
--- a/coreTestScala3/src/test/scala/demo/EdgeADTDemo.scala
+++ /dev/null
@@ -1,72 +0,0 @@
-package demo
-
-import scalax.collection.OneOrMore
-import scalax.collection.OneOrMore.one
-import scalax.collection.generic.{AbstractDiEdge, AbstractUnDiEdge, AnyEdge, MultiEdge}
-import scalax.collection.immutable.{Graph, TypedGraphFactory}
-
-/** Demonstrates a Graph with nodes representing Persons and edges representing Relations between Persons.
- */
-object EdgeADTDemo {
- // node type, which could also be an ADT
- case class Person(name: String)
-
- // edge ADT
- sealed trait Relation extends AnyEdge[Person]
-
- /** `abstract class`es facilitating more concise case class definitions.
- * `ExtendedKey` is needed to allow for multiple Relations between the same Persons.
- */
- sealed abstract protected class DiRelation(from: Person, to: Person, discriminator: AnyRef)
- extends AbstractDiEdge(from, to)
- with MultiEdge
- with Relation {
- def extendKeyBy: OneOrMore[Any] = one(discriminator)
- }
- sealed abstract protected class UnDiRelation(person_1: Person, person_2: Person, discriminator: AnyRef)
- extends AbstractUnDiEdge(person_1, person_2)
- with MultiEdge
- with Relation {
- def extendKeyBy: OneOrMore[Any] = one(discriminator)
- }
-
- final case class Parent(offspring: Person, parent: Person) extends DiRelation(offspring, parent, Parent)
- final case class Siblings(one: Person, another: Person) extends UnDiRelation(one, another, Siblings)
- final case class Friends(one: Person, another: Person) extends UnDiRelation(one, another, Friends)
-
- val kate = Person("Kate")
- val john = Person("John")
- val mike = Person("Mike")
-
- type People = Graph[Person, Relation]
- object People extends TypedGraphFactory[Person, Relation]
-
- // create empty Graph
- val empty = People.empty
-
- // populate Graph by Iterable[Relation]
- val people: People = People.from(
- List(
- Parent(kate, mike),
- Friends(kate, john),
- Siblings(kate, john)
- )
- )
-
- val edgesInWords =
- people.edges.outerIterator map {
- case Friends(Person(name_1), Person(name_2)) => s"$name_1 and $name_2 are friends"
- case Siblings(Person(name_1), Person(name_2)) => s"$name_1 and $name_2 are siblings"
- case Parent(Person(offspring), Person(parent)) => s"$parent is parent of $offspring"
- }
-
- // populate Graph by Iterable[People] and Iterable[Relation]
- val p1 = People.from(
- nodes = List(kate, john, mike),
- edges = List(Parent(kate, mike), Friends(kate, john))
- )
-
- // populate Graph by repeated Peoples and Relations
- import People.OuterImplicits.*
- val p2 = People(kate, Parent(kate, mike), Friends(kate, john), Siblings(kate, john))
-}
diff --git a/coreTestScala3/src/test/scala/demo/EditingDemoSpec.scala b/coreTestScala3/src/test/scala/demo/EditingDemoSpec.scala
deleted file mode 100644
index aa62dccf..00000000
--- a/coreTestScala3/src/test/scala/demo/EditingDemoSpec.scala
+++ /dev/null
@@ -1,147 +0,0 @@
-package demo
-
-import scala.collection.SortedSet
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.*
-import scalax.collection.{immutable, mutable}
-
-/** Includes the examples given on [[http://www.scala-graph.org/guides/core-operations.html
- * Graph Operations]].
- */
-final class EditingDemoSpec extends RefSpec with Matchers {
-
- object `demonstrating ` {
-
- def `Add and Subtract Elements`(): Unit = {
- import immutable.Graph
- val g = Graph(1, 2 ~ 3) // Graph(NodeSet(1, 2, 3), EdgeSet(2 ~ 3))
- g + 1 shouldBe g
- g + 0 shouldBe Graph(0, 1, 2 ~ 3)
- "g + 1.2" shouldNot compile // error: overloaded method...
- g + 0 ~ 1 shouldBe Graph(0, 1, 0 ~ 1, 2 ~ 3)
- g ++ List(1 ~ 2, 2 ~ 3) shouldBe Graph(1 ~ 2, 2 ~ 3)
- g ++ (0 :: Nil, 1 ~ 2 :: 2 ~ 3 :: Nil) shouldBe Graph(0, 1, 1 ~ 2, 2 ~ 3)
- g - 0 shouldBe g
- g - 1 shouldBe Graph(2 ~ 3)
- g - 2 shouldBe Graph(1, 3)
- g - 2 ~ 3 shouldBe Graph(1, 2, 3)
- g -- (2 :: Nil, 3 ~ 3 :: Nil) shouldBe Graph(1, 3)
- }
-
- def `Add Elements to mutable.Graph`(): Unit = {
- import mutable.Graph
- (Graph(1, 2 ~ 3) += 0) shouldBe Graph(0, 1, 2 ~ 3)
- (Graph[Int, AnyEdge](1, 2 ~ 3) += 3 ~> 1) shouldBe Graph[Int, AnyEdge](1, 2 ~ 3, 3 ~> 1)
- }
-
- def `equality ` : Unit = {
- val g = immutable.Graph(1 ~ 2)
- (g get 1).outer shouldBe 1
- g get 1 ~ 2 shouldBe 2 ~ 1
- g get 1 ~ 2 eq 2 ~ 1 shouldBe false
- g get 1 ~ 2 should not be 2 ~ 2
- }
-
- def `union, diff, intersect ` : Unit = {
- import immutable.Graph
- val g = Graph(1 ~ 2, 2 ~ 3, 2 ~ 4, 3 ~ 5, 4 ~ 5)
- val h = Graph(3 ~ 4, 3 ~ 5, 4 ~ 6, 5 ~ 6)
-
- g union h shouldBe Graph(1 ~ 2, 2 ~ 3, 2 ~ 4, 3 ~ 5, 4 ~ 5, 3 ~ 4, 4 ~ 6, 5 ~ 6)
- g diff h shouldBe Graph(1 ~ 2)
- g intersect h shouldBe Graph(4, 3 ~ 5)
- g & h shouldBe Graph(4, 3 ~ 5)
- }
-
- def `endpoints ` : Unit = {
- val uE = 3 ~ 4 // UnDiEdge[Int]
-
- uE.node1 * uE.node2 shouldBe 12
- uE.ends.iterator.product shouldBe 12
- (uE match {
- case n ~ m => n * m
- }) shouldBe 12
-
- val dE = 1 ~> 2 // DiEdge[Int]
- dE.source - dE.target shouldBe -1
- uE.arity == dE.arity shouldBe true
- (dE match {
- case s ~> t => s - t
- }) shouldBe -1
-
- import scalax.collection.hyperedges.*
- val hE = 1 ~~ 2 ~~ 11 ~~ 12 // HyperEdge[Int]
- hE.node(hE.arity - 1) shouldBe 12
- hE.ends.iterator.sum shouldBe 26
- }
-
- def `neighbors ` : Unit = {
- import immutable.Graph
- val g = Graph[Int, AnyEdge](0, 1 ~ 3, 3 ~> 2)
-
- def n(outer: Int): g.NodeT = g get outer
-
- def e(outer: AnyEdge[Int]): g.EdgeT = g get outer
-
- n(0).diSuccessors shouldBe Set.empty[g.NodeT]
- n(2).diSuccessors.isEmpty shouldBe true
- n(3).diSuccessors shouldBe Set(n(1), n(2))
- n(3).diPredecessors shouldBe Set(n(1))
- n(2).incoming shouldBe Set(e(3 ~> 2))
- n(3) findOutgoingTo n(2) shouldBe Some(e(3 ~> 2))
- }
-
- def `querying ` : Unit = {
- import immutable.Graph
- val g = Graph[Int, AnyEdge](2 ~> 3, 3 ~ 1, 5)
-
- def n(outer: Int): g.NodeT = g get outer
-
- g.nodes filter (_ > 2) shouldBe Set(n(5), n(3))
- g.nodes filter (_.degree > 1) shouldBe Set(n(3))
- g.edges filter (_ contains 4) shouldBe Symbol("empty")
- }
-
- def `measuring ` : Unit = {
- import immutable.Graph
- import scalax.collection.edges.labeled.*
- val g = Graph[Int, AnyEdge](
- 1 ~ 2 % 4,
- 2 ~ 3 % 2,
- 1 ~> 3 % 5,
- 1 ~ 5 % 3,
- 3 ~ 5 % 2,
- 3 ~ 4 % 1,
- 4 ~> 4 % 1,
- 4 ~> 5 % 0
- )
- g.order shouldBe 5
- g.size shouldBe 8
- g.totalDegree shouldBe 16
- g.degreeSet shouldBe SortedSet(4, 3, 2)
- g.degreeNodeSeq(g.InDegree) shouldBe List((4, 3), (3, 5), (2, 1), (2, 2), (2, 4))
- g.degreeNodesMap should contain only (2 -> Set(2), 3 -> Set(5, 1), 4 -> Set(3, 4))
- g.degreeNodesMap(degreeFilter = _ > 3) should contain only (4 -> Set(3, 4))
- }
-
- def `classifying ` : Unit = {
- import immutable.Graph
- val g = Graph(1, 2 ~> 3)
- g.isConnected shouldBe false
- (g + 2 ~> 1).isConnected shouldBe true
- (g get 2).findConnected(_.outer == 3) shouldBe Some(3)
- g.isCyclic shouldBe false
- (g + 3 ~> 2).isCyclic shouldBe true
- g.isComplete shouldBe false
- (g ++ List(1 ~> 2, 1 ~> 3, 2 ~> 1, 3 ~> 1, 3 ~> 2)).isComplete shouldBe true
- g.isDirected shouldBe true
- g.isHyper shouldBe false
- g.isMulti shouldBe false
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/demo/EnrichingDemoSpec.scala b/coreTestScala3/src/test/scala/demo/EnrichingDemoSpec.scala
deleted file mode 100644
index bdd622e0..00000000
--- a/coreTestScala3/src/test/scala/demo/EnrichingDemoSpec.scala
+++ /dev/null
@@ -1,43 +0,0 @@
-package demo
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.*
-import scalax.collection.immutable.Graph
-
-class EnrichingDemoSpec extends RefSpec with Matchers {
-
- object `demonstrating how to` {
-
- def `enrich graphs`: Unit = {
- implicit class ExtGraph[N, E <: Edge[N]](protected val g: Graph[N, E]) {
- def foo: String = "bar"
- }
- Graph(1 ~ 2).foo shouldBe "bar"
- }
-
- def `enrich directed graphs`: Unit = {
- implicit class ExtGraph[N, E <: AnyDiEdge[N]](protected val g: Graph[N, E]) {
- def foo: String = "bar"
- }
- Graph(1 ~> 2).foo shouldBe "bar"
- "Graph(1 ~ 2).foo" shouldNot typeCheck
- }
-
- def `enrich inner nodes`: Unit = {
- // works for any Graph due to projection type
- implicit class ExtInnerNode[N, E <: Edge[N]](node: Graph[N, E]#NodeT) {
- def outOverInDegree: Int = node.outDegree - node.inDegree
- }
-
- Graph(1 ~> 2).nodes foreach {
- case n if n.outer == 1 => n.outOverInDegree shouldBe 1
- case n if n.outer == 2 => n.outOverInDegree shouldBe -1
- case _ => fail()
- }
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/demo/FlightDemoSpec.scala b/coreTestScala3/src/test/scala/demo/FlightDemoSpec.scala
deleted file mode 100644
index f1a1d3d3..00000000
--- a/coreTestScala3/src/test/scala/demo/FlightDemoSpec.scala
+++ /dev/null
@@ -1,97 +0,0 @@
-package demo
-
-import java.time.DayOfWeek.*
-import java.time.{DayOfWeek, LocalTime}
-
-import scala.concurrent.duration.*
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.edges.*
-
-class FlightDemoSpec extends RefSpec with Matchers {
-
- object `demonstrating how to` {
-
- def `work with the Flight typed edge`: Unit = {
- import FlightDemoSpec.*
- import scalax.collection.labeled.aviation.*
-
- def expectedStringRepresentation(
- from: Airport,
- to: Airport,
- flightNo: String,
- times: List[(DayOfWeek, LocalTime)],
- duration: FiniteDuration
- ) =
- s"$from ~> $to :++ ($flightNo, $times, $duration)"
-
- /* look up a node and examine outgoing edges by using the prefix extractor
- */
- g.find(hamburg).map { ham =>
- ham.diSuccessors shouldBe Set(amsterdam, london)
- ham.outgoing.map { case g.InnerEdge(_, flight @ Flight(from, to, flightNo, times, duration)) =>
- flight.toString shouldBe expectedStringRepresentation(from, to, flightNo, times, duration)
- }
- }
-
- /* same but using the infix extractors `:~>` and `++:` that were added optionally
- */
- g.find(hamburg).map { ham =>
- ham.diSuccessors shouldBe Set(amsterdam, london)
- ham.outgoing.map { case g.InnerEdge(_, flight @ from :~> to ++: ((flightNo, times, duration))) =>
- flight.toString shouldBe expectedStringRepresentation(from, to, flightNo, times, duration)
- }
- }
- }
- }
-}
-
-object FlightDemoSpec {
- import scalax.collection.labeled.aviation.*
- import scalax.collection.labeled.aviation.immutable.*
- import scalax.collection.labeled.aviation.immutable.FlightGraph.OuterImplicits.*
-
- val amsterdam = Airport("AMS")
- val hamburg = Airport("HAM")
- val frankfurt = Airport("FRA")
- val newYork = Airport("JFK")
- val london = Airport("LHR")
- val mexico = Airport("MEX")
-
- /* construct the Graph by supplying edges
- */
- val g = FlightGraph(
- hamburg ~> amsterdam :++ (
- "KL 1776",
- List(
- MONDAY -> LocalTime.of(17, 50),
- SATURDAY -> LocalTime.of(17, 40)
- ),
- 50.minutes
- ),
- hamburg ~> london :++ (
- "BA 967",
- List(
- TUESDAY -> LocalTime.of(8, 20),
- SATURDAY -> LocalTime.of(8, 20)
- ),
- 1.hour + 10.minutes
- ),
- london ~> newYork :++ (
- "UA 921",
- List(
- THURSDAY -> LocalTime.of(18, 0)
- ),
- 5.hours + 40.minutes
- ),
- newYork ~> mexico :++ (
- "VB 101",
- List(
- TUESDAY -> LocalTime.of(14, 10),
- SUNDAY -> LocalTime.of(14, 20)
- ),
- 4.hours + 25.minutes
- )
- )
-}
diff --git a/coreTestScala3/src/test/scala/demo/GraphTestDemo.scala b/coreTestScala3/src/test/scala/demo/GraphTestDemo.scala
deleted file mode 100644
index b3b94de9..00000000
--- a/coreTestScala3/src/test/scala/demo/GraphTestDemo.scala
+++ /dev/null
@@ -1,181 +0,0 @@
-package demo
-
-import scalax.collection.edges.*
-import scalax.collection.mutable.Graph
-
-/** Includes the examples given on [[http://www.scala-graph.org/guides/test.html
- * Test Utilities]].
- */
-object GraphTestDemo extends App {
-
- import scalax.collection.generator.*
-
- object PersonData {
- val firstNames = Vector("Alen", "Alice", "Bob", "Jack", "Jim", "Joe", "Kate", "Leo", "Tim", "Tom")
- val firstNamesSize = firstNames.size
-
- val surnames = Vector("Bell", "Brown", "Clark", "Cox", "King", "Lee", "Moore", "Ross", "Smith", "Wong")
- val surnamesSize = surnames.size
-
- def order = firstNamesSize * surnamesSize / 10
- def degrees = new NodeDegreeRange(2, order / 2)
- val maxYearOfBirth = 2010
- }
-
- object RG {
- // working with random graph generators -----------------------------------------------
-
- // obtaining generators for graphs with predefined metrics
- val predefined = RandomGraph.tinyConnectedIntDi(Graph)
- val tinyGraph = predefined.draw // Graph[Int,DiEdge]
-
- // setting individual graph metrics while keeping metrics constraints in mind
- object sparse_1000_Int extends RandomGraph.IntFactory {
- val order = 1000
- val nodeDegrees = NodeDegreeRange(1, 10)
- override def connected = false
- }
- val randomSparse = RandomGraph.fromMetrics[Int, UnDiEdge[Int], Graph](Graph, sparse_1000_Int, Set(UnDiEdge))
- val sparseGraph = randomSparse.draw // Graph[Int,UnDiEdge]
-
- // TODO obtain generators for graphs with typed edges
-
- case class Person(name: String, yearOfBirth: Int)
- object Person {
- import PersonData.*
- private val r = new scala.util.Random
-
- def drawName: String = {
- def drawFirstName: String = firstNames(r.nextInt(firstNamesSize))
- def drawSurame: String = surnames(r.nextInt(surnamesSize))
-
- s"$drawFirstName, $drawSurame"
- }
-
- def drawYearOfBirth = maxYearOfBirth - r.nextInt(100)
- }
-
- val randomMixedGraph =
- RandomGraph.fromMetrics[Person, UnDiEdge[Person], Graph](
- Graph,
- new RandomGraph.Metrics[Person] {
- val order = PersonData.order
- val nodeDegrees = PersonData.degrees
- def nodeGen: Person = Person(Person.drawName, Person.drawYearOfBirth)
- },
- Set(UnDiEdge) // TODO LDiEdge
- )
- val mixedGraph = randomMixedGraph.draw
- /*
- println(mixedGraph)
- Graph(
- Person(Alice, Smith,1967),
- Person(Kate, Ross,1921),
- Person(Leo, Bell,2008),
- Person(Leo, Smith,1983),
- ...,
- Person(Alice, Smith,1967)~>Person(Kate, Ross,1921) 'C,
- Person(Leo, Bell,2008)~Person(Leo, Smith,1983),
- ...
- )
- */
- }
-
- object GG {
- import org.scalacheck.{Arbitrary, Gen}
- import Arbitrary.arbitrary
- import org.scalacheck.Prop.forAll
-
- // working with org.scalacheck.Arbitrary graphs ---------------------------------------
-
- // obtaining Arbitrary instances for graphs with predefined metrics
- type IntDiGraph = Graph[Int, DiEdge[Int]]
- implicit val arbitraryTinyGraph: Arbitrary[Graph[Int, DiEdge[Int]]] = GraphGen.tinyConnectedIntDi[Graph](Graph)
-
- val properTiny = forAll(arbitrary[IntDiGraph]) { (g: IntDiGraph) =>
- g.order == GraphGen.TinyInt.order
- }
- properTiny.check()
-
- // setting individual graph metrics for Arbitrary instances
- // while keeping metrics constraints in mind
- object Sparse_1000_Int extends GraphGen.Metrics[Int] {
- val order = 1000
- val nodeDegrees = NodeDegreeRange(1, 10)
- def nodeGen: Gen[Int] = Gen.choose(0, 10 * order)
- override def connected = false
- }
-
- type IntUnDiGraph = Graph[Int, UnDiEdge[Int]]
- implicit val arbitrarySparseGraph: Arbitrary[Graph[Int, UnDiEdge[Int]]] = Arbitrary {
- GraphGen.fromMetrics[Int, UnDiEdge[Int], Graph](Graph, Sparse_1000_Int, Set(UnDiEdge)).apply
- }
-
- val properSparse = forAll(arbitrary[IntUnDiGraph]) { (g: IntUnDiGraph) =>
- g.order == Sparse_1000_Int.order
- }
- properSparse.check()
-
- // TODO obtain Arbitrary instances to generate graphs with typed edges
-
- case class Person(name: String, yearOfBirth: Int)
- object Person {
- import PersonData.*
-
- def firstNameGen: Gen[String] = Gen.oneOf(firstNames)
- def surameGen: Gen[String] = Gen.oneOf(surnames)
-
- def nameGen: Gen[String] = Gen.resultOf((firstName: String, surname: String) => s"$firstName, $surname")(
- Arbitrary(firstNameGen),
- Arbitrary(surameGen)
- )
-
- def yearOfBirthGen: Gen[Int] = Gen.choose(maxYearOfBirth - 100, maxYearOfBirth)
- }
-
- object MixedMetrics extends GraphGen.Metrics[Person] {
- val order = PersonData.order
- val nodeDegrees = PersonData.degrees
- def nodeGen: Gen[Person] = Gen.resultOf((name: String, year: Int) => Person(name, year))(
- Arbitrary(Person.nameGen),
- Arbitrary(Person.yearOfBirthGen)
- )
- }
-
- type Mixed = Graph[Person, UnDiEdge[Person]]
- implicit val arbitraryMixedGraph: Arbitrary[Graph[Person, UnDiEdge[Person]]] = Arbitrary {
- GraphGen
- .fromMetrics[Person, UnDiEdge[Person], Graph](Graph, MixedMetrics, Set(UnDiEdge /*, TODO LDiEdge*/ ))
- .apply
- }
-
- val properMixedGraph = forAll(arbitrary[Mixed]) { (g: Mixed) =>
- g.order == MixedMetrics.order
- }
- properMixedGraph.check()
- // println(arbitraryMixedGraph.arbitrary.sample)
-
- // Integrating with ScalaTest, limiting the minimum # of successful tests
- import org.scalatest.matchers.should.Matchers
- import org.scalatest.refspec.RefSpec
- import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-
- class TGraphGenTest extends RefSpec with Matchers with ScalaCheckPropertyChecks {
-
- implicit val config: PropertyCheckConfiguration =
- PropertyCheckConfiguration(minSuccessful = 5, maxDiscardedFactor = 1.0)
-
- object `generated Tiny graph` {
- implicit val arbitraryTinyGraph: Arbitrary[Graph[Int, DiEdge[Int]]] = GraphGen.tinyConnectedIntDi[Graph](Graph)
-
- def `should conform to tiny metrics`: Unit =
- forAll(arbitrary[IntDiGraph]) { (g: IntDiGraph) =>
- g.order should equal(GraphGen.TinyInt.order)
- }
- }
- }
- }
-
- RG
- GG
-}
diff --git a/coreTestScala3/src/test/scala/demo/HyperADTDemo.scala b/coreTestScala3/src/test/scala/demo/HyperADTDemo.scala
deleted file mode 100644
index 160d32e8..00000000
--- a/coreTestScala3/src/test/scala/demo/HyperADTDemo.scala
+++ /dev/null
@@ -1,155 +0,0 @@
-package demo
-
-import scala.util.chaining.*
-
-import scalax.collection.OneOrMore
-import scalax.collection.OneOrMore.one
-import scalax.collection.generic.*
-import scalax.collection.immutable.{Graph, TypedGraphFactory}
-
-/** Demonstrates a largely typesafe Hypergraph for SQL schemas with
- * - `Node`'s representing tables and columns and
- * - `Connection`s representing
- * - table-column relationships and
- * - foreign keys.
- */
-object HyperADTDemo extends App {
- sealed trait DataType
- case object StringType extends DataType
- case object NumericType extends DataType
-
- sealed trait Node
- case class Table(name: String) extends Node
- case class Column(table: Table, name: String, `type`: DataType) extends Node
-
- sealed trait Connection extends AnyDiHyperEdge[Node]
-
- /** Ensures by type safety that
- * - columns cannot be connected to a table multiple times
- * - primary key columns are an ordered subset of the table's columns
- * - foreign key columns are an ordered subset of the table's columns
- * - foreign keys are connected with the primary key of the child table
- * TODO try to also ensure that
- * - only columns of the same table definition may be added to indexes/foreign keys
- * - column names are unique with respect to the table
- * - sets are not empty whenever appropriate
- * - the # of foreign key columns must correspond to the # of primary key columns in the child table
- * - `CS` of ForeignKey is different from `S`
- */
- final case class TableContext[S <: Set[Column] with Singleton](
- table: Table,
- columns: Superset[Column, S],
- primaryKeyColumns: OrderedSubset[Column, S]
- ) { outer =>
-
- case class TableColumn private[TableContext] (table: outer.table.type, column: Column)
- extends AbstractDiEdge(table: Table, column)
- with DiEdgeToString
- with Connection
-
- protected case class PrimaryKey private (table: outer.table.type, columns: OrderedSubset[Column, S])
- extends AbstractDiHyperEdge(one(table: Table), OneOrMore.fromUnsafe(columns))
- with MultiEdge
- with Connection {
- def extendKeyBy: OneOrMore[Any] = PrimaryKey.edgeKeyExtension
- }
-
- case object PrimaryKey {
- def apply(): PrimaryKey = PrimaryKey(table, primaryKeyColumns)
- private val edgeKeyExtension = one(PrimaryKey.toString)
- }
-
- def columnEdges: List[TableColumn] =
- columns.set pipe (set =>
- set.iterator.map { column =>
- TableColumn(table, column)
- }.toList
- )
-
- def primaryKeyEdge: PrimaryKey = PrimaryKey()
-
- def requiredEdges: List[Connection] = primaryKeyEdge +: columnEdges
-
- case class Index[CS <: Set[Column] with Singleton] private (
- table: outer.table.type,
- columns: OrderedSubset[Column, S]
- ) extends AbstractDiHyperEdge(one(table: Table), OneOrMore.fromUnsafe(columns))
- with MultiEdge
- with Connection {
- def extendKeyBy: OneOrMore[Any] = Index.edgeKeyExtension
- }
-
- case object Index {
- def apply[CS <: Set[Column] with Singleton](
- columns: OrderedSubset[Column, S]
- ): Index[CS] =
- Index(table, columns)
-
- private val edgeKeyExtension = one(this.toString)
- }
-
- case class ForeignKey[CS <: Set[Column] with Singleton] private (
- table: outer.table.type,
- columns: OrderedSubset[Column, S],
- childTable: TableContext[CS]
- ) extends AbstractDiHyperEdge(one(table: Table), OneOrMore.fromUnsafe(columns))
- with MultiEdge
- with Connection {
- def extendKeyBy: OneOrMore[Any] = ForeignKey.edgeKeyExtension
- }
-
- case object ForeignKey {
- def apply[CS <: Set[Column] with Singleton](
- columns: OrderedSubset[Column, S],
- childTable: TableContext[CS]
- ): ForeignKey[CS] =
- ForeignKey(table, columns, childTable)
-
- private val edgeKeyExtension = one(this.toString)
- }
- }
-
- abstract class TableDef(val tableName: String) {
- final val table = Table(tableName)
- val columns: Set[Column]
- val primaryKeyColumns: OrderedSubset[Column, columns.type]
-
- final def column(name: String, `type`: DataType): Column = Column(table, name, `type`)
- final lazy val context: TableContext[columns.type] = TableContext(table, Superset(columns), primaryKeyColumns)
- final def requiredEdges: List[Connection] = context.requiredEdges
-
- final def index[C <: Set[Column] with Singleton](columns: Column*) =
- context.Index(OrderedSubset(this.columns)(columns: _*))
-
- final def foreignKey[C <: Set[Column] with Singleton](childTable: TableContext[C])(columns: Column*) =
- context.ForeignKey(OrderedSubset(this.columns)(columns: _*), childTable)
- }
-
- object Address extends TableDef("address") {
- val name = column("name", StringType)
- val countryCode = column("countryCode", StringType)
- val columns = Set(name, countryCode)
- val primaryKeyColumns = OrderedSubset(columns)(name)
- }
-
- object Country extends TableDef("country") {
- val name = column("name", StringType)
- val countryCode = column("countryCode", StringType)
- val columns = Set(name, countryCode)
- val primaryKeyColumns = OrderedSubset(columns)(countryCode)
- }
-
- type SqlSchema = Graph[Node, Connection]
- object SqlSchema extends TypedGraphFactory[Node, Connection]
-
- val schema = SqlSchema.from(
- Address.requiredEdges
- ++: Country.requiredEdges
- ++: List(
- Address.foreignKey(childTable = Country.context)(Address.countryCode),
- Country.index(Country.countryCode)
- )
- )
-
- // TODO some tasks based on `schema`
-}
diff --git a/coreTestScala3/src/test/scala/demo/InspectingDemoSpec.scala b/coreTestScala3/src/test/scala/demo/InspectingDemoSpec.scala
deleted file mode 100644
index d7f50dd6..00000000
--- a/coreTestScala3/src/test/scala/demo/InspectingDemoSpec.scala
+++ /dev/null
@@ -1,146 +0,0 @@
-package demo
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.OuterImplicits.*
-import scalax.collection.{OneOrMore, Several}
-import scalax.collection.edges.*
-import scalax.collection.generic.AnyEdge
-import scalax.collection.hyperedges.*
-import scalax.collection.mutable.Graph
-
-class InspectingDemoSpec extends RefSpec with Matchers {
-
- object `demonstrating ` {
-
- def `Iterate over Elements`(): Unit = {
- val g = Graph(2 ~ 3, 3 ~ 1)
- g.toString // "Graph(NodeSet(1, 2, 3), EdgeSet(2 ~ 3, 3 ~ 1))"
- g.nodes mkString ", " // "1, 2, 3"
- g.edges mkString ", " // "2 ~ 3, 3 ~ 1"
- g.outerIterator
- .map {
- case g.OuterNode(n) => n.toString
- case g.OuterEdge(e) => e.toString
- }
- .mkString(", ") // 1, 2, 3, 2 ~ 3, 3 ~ 1
- }
-
- def `Look up Nodes and Edges`(): Unit = {
- val g = Graph(1 ~ 2)
- g find 1 // Option[g.NodeT] = Some(1)
- g find 3 // Option[g.NodeT] = None
- g get 1 // g.NodeT = 1
- a[NoSuchElementException] should be thrownBy {
- g get 3
- } // NoSuchElementException
- g find 1 ~ 2 // Option[g.EdgeT] = Some(1 ~ 2)
- g.nodes find (_.outer == 1) // Option[g.NodeT] = 1
- g addAndGet 3 // g.NodeT = 3
- }
-
- def `Inspect Edge Ends`(): Unit = {
- val unDiEdge = 3 ~ 4 // UnDiEdge[Int]
- unDiEdge.node1 * unDiEdge.node2 // Int = 12
- unDiEdge.ends.iterator.product // Int = 12
- unDiEdge match {
- case n ~ m => n * m // Int = 12
- }
-
- val diEdge = 1 ~> 2 // DiEdge[Int]
- unDiEdge.arity == diEdge.arity // true
- diEdge.source - diEdge.target // Int = -1
- diEdge match {
- case s ~> t => s - t // Int = -1
- }
-
- val hyperEdge = 1 ~~ 2 ~~ 11 ~~ 12 // HyperEdge[Int]
- hyperEdge.ends.get(hyperEdge.arity - 1) // Int = 12
- hyperEdge.ends.iterator.sum // Int = 26
- hyperEdge match {
- case ~~(Several.Seq(n1, n2, _*)) => n1 - n2 // Int = -1
- }
-
- val diHyperEdge = OneOrMore(1, 2) ~~> OneOrMore(5, 6)
- diHyperEdge.sources.iterator.sum // Int = 3
- diHyperEdge.targets.iterator.sum // Int = 11
- diHyperEdge match {
- case OneOrMore.Seq(_, s2, _*) ~~> OneOrMore(t1, _) => s2 * t1 // Int = 10
- }
- }
-
- def `Inspect Neighbors and Incident Edges`(): Unit = {
- val g = Graph[Int, AnyEdge](0, 1 ~ 3, 3 ~> 2)
-
- def n(outer: Int): g.NodeT = g get outer
-
- n(0).diSuccessors // Set[g.NodeT] = Set()
- n(2).diSuccessors // Set[g.NodeT] = Set()
- n(3).diSuccessors // Set[g.NodeT] = Set(1, 2)
- n(3).diPredecessors // Set[g.NodeT] = Set(1)
- n(2).incoming // Set[g.EdgeT] = Set(3 ~> 2)
- }
- }
-
- def `Query the Node or Edge Set`(): Unit = {
- val g = Graph[Int, AnyEdge](2 ~> 3, 3 ~ 1, 5)
-
- g.nodes.filter(_.outer > 2) // Set[g.NodeT] = Set(3, 5)
- g.nodes.filter(_.degree > 1) // Set[g.NodeT] = Set(3)
- g.edges.filter(_.adjacents.isEmpty) // Set[g.EdgeT] = Set()
-
- g.outerIterator
- .filter {
- case g.OuterNode(n) => n > 1
- case g.OuterEdge(AnyEdge(n1, n2)) => n1 > 1 && n2 > 1
- }
- .map {
- case g.OuterNode(n) => n
- case g.OuterEdge(e) => e
- }
- .toList // List[Any] = List(2, 3, 5, 2 ~> 3)
-
- g.iterator.filter {
- case g.InnerNode(innerN, _) => innerN.degree > 1
- case g.InnerEdge(_, outerE) => outerE.isDirected
- }.mkString // String = 3, 2 ~> 3
- }
-
- def `Compute Union, Difference and Intersection`(): Unit = {
- val g = Graph(1 ~ 2, 2 ~ 3, 2 ~ 4, 3 ~ 5, 4 ~ 5)
- val h = Graph(3 ~ 4, 3 ~ 5, 4 ~ 6, 5 ~ 6)
- g union h // Graph(1 ~ 2, 2 ~ 3, 2 ~ 4, 3 ~ 5, 4 ~ 5, 3 ~ 4, 4 ~ 6, 5 ~ 6)
- g diff h // Graph(1 ~ 2)
- g intersect h // Graph(4, 3 ~ 5)
- g &= h // Graph(4, 3 ~ 5), mutated instance
- }
-
- def `Measure your Graph`(): Unit = {
- val g = Graph[Int, AnyEdge](1 ~ 2, 2 ~ 3, 1 ~> 3, 1 ~ 5, 3 ~ 5, 3 ~ 4, 4 ~> 4, 4 ~> 5)
-
- g.order // Int = 5
- g.size // Int = 8
- g.elementCount // Int = 13
- g.totalDegree // Int = 16
- g.degreeSet // TreeSet(4, 3, 2)
- g.degreeNodeSeq(g.InDegree) // List((4, 3), (3, 5), (2, 1), (2, 2), (2, 4))
- g.degreeNodesMap // Map(2->Set(2), 3->Set(5, 1), 4->Set(3, 4))
- g.degreeNodesMap(degreeFilter = _ > 3) // Map(4 -> Set(3, 4))
- }
-
- def `Classify your Graph`(): Unit = {
- val g = Graph(1, 2 ~> 3)
-
- g.isConnected // false
- (g addOne 2 ~> 1).isConnected // true
- (g get 2).findConnected(_.outer == 3) // Some(3)
- g.isCyclic // false
- (g addOne 3 ~> 2).isCyclic // true
- g.isComplete // false
- (g ++ List(1 ~> 2, 1 ~> 3, 2 ~> 1, 3 ~> 1, 3 ~> 2)).isComplete // true
- g.isDirected // true
- g.isHyper // false
- g.isMulti // false
- }
-}
diff --git a/coreTestScala3/src/test/scala/demo/TransformingDemoSpec.scala b/coreTestScala3/src/test/scala/demo/TransformingDemoSpec.scala
deleted file mode 100644
index 50896dac..00000000
--- a/coreTestScala3/src/test/scala/demo/TransformingDemoSpec.scala
+++ /dev/null
@@ -1,131 +0,0 @@
-package demo
-
-import scala.concurrent.duration.*
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.AnyEdge
-import scalax.collection.immutable.Graph
-
-final class TransformingDemoSpec extends RefSpec with Matchers {
-
- object `demonstrating ` {
- def `Filter your graph`(): Unit = {
- val g = Graph[Int, AnyEdge](2 ~> 3, 3 ~ 1, 5)
-
- g filter (nodeP = _ >= 2) should ===(Graph(2, 3, 5, 2 ~> 3))
- g filter (edgeP = _.isDirected) should ===(Graph(1, 5, 2, 3, 2 ~> 3))
- g filter (nodeP = _ >= 2, edgeP = _.isUndirected) should ===(Graph(2, 3, 5))
- }
-
- def `Fold your graph`(): Unit = {
- val g = Graph(1 ~> 2, 1 ~> 3, 4)
-
- g.foldLeft(Graph.empty[Int, DiEdge[Int]])(
- opNode = {
- case (cum, g.InnerNode(n, _)) if n.isIsolated => cum + n
- case (cum, _) => cum
- },
- opEdge = {
- case (cum, g.InnerEdge(e, _)) if cum.size % 2 == 0 => cum + e
- case (cum, _) => cum
- }
- ) should (be(Graph(4, 1 ~> 3)) or be(Graph(4, 1 ~> 2))) // Graph(NodeSet(1, 2, 4), EdgeSet(1 ~> 2))
- }
-
- def `Map your generic graph`(): Unit =
- Graph(1 ~ 2).map(
- fNode = _.outer + 1,
- fEdge = (n1: Int, n2: Int) => n1 ~> n2
- ) shouldEqual Graph(2 ~> 3)
-
- def `Flat-map your generic graph`: Unit =
- Graph(1 ~ 2).flatMap(
- fNode = _.outer + 1 :: Nil,
- fEdge = (n1s: Seq[Int], n2s: Seq[Int]) =>
- (n1s, n2s) match {
- case (Seq(n1, _*), Seq(n2, _*)) => List(n1 ~> n2, n2 ~> n1)
- }
- ) shouldEqual Graph(2 ~> 3, 3 ~> 2)
-
- def `Map your typed graph`(): Unit = {
- import FlightDemoSpec.*
- import scalax.collection.labeled.aviation.*
-
- val hamReplacedByFra =
- g.mapBound((airport: g.NodeT) => if (airport == hamburg) frankfurt else airport)
-
- hamReplacedByFra should have size g.size
- hamReplacedByFra.nodes should not contain hamburg
-
- def hamInvolved(flight: Flight): Boolean =
- flight.departure == hamburg ||
- flight.destination == hamburg
- def replaced(flight: Flight) = flight.copy(
- departure = if (flight.departure == hamburg) frankfurt else flight.departure,
- destination = if (flight.destination == hamburg) frankfurt else flight.destination
- )
- g.edges.outerIterable.filter(hamInvolved) foreach { originalFlight =>
- hamReplacedByFra.edges.outerIterable should contain(replaced(originalFlight))
- }
-
- g.map(
- fNode = (airport: g.NodeT) => airport.outer.toString,
- fEdge = (from: String, to: String) => DiEdge(from, to)
- ) shouldEqual Graph.from(
- g.edges.outerIterable.map(flight => DiEdge(flight.departure.toString, flight.destination.toString))
- )
- }
-
- def `Flat-map your typed graph`(): Unit = {
- import FlightDemoSpec.*
- import scalax.collection.labeled.aviation.*
-
- def ham(flight: Flight): Boolean = flight.departure == hamburg || flight.destination == hamburg
- def shortHam(flight: Flight): Boolean = ham(flight) && flight.duration < 1.hour
-
- val shortHamReplacedByFra =
- g.flatMapBound(
- fNode = (airport: g.NodeT) => (if (airport == hamburg) frankfurt else airport.outer) :: Nil,
- fEdge = (edge: g.EdgeT, newDepartures: Seq[Airport], newDestinations: Seq[Airport]) => {
- val outer = edge.outer
- if (shortHam(outer))
- outer.copy(departure = newDepartures.head, destination = newDestinations.head) :: Nil
- else if (ham(outer)) Nil
- else outer :: Nil
- }
- )
-
- val longHamCount = g.edges.outerIterable.count(f => ham(f) && !shortHam(f))
- shortHamReplacedByFra should have size g.size - longHamCount
- shortHamReplacedByFra.nodes should not contain hamburg
-
- def replaced(flight: Flight) = flight.copy(
- departure = if (flight.departure == hamburg) frankfurt else flight.departure,
- destination = if (flight.destination == hamburg) frankfurt else flight.destination
- )
- g.edges.outerIterable.filter(shortHam) foreach { originalFlight =>
- shortHamReplacedByFra.edges.outerIterable should contain(replaced(originalFlight))
- }
-
- g.flatMap(
- fNode = (airport: g.NodeT) => {
- def existing = airport.outer.toString
- if (airport == hamburg) existing :: frankfurt.toString :: Nil
- else existing :: Nil
- },
- fEdge = (edge: g.EdgeT, from: Seq[String], to: Seq[String]) => {
- val outer = edge.outer
- if (shortHam(outer)) {
- def replaced(a: Airport) = (if (a == hamburg) frankfurt else a).toString
- DiEdge(replaced(outer.departure), replaced(outer.destination)) :: Nil
- } else if (ham(outer)) Nil
- else DiEdge(from.head, to.head) :: Nil
- }
- )
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/demo/TraversingDemoSpec.scala b/coreTestScala3/src/test/scala/demo/TraversingDemoSpec.scala
deleted file mode 100644
index f48f1336..00000000
--- a/coreTestScala3/src/test/scala/demo/TraversingDemoSpec.scala
+++ /dev/null
@@ -1,206 +0,0 @@
-package demo
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.{OuterElem, OuterNode}
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.edges.labeled.*
-import scalax.collection.generic.AnyEdge
-import scalax.collection.immutable.Graph
-
-/** Includes the examples given on [[http://www.scala-graph.org/guides/core-traversing.html
- * Traversing Graphs]].
- */
-final class TraversingDemoSpec extends RefSpec with Matchers {
-
- type Outer = OuterElem[Int, AnyEdge[Int]]
- val g = Graph[Int, AnyEdge](1 ~ 2 % 4, 2 ~ 3 % 2, 1 ~> 3 % 5, 1 ~ 5 % 3, 3 ~ 5 % 2, 3 ~ 4 % 1, 4 ~> 4 % 1, 4 ~> 5 % 0)
- def n(outer: Int): g.NodeT = g get outer
-
- object `demonstrating ` {
- def `traversals for a result`: Unit = {
- def validatePath(p: g.Path, sample: List[Outer]): Unit = {
- def toN(p: Outer): Int = p match {
- case OuterNode(n) => n
- case _ => throw new IllegalArgumentException
- }
- p.isValid shouldBe true
- p.startNode.outer == toN(sample.head) shouldBe true
- p.endNode.outer == toN(sample.last) shouldBe true
- }
-
- n(1) findSuccessor (_.outDegree > 3) shouldBe None
- n(1) findSuccessor (_.outDegree >= 3) should be(Some(3))
- n(4) findSuccessor (_.edges forall (!_.isDirected)) should be(Some(2))
- n(4) isPredecessorOf n(1) shouldBe true
- validatePath(
- (n(1) pathTo n(4)).get,
- List[Outer](1, 1 ~> 3 % 5, 3, 3 ~ 4 % 1, 4)
- )
- validatePath(
- (n(1) pathUntil (_.outDegree >= 3)).get,
- List[Outer](1, 1 ~> 3 % 5, 3)
- )
- val maybeP = n(3) shortestPathTo n(1)
- val p = maybeP.get
- validatePath(p, List[Outer](3, 3 ~ 4 % 1, 4, 4 ~> 5 % 0, 5, 1 ~ 5 % 3, 1))
- p.nodes.toList should be(List(3, 4, 5, 1))
- p.weight shouldBe 4
-
- def negWeight(e: g.EdgeT): Double = 5.5f - e.weight
- val maybeNegP = n(3).shortestPathTo(n(1), negWeight)
- val negP = maybeNegP.get
- validatePath(negP, List[Outer](3, 2 ~ 3 % 2, 2, 1 ~> 2 % 4, 1))
- negP.nodes.toList shouldBe List(3, 2, 1)
- negP.weight shouldBe 6
-
- val maybeSubgraphP1 = n(4).withSubgraph(nodes = _ < 4) pathTo n(2)
- validatePath(maybeSubgraphP1.get, List[Outer](4, 3 ~ 4 % 1, 3, 2 ~ 3 % 2, 2))
- maybeSubgraphP1.map(_.nodes).get.toList shouldBe List(4, 3, 2)
-
- val maybeSubgraphP2 = n(4).withSubgraph(edges = _.weight != 2) pathTo n(2)
- validatePath(maybeSubgraphP2.get, List[Outer](4, 4 ~> 5 % 0, 5, 1 ~ 5 % 3, 1, 1 ~ 2 % 4, 2))
- maybeSubgraphP2.map(_.nodes).get.toList shouldBe List(4, 5, 1, 2)
- }
-
- def `cycle detection`: Unit = {
- val g = Graph(1 ~> 2, 1 ~> 3, 2 ~> 3, 3 ~> 4, 4 ~> 2)
- val fc1 = g.findCycle
- fc1.get.sameElements(List(2, 2 ~> 3, 3, 3 ~> 4, 4, 4 ~> 2, 2)) shouldBe true
- val fc2 = (g get 4).findCycle
- fc2.get.sameElements(List(4, 4 ~> 2, 2, 2 ~> 3, 3, 3 ~> 4, 4)) shouldBe true
- for {
- c1 <- fc1
- c2 <- fc2
- } yield c1 == c2 shouldBe false
- for {
- c1 <- fc1
- c2 <- fc2
- } yield c1 sameAs c2 shouldBe true
- }
-
- def `ordered traversal`: Unit = {
- val root = 1
- val g = Graph(root ~> 4 % 2, root ~> 2 % 5, root ~> 3 % 4, 3 ~> 6 % 4, 3 ~> 5 % 5, 3 ~> 7 % 2)
-
- def edgeOrdering = g.EdgeOrdering(g.BaseInnerEdge.WeightOrdering.reverse.compare _)
- val traverser = (g get root).outerNodeTraverser.withOrdering(edgeOrdering)
-
- traverser.toList should equal(List(1 to 7: _*))
- }
-
- def `traversers with fluent properties`: Unit = {
- val g = Graph(1 ~> 2 % 1, 1 ~> 3 % 2, 2 ~> 3 % 3, 3 ~> 4 % 1)
- val n1 = g get 1
-
- n1.outerNodeTraverser.sum shouldBe 10
- g.outerNodeTraverser(n1).sum shouldBe 10
- n1.outerNodeTraverser.withMaxDepth(1).sum shouldBe 6
-
- n1.innerEdgeTraverser.map(_.weight).sum shouldBe 7
-
- n1.innerElemTraverser
- .filter {
- case g.InnerNode(n, _) => n.degree > 1
- case g.InnerEdge(_, e) => e.weight > 1
- }
- .map {
- case g.InnerNode(_, n) => n
- case g.InnerEdge(_, e) => e
- }
- .toSet shouldBe Set(1, 2, 3, 1 ~> 3 % 2, 2 ~> 3 % 3)
- }
-
- def `DownUp traverser`: Unit = {
- import scala.collection.mutable.ArrayBuffer
-
- val root = "A"
- val g = Graph(root ~> "B1", root ~> "B2")
- val innerRoot = g get root
- val result = innerRoot.innerNodeDownUpTraverser.foldLeft(ArrayBuffer.empty[String]) { (buf, param) =>
- param match {
- case (down, node) =>
- if (down) buf += (if (node eq innerRoot) "(" else "[") += node.toString
- else buf += (if (node eq innerRoot) ")" else "]")
- }
- }
- result.fold("")(_ + _) should (be("(A[B1][B2])") or
- be("(A[B2][B1])"))
- }
-
- def `extended traverser`: Unit = {
- val g = Graph(1 ~> 2, 1 ~> 3, 2 ~> 3, 3 ~> 4, 4 ~> 2)
-
- import g.ExtendedNodeVisitor
-
- type ValDepth = (Int, Int)
- var info = List.empty[ValDepth]
- (g get 1).innerNodeTraverser.foreach {
- ExtendedNodeVisitor((node, _, depth, _) => info :+= (node.outer, depth))
- }
- info.sortWith((a: ValDepth, b: ValDepth) =>
- a._1 < b._1 ||
- a._1 == b._1 && a._2 < b._2
- ) should be(List((1, 0), (2, 1), (3, 1), (4, 2)))
- }
-
- def `cycle detection for side effect`: Unit = {
- val g = Graph(1 ~> 2, 1 ~> 3, 2 ~> 3, 3 ~> 4, 4 ~> 2)
-
- var center: Option[g.NodeT] = None
- val maybeCycle = (g get 4).findCycle(n =>
- center = center match {
- case s @ Some(c) => if (n.degree > c.degree) Some(n) else s
- case None => Some(n)
- }
- )
- maybeCycle.map(_.sameElements(List(2, 2 ~> 3, 3, 3 ~> 4, 4, 4 ~> 2, 2))) shouldBe Some(true)
- center shouldBe Some(2)
- }
-
- def `weak component traverser`: Unit = {
- val componentEdges = {
- def edges(i: Int) = List(i ~> (i + 1), i ~> (i + 2), (i + 1) ~> (i + 2))
- (edges(1), edges(5))
- }
- val disconnected = Graph.from(edges = componentEdges._1 ++ componentEdges._2)
- val sums =
- for (component <- disconnected.componentTraverser())
- yield component.nodes.foldLeft(0)((cum, n) => cum + n.outer)
- sums should be(List(6, 18))
-
- val anyNode = disconnected.nodes.draw(new util.Random)
- anyNode.weakComponent.nodes should have size componentEdges._1.size
- }
-
- def `strong component traverser`: Unit = {
- type G = Graph[Char, DiEdge[Char]]
- val sccExpected: (G, G) = (
- Graph('a' ~> 'b', 'b' ~> 'c', 'c' ~> 'd', 'd' ~> 'a', 'd' ~> 'e', 'c' ~> 'e', 'e' ~> 'c'),
- Graph('f' ~> 'g', 'g' ~> 'f', 'g' ~> 'h', 'h' ~> 'j', 'j' ~> 'i', 'i' ~> 'g', 'i' ~> 'f', 'f' ~> 'i')
- )
- val connected = (sccExpected._1 union sccExpected._2) concat List('e' ~> 'f')
- val scc = connected.strongComponentTraverser().map(_.to(Graph))
- scc.toSet should be(Set(sccExpected._1, sccExpected._2))
-
- val startAt = sccExpected._2.nodes.head
- startAt.strongComponents should have size 1
- startAt.innerNodeTraverser.strongComponents(_ => ())
- }
-
- def `path builder`: Unit = {
- val builder = g.newPathBuilder(n(1))
- builder += n(3) += n(4)
- builder.result().toOuterElems.toList shouldBe List[Outer](1, 1 ~> 3 % 5.0, 3, 3 ~ 4 % 1.0, 4)
-
- builder.clear()
- builder += n(4) += n(3)
- builder.result().toOuterElems.toList shouldBe List[Outer](1, 1 ~> 3 % 5.0, 3)
-
- builder.clear()
- builder add n(4) shouldBe false
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/demo/subset.scala b/coreTestScala3/src/test/scala/demo/subset.scala
deleted file mode 100644
index 47bd2336..00000000
--- a/coreTestScala3/src/test/scala/demo/subset.scala
+++ /dev/null
@@ -1,88 +0,0 @@
-package demo
-
-import scala.collection.immutable.ArraySeq
-import scala.reflect.ClassTag
-import scala.util.chaining.*
-
-protected trait SubsetOps[A, +S <: Set[A] with Singleton] extends Set[A] {
- def superset: S
- def set: Set[A]
-
- def contains(elem: A): Boolean = set(elem)
- def iterator: Iterator[A] = set.iterator
- override def toString: String = s"${getClass.getSimpleName}(${set mkString ", "}) out of ${superset.size}"
-}
-
-/** Includes a `superset` and a `set` guaranteeing that `set` is a subset of `superset`.
- *
- * @tparam A type of the elements of both `superset` and `set`
- * @tparam S singleton type denoting `superset`
- */
-case class Subset[A, +S <: Set[A] with Singleton] private (superset: S, set: Set[A]) extends SubsetOps[A, S] {
-
- def incl(elem: A): Subset[A, S] =
- if (superset(elem) && !set(elem)) Subset(superset, set incl elem)
- else this
-
- def excl(elem: A): Subset[A, S] = Subset(superset, set excl elem)
-}
-
-object Subset {
- def apply[A](superset: Set[A])(elems: A*): Subset[A, superset.type] =
- new Subset(superset, elems.iterator.filter(superset.apply).toSet)
-
- def byFilter[A](superset: Set[A])(predicate: A => Boolean): Subset[A, superset.type] =
- new Subset(superset, superset.filter(predicate))
-}
-
-/** Includes a `superset`, a `seq` and a `set` guaranteeing that `set` is a subset of `superset` and
- * `seq` has the same elements as `set` ordered on creation time.
- *
- * @tparam A type of the elements of both `superset` and `set`
- * @tparam S singleton type denoting `superset`
- */
-case class OrderedSubset[A, +S <: Set[A] with Singleton] private (superset: S, ordered: ArraySeq[A], set: Set[A])
- extends SubsetOps[A, S] {
-
- def incl(elem: A): OrderedSubset[A, S] =
- if (superset(elem) && !set(elem))
- OrderedSubset(superset, ordered appended elem, set incl elem)
- else this
-
- def excl(elem: A): OrderedSubset[A, S] =
- ordered.indexOf(elem) pipe { idx =>
- if (idx == -1) this
- else OrderedSubset(superset, ordered.patch(idx, elem :: Nil, 1), set excl elem)
- }
-}
-
-object OrderedSubset {
- def apply[A](superset: Set[A])(elems: A*)(implicit tag: ClassTag[A]): OrderedSubset[A, superset.type] =
- elems.foldLeft((ArraySeq.empty[A], Set.empty[A])) {
- case (cum @ (_, set), elem) if !superset(elem) || set(elem) => cum
- case ((seq, set), elem) => (seq appended elem, set incl elem)
- } match {
- case (seq, set) => new OrderedSubset(superset, seq, set)
- }
-}
-
-/** Includes a `superset` and a single element `set` guaranteeing that `set` is a subset of `superset`.
- *
- * @tparam A type of the elements of both `superset` and `set`
- * @tparam S singleton type denoting `superset`
- */
-case class OneOf[A, +S <: Set[A] with Singleton] private (superset: S, one: A) {
- override def toString: String = s"One($one) out of ${superset.size}"
-}
-
-object OneOf {
- def apply[A](superset: Set[A])(elem: A): Option[OneOf[A, superset.type]] =
- if (superset(elem)) Some(new OneOf(superset, elem))
- else None
-}
-
-/** Wraps an `immutable.Set` by also capturing the underlying set as a singleton type.
- * Useful if you need to enforce `Superset` and `Subset` instances to use the same superset singleton.
- * Gets probably obsolete in Scala 3.
- */
-case class Superset[A, +S <: Set[A] with Singleton](set: Set[A] with S)
diff --git a/coreTestScala3/src/test/scala/scala/collection/mutable/ExtHashSetSpec.scala b/coreTestScala3/src/test/scala/scala/collection/mutable/ExtHashSetSpec.scala
deleted file mode 100644
index 27f1ca8a..00000000
--- a/coreTestScala3/src/test/scala/scala/collection/mutable/ExtHashSetSpec.scala
+++ /dev/null
@@ -1,154 +0,0 @@
-package scala.collection.mutable
-
-import scala.collection.immutable
-import scala.math.abs
-import scala.util.Random
-import scala.util.chaining.*
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-class ExtHashSetSpec extends RefSpec with Matchers {
-
- object `ExtHashSet works properly in that it` {
- import ExtHashSetSpec.*
-
- def `draws random elements with uniform distribution if buckets are of equal length`: Unit = {
- val size = 16
- val set = ExtHashSet(1 to size: _*)
- nonEmptyBuckets(set).length should ===(size)
-
- val nrProbesPerElement = 100
- val nrProbes = size * nrProbesPerElement
- val frequencies = sortedProbeFrequencies(set, nrProbes, Some(0))
- val maxDeviation_% = 20
- range(frequencies) should be < nrProbesPerElement * (2 * maxDeviation_%) / 100
- }
-
- def `draws random elements with near-uniform distribution if buckets are of different length`: Unit = {
- val set = {
- val maxSize = 16
- val r = new Random
- r.setSeed(1150)
- ExtHashSet.fill(maxSize)(r.nextInt(maxSize * 4))
- }
-
- val buckets = nonEmptyBuckets(set)
- buckets.map(_.length) pipe { bucketLengths =>
- bucketLengths.max - bucketLengths.min should be > 0
- }
-
- val bucketLengthOfElement: Int Map Int = {
- val m = Map.empty[Int, Int]
- buckets foreach { bucket =>
- val len = bucket.length
- bucket foreach (v => m update (v, len))
- }
- m
- }
- val nrProbesPerElement = 100
- val nrProbes = set.size * nrProbesPerElement
- val frequencies = sortedProbeFrequencies(set, nrProbes, Some(77))
- val maxDeviationForBucketLength_% = Map(1 -> 25, 2 -> 50)
- frequencies foreach { case ProbeFrequency(element, count) =>
- abs(nrProbesPerElement - count) should be < maxDeviationForBucketLength_%(bucketLengthOfElement(element))
- }
- }
-
- def `finds elements by predicate`: Unit = {
- case class C(value: Int) {
- override def hashCode(): Int = 0
- }
- val s = ExtHashSet(C(1), C(2))
- s.findElem(C(3), (i: C, j: C) => i.value == j.value - 1) should ===(C(2))
- }
-
- def `is able to upsert elements`: Unit = {
- val elem = new MutableElem(1, 0)
- val set = ExtHashSet(elem)
-
- val mutation = new MutableElem(1, 1)
- mutation should ===(elem)
-
- set.upsert(mutation) should be(false)
- set should (have size 1 and contain(mutation))
-
- set.upsert(new MutableElem(2, 0)) should be(true)
- set should have size 2
- }
-
- def `iterates over hashCodes`: Unit = {
- case class C(value: Int) {
- override def hashCode(): Int = value
- }
- val set = ExtHashSet(C(1), C(2))
- set.hashCodeIterator(3).toList should have size 0
- val elems = set.hashCodeIterator(1).toList
- elems should have size 1
- elems.head should be(C(1))
- }
-
- def `iterates over duplicate hashCodes`: Unit = {
- case class C(i: Int, j: Int) {
- override def hashCode = i.##
- }
- val multi = ExtHashSet(C(1, 0), C(1, 1), C(2, 2), C(1, 3), C(2, 0))
- for (i <- 0 to 2) {
- val elems = multi.hashCodeIterator(i.##).toList
- elems should have size (multi count (_.i == i))
- }
- }
- }
-}
-
-object ExtHashSetSpec {
-
- private def nonEmptyBuckets(set: ExtHashSet[Int]) = set.dump filter (_.nonEmpty)
-
- protected case class ProbeFrequency[A](probe: A, count: Int)
-
- private def sortedProbeFrequencies(
- set: ExtHashSet[Int],
- nrProbes: Int,
- seed: Option[Long]
- ): List[ProbeFrequency[Int]] = {
- val r = new Random
- seed foreach r.setSeed
- Array
- .fill(nrProbes)(set draw r)
- .groupBy(identity)
- .map { case (k, v: Array[Int]) =>
- ProbeFrequency(k, v.length)
- }
- .toList
- .sortBy { case ProbeFrequency(_, v) =>
- v
- }
- }
-
- private def range(sortedFrequencies: List[ProbeFrequency[Int]]): Int =
- (sortedFrequencies.head, sortedFrequencies.last) match {
- case (ProbeFrequency(_, lowest), ProbeFrequency(_, highest)) => highest - lowest
- }
-
- class MutableElem(val a: Int, var b: Int) {
- override def hashCode(): Int = a.##
-
- override def equals(other: Any): Boolean = other match {
- case that: MutableElem => a == that.a
- case _ => false
- }
-
- override def toString: String = s"M($a, $b)"
- }
-
- /* some support to play on the console:
-
- val set = ExtHashSet(0, 1, 7, 10, 12, 81, 82, 83)
- set.dump foreach println
-
- Range(10, 2000, 100) foreach { i =>
- println(sortedProbeFrequencies(set, i))
- }
- */
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/ConfigWrapper.scala b/coreTestScala3/src/test/scala/scalax/collection/ConfigWrapper.scala
deleted file mode 100644
index 44d0e5f0..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/ConfigWrapper.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-package scalax.collection
-
-import scalax.collection.config.GraphConfig
-import scalax.collection.generic.{Edge, GenericGraphFactory}
-
-/** Enables to transparently pass `GraphCompanion` objects with non-default configuration parameters to specs.
- */
-trait ConfigWrapper[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]] {
- val companion: GenericGraphFactory[CC]
- implicit val config: GraphConfig
-
- def empty[N, E <: Edge[N]]: CC[N, E] = companion.empty[N, E]
-
- def apply[N, E[X] <: Edge[X]](elems: OuterElem[N, E[N]]*)(implicit config: GraphConfig): CC[N, E[N]] =
- companion(elems: _*)
-
- def from[N, E <: Edge[N]](nodes: collection.Iterable[N], edges: collection.Iterable[E])(implicit
- config: GraphConfig
- ): CC[N, E] =
- companion.from[N, E](nodes, edges)
-
- def from[N, E[X] <: Edge[X]](edges: collection.Iterable[E[N]]): CC[N, E[N]] =
- companion.from[N, E](edges)
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/ConnectivitySpec.scala b/coreTestScala3/src/test/scala/scalax/collection/ConnectivitySpec.scala
deleted file mode 100644
index ef7b8b2b..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/ConnectivitySpec.scala
+++ /dev/null
@@ -1,181 +0,0 @@
-package scalax.collection
-
-import scala.util.Random
-
-import org.scalatest.*
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generator.*
-import scalax.collection.generator.RandomGraph.IntFactory
-import scalax.collection.generic.*
-import scalax.collection.visualization.Visualizer
-
-class ConnectivitySpec
- extends Suites(
- new Connectivity[immutable.Graph](immutable.Graph),
- new Connectivity[mutable.Graph](mutable.Graph)
- )
-
-final class Connectivity[G[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, G]](
- val factory: GenericGraphCoreFactory[G]
-) extends RefSpec
- with Matchers
- with ScalaCheckPropertyChecks
- with IntelliJ[G]
- with Visualizer {
-
- implicit val config: PropertyCheckConfiguration =
- PropertyCheckConfiguration(minSuccessful = 5, maxDiscardedFactor = 1.0)
-
- object `In a weakly connected diGraph` {
- import Data.elementsOfDi_1
- val g = factory(elementsOfDi_1: _*).asAnyGraph
-
- def `there exists no pair of mutually reachable nodes`: Unit =
- withGraph(g) {
- _.nodes.toList.combinations(2) foreach {
- case List(a, b) => List(a pathTo b, b pathTo a) should contain(None)
- case _ => fail()
- }
- }
-
- def `evaluating strong components from any node yields single-node components`: Unit =
- withGraph(g) {
- _.nodes foreach { n =>
- val components = n.innerNodeTraverser.strongComponents
- components foreach (_.nodes should have size 1)
- }
- }
-
- def `evaluating all strong components yields a component for every node`: Unit =
- withGraph(g) { g =>
- g.strongComponentTraverser().size shouldBe g.order
- }
- }
-
- object `Having two strong components` {
- // see example on https://de.wikipedia.org/wiki/Algorithmus_von_Tarjan_zur_Bestimmung_starker_Zusammenhangskomponenten
- val sccExpected = Vector[G[Char, DiEdge[Char]]](
- factory('a' ~> 'b', 'b' ~> 'c', 'c' ~> 'd', 'd' ~> 'a', 'd' ~> 'e', 'c' ~> 'e', 'e' ~> 'c'),
- factory('f' ~> 'g', 'g' ~> 'f', 'g' ~> 'h', 'h' ~> 'j', 'j' ~> 'i', 'i' ~> 'g', 'i' ~> 'f', 'f' ~> 'i')
- )
- val sscExpectedAny: Vector[AnyGraph[Char, DiEdge[Char]]] = sccExpected // annotated for IntelliJ
- val sccExpectedG = sccExpected
-
- assert(sccExpected.size == 2)
- assert(sscExpectedAny(0).intersect(sscExpectedAny(1)).isEmpty)
-
- def `each is detected as such`: Unit =
- sscExpectedAny.foreach { g =>
- withGraph(g) {
- _.strongComponentTraverser() should have size 1
- }
- }
-
- def `connected by a diEdge yields a graph with the very same two strong components`: Unit = {
- val r = new Random
- val union =
- sscExpectedAny.foldLeft(factory.empty[Char, DiEdge[Char]].asAnyGraph)((r, g) => g union r)
- val connectors = {
- def pickNode(index: Int) = sscExpectedAny(index).nodes.draw(r).outer
- for (i <- 1 to 10) yield pickNode(0) ~> pickNode(1)
- }
- connectors foreach { connector =>
- val connected = union concat List(connector)
- def check(scc: Iterable[connected.Component], expectedSize: Int): Unit = {
- scc should have size expectedSize
- scc foreach { sc =>
- withGraph(sc.to(factory).asAnyGraph) { g =>
- sccExpected should contain(g)
- sc.frontierEdges should have size 1
- }
- }
- }
-
- check(connected.strongComponentTraverser().toVector, 2)
-
- val start = connected.nodes.draw(r)
- check(
- start.innerNodeTraverser.strongComponents.toVector,
- if (sccExpected(0).asAnyGraph contains start) 2 else 1
- )
- }
- }
- }
-
- object `Having two weak components` {
- def `weak components are detected, fix #57`: Unit =
- withGraph(factory(11 ~> 12, 13 ~> 14)) {
- _.componentTraverser() should have size 2
- }
- }
-
- object `Having a bigger graph` {
- val g = {
- val gOrder = 1000
- val random = RandomGraph.diGraph(
- factory,
- new IntFactory {
- val order = gOrder
- val nodeDegrees = NodeDegreeRange(gOrder / 10, gOrder / 4)
- }
- )
- random.draw
- }.asAnyGraph
-
- val strongComponents = g.strongComponentTraverser().toVector
-
- def `no stack overflow occurs`: Unit =
- withGraph(g)(_ => strongComponents shouldBe a[Vector[_]])
-
- def `strong components are complete`: Unit =
- withGraph(g) { _ =>
- strongComponents.foldLeft(Set.empty[g.NodeT])((cum, sc) => cum ++ sc.nodes) shouldBe g.nodes
- }
-
- def `strong components are proper`: Unit =
- withGraph(g) { _ =>
- val maxProbes = 10
- val arbitraryNodes: Vector[Set[g.NodeT]] = strongComponents map { sc =>
- val nodes = sc.nodes
- if (nodes.size <= maxProbes) nodes
- else {
- val every = nodes.size / maxProbes
- nodes.zipWithIndex withFilter { case (_, i) => i % every == 0 } map (_._1)
- }
- }
- arbitraryNodes foreach { nodes =>
- def checkBiConnected(n1: g.NodeT, n2: g.NodeT) =
- if (n1 ne n2) {
- n1 pathTo n2 shouldBe defined
- n2 pathTo n1 shouldBe defined
- }
-
- nodes.sliding(2) foreach { pairOrSingle =>
- pairOrSingle.toList match {
- case List(n1, n2) => checkBiConnected(n1, n2)
- case n :: Nil => checkBiConnected(n, nodes.head)
- case _ => fail()
- }
- }
- }
- arbitraryNodes.sliding(2) foreach { pairOrSingle =>
- def checkNonBiConnected(ns1: Set[g.NodeT], ns2: Set[g.NodeT]): Unit =
- if (ns1 ne ns2)
- ns1 zip ns2 foreach { case (n1, n2) =>
- (n1 pathTo n2) shouldBe defined
- (n2 pathTo n1) should not be defined
- }
-
- pairOrSingle.toList match {
- case List(ns1, ns2) => checkNonBiConnected(ns1, ns2)
- case ns :: Nil => checkNonBiConnected(ns, arbitraryNodes.head)
- case _ => fail()
- }
- }
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/CycleSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/CycleSpec.scala
deleted file mode 100644
index 3153ff91..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/CycleSpec.scala
+++ /dev/null
@@ -1,393 +0,0 @@
-package scalax.collection
-
-import language.postfixOps
-
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.*
-import scalax.collection.visualization.Visualizer
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import org.scalatest.Suites
-import org.scalatest.matchers.{MatchResult, Matcher}
-
-import scala.util.chaining.scalaUtilChainingOps
-
-class CycleSpec extends Suites(new Cycle[immutable.Graph](immutable.Graph), new Cycle[mutable.Graph](mutable.Graph))
-
-private trait CycleMatcher[N, E <: Edge[N]] {
- protected type C = AnyGraph[N, E]#Cycle
-
- def haveOneNodeSequenceOf(expected: Seq[N]*): Matcher[Option[C]] =
- Matcher { (ns: Option[C]) =>
- val found: Seq[N] = ns match {
- case None => Seq()
- case Some(path) => path.nodes.toSeq.map(_.outer).toList
- }
- def msg(key: String): String =
- s"""$found equals to $key of
- |${expected mkString ", "} in
- |${ns.get.containingGraph}.
- """.stripMargin
- MatchResult(expected contains found, msg("none"), msg("one"))
- }
-
- def beValid: Matcher[Option[C]] =
- Matcher { (c: Option[C]) =>
- def msg(key: String): String = s"$c $key valid"
- MatchResult(c.get.isValid, msg("is not"), msg("is"))
- }
-}
-
-private class Cycle[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]](
- val factory: GenericGraphCoreFactory[CC]
-) extends RefSpec
- with Matchers
- with IntelliJ[CC]
- with Visualizer {
-
- object `given some directed graphs` extends CycleMatcher[Int, DiEdge[Int]] {
- private val acyclic_1 = factory(1 ~> 2, 1 ~> 3, 2 ~> 3, 3 ~> 4).asAnyGraph
- private val acyclic_2 =
- factory(1 ~> 2, 1 ~> 3, 1 ~> 4, 1 ~> 5, 2 ~> 3, 3 ~> 7, 7 ~> 4, 7 ~> 8, 4 ~> 5, 5 ~> 6).asAnyGraph
- private val (
- (cyclic_1, cyclicEdge_1),
- (cyclic_21, cyclicEdge_21),
- (cyclic_22, cyclicEdge_22)
- ) = {
- def makeCyclic(acyclic: AnyGraph[Int, DiEdge[Int]], byEdge: DiEdge[Int]) = {
- val cyclic = acyclic concat List(byEdge)
- (cyclic, cyclic get byEdge)
- }
- (
- makeCyclic(acyclic_1, 4 ~> 2),
- makeCyclic(acyclic_2, 8 ~> 3),
- makeCyclic(acyclic_2, 6 ~> 1)
- )
- }
-
- def `the cycle returned by 'findCycle' contains the expected nodes`: Unit = {
- withGraph(acyclic_1) { g =>
- (g get 1 findCycle) should be(None)
- }
- withGraph(cyclic_1) { g =>
- (g get 2 findCycle) should haveOneNodeSequenceOf(Seq(2, 3, 4, 2))
- }
-
- withGraph(acyclic_2) { g =>
- (g get 1 findCycle) should be(None)
- }
- withGraph(cyclic_21) { g =>
- (g get 1 findCycle) should haveOneNodeSequenceOf(Seq(3, 7, 8, 3))
- }
- withGraph(cyclic_22) { g =>
- def n(outer: Int) = g get outer
-
- n(1).findCycle should haveOneNodeSequenceOf(
- Seq(1, 5, 6, 1),
- Seq(1, 4, 5, 6, 1),
- Seq(1, 3, 7, 4, 5, 6, 1),
- Seq(1, 2, 3, 7, 4, 5, 6, 1)
- )
- n(4).findCycle should haveOneNodeSequenceOf(
- Seq(5, 6, 1, 5),
- Seq(4, 5, 6, 1, 4),
- Seq(4, 5, 6, 1, 3, 7, 4),
- Seq(4, 5, 6, 1, 2, 3, 7, 4)
- )
- }
-
- val g = {
- var i, j = 0
- factory.fill(5) { i += 1; j = i + 1; i ~> j }
- }.asAnyGraph
-
- def fromEachNode[N, E <: Edge[N]](noCycles: Set[N], cycle: AnyGraph[N, E]#Cycle): Unit =
- withGraph(cycle.nodes.head.containingGraph) {
- _.nodes foreach { n =>
- val found = n.findCycle
- if (noCycles contains n.outer) found should be(None)
- else (found.get sameAs cycle) should be(true)
- }
- }
-
- withGraph(g concat List(4 ~> 2)) { g =>
- val cycle = g get 3 findCycle
-
- cycle should haveOneNodeSequenceOf(Seq(3, 4, 2, 3))
- fromEachNode(Set(5, 6), cycle get)
- }
-
- withGraph(g concat List(5 ~> 2)) { g =>
- val cycle = g get 3 findCycle
-
- cycle should haveOneNodeSequenceOf(Seq(3, 4, 5, 2, 3))
- fromEachNode(Set(6), cycle get)
- }
- }
-
- def `the cycle returned by 'findCycleContaining' contains the expected nodes`: Unit = {
- withGraph(acyclic_1) { g =>
- g.findCycleContaining(g get 1) should be(None)
- }
- withGraph(cyclic_1) { g =>
- g.findCycleContaining(g get 2) should haveOneNodeSequenceOf(Seq(2, 3, 4, 2))
- }
- withGraph(acyclic_2) { g =>
- g.findCycleContaining(g get 1) should be(None)
- }
- withGraph(cyclic_21) { g =>
- def n(outer: Int) = g get outer
-
- g.findCycleContaining(n(1)) should be(None)
- g.findCycleContaining(n(3)) should haveOneNodeSequenceOf(Seq(3, 7, 8, 3))
- }
- withGraph(cyclic_22) { g =>
- def n(outer: Int) = g get outer
-
- g.findCycleContaining(n(1)) should haveOneNodeSequenceOf(
- Seq(1, 5, 6, 1),
- Seq(1, 4, 5, 6, 1),
- Seq(1, 3, 7, 4, 5, 6, 1),
- Seq(1, 2, 3, 7, 4, 5, 6, 1)
- )
- g.findCycleContaining(n(4)) should haveOneNodeSequenceOf(
- Seq(4, 5, 6, 1, 4),
- Seq(4, 5, 6, 1, 3, 7, 4),
- Seq(4, 5, 6, 1, 2, 3, 7, 4)
- )
- g.findCycleContaining(n(3)) should haveOneNodeSequenceOf(Seq(3, 7, 4, 5, 6, 1, 3), Seq(3, 7, 4, 5, 6, 1, 2, 3))
- g.findCycleContaining(n(2)) should haveOneNodeSequenceOf(Seq(2, 3, 7, 4, 5, 6, 1, 2))
- }
- }
-
- def `the cycle returned by 'partOfCycle' combined with fluent properties contains the expected nodes`: Unit =
- withGraph(cyclic_22) { g =>
- def n(outer: Int) = g get outer
-
- n(1).withSubgraph(nodes = _.outer != 3).partOfCycle() should haveOneNodeSequenceOf(
- Seq(1, 5, 6, 1),
- Seq(1, 4, 5, 6, 1)
- )
- n(4).withSubgraph(nodes = _.outer != 3).partOfCycle() should haveOneNodeSequenceOf(Seq(4, 5, 6, 1, 4))
- n(2).withSubgraph(nodes = _.outer != 3).partOfCycle() should be(None)
- }
-
- def `the cycle returned by 'findCycle' contains the expected edges`: Unit = {
- withGraph(acyclic_1)(_.findCycle should be(None))
- withGraph(cyclic_1)(_.findCycle.get.edges should contain(cyclicEdge_1))
- withGraph(acyclic_2)(_.findCycle should be(None))
- withGraph(cyclic_21)(_.findCycle.get.edges should contain(cyclicEdge_21))
- withGraph(cyclic_22)(_.findCycle.get.edges should contain(cyclicEdge_22))
- }
-
- def `the cycle returned by 'findCycleContaining' contains the expected edges`: Unit = {
- withGraph(cyclic_1) { g =>
- g.findCycleContaining(g get 2).get.edges should contain(cyclicEdge_1)
- }
- withGraph(cyclic_21) { g =>
- g.findCycleContaining(g get 3).get.edges should contain(cyclicEdge_21)
- }
- withGraph(cyclic_22) { g =>
- g.findCycleContaining(g get 1).get.edges should contain(cyclicEdge_22)
- }
- }
-
- def `'isCyclic' returns the expected result`: Unit = {
- withGraph(acyclic_1)(_.isAcyclic shouldBe true)
- withGraph(cyclic_1)(_.isCyclic shouldBe true)
- withGraph(acyclic_2)(_.isAcyclic shouldBe true)
- withGraph(cyclic_21)(_.isCyclic shouldBe true)
- withGraph(cyclic_22)(_.isCyclic shouldBe true)
- }
-
- def `they are cyclic if they contain a self loop #76`: Unit = {
- val loop = 1 ~> 1
- withGraph(acyclic_1 concat List(loop))(_.isCyclic shouldBe true)
- withGraph(factory(loop)) { g =>
- g.findCycle should (be(defined) and beValid)
- g.findCycleContaining(g get 1) should (be(defined) and beValid)
- }
- }
- }
-
- object `given some undirected graphs` extends CycleMatcher[Int, UnDiEdge[Int]] {
- private val unDiAcyclic_1 = factory(1 ~ 2, 2 ~ 3).asAnyGraph
- private val unDiCyclic_1 = unDiAcyclic_1 concat List(1 ~ 3)
-
- private val unDiAcyclic_2 = factory(1 ~ 2, 1 ~ 3, 2 ~ 4, 2 ~ 5).asAnyGraph
- private val unDiCyclic_21 = unDiAcyclic_2 concat List(3 ~ 5)
- private val unDiCyclic_22 = unDiAcyclic_2 concat List(3 ~ 6, 6 ~ 7, 7 ~ 4)
-
- def `the cycle returned by 'findCycle' contains the expected nodes`: Unit = {
- withGraph(unDiAcyclic_1) { g =>
- (g get 1 findCycle) shouldBe None
- }
- withGraph(unDiCyclic_1) { g =>
- (g get 2 findCycle) should haveOneNodeSequenceOf(Seq(2, 3, 1, 2), Seq(2, 1, 3, 2))
- }
- withGraph(unDiAcyclic_2) { g =>
- (g get 1 findCycle) should be(None)
- }
- withGraph(unDiCyclic_21) { g =>
- (g get 1 findCycle) should haveOneNodeSequenceOf(Seq(1, 3, 5, 2, 1), Seq(1, 2, 5, 3, 1))
- }
- withGraph(unDiCyclic_22) { g =>
- (g get 3 findCycle) should haveOneNodeSequenceOf(Seq(3, 1, 2, 4, 7, 6, 3), Seq(3, 6, 7, 4, 2, 1, 3))
- }
- }
-
- def `the cycle returned by 'findCycleContaining' contains the expected nodes`: Unit = {
- withGraph(unDiAcyclic_1) { g =>
- g.findCycleContaining(g get 1) should be(None)
- }
- withGraph(unDiCyclic_1) { g =>
- g.findCycleContaining(g get 2) should haveOneNodeSequenceOf(Seq(2, 3, 1, 2), Seq(2, 1, 3, 2))
- }
- withGraph(unDiAcyclic_2) { g =>
- g.findCycleContaining(g get 1) should be(None)
- }
- withGraph(unDiCyclic_21) { g =>
- def n(outer: Int) = g get outer
-
- g.findCycleContaining(n(1)) should haveOneNodeSequenceOf(Seq(1, 3, 5, 2, 1), Seq(1, 2, 5, 3, 1))
- g.findCycleContaining(n(4)) should be(None)
- }
- withGraph(unDiCyclic_22) { g =>
- def n(outer: Int) = g get outer
-
- g.findCycleContaining(n(3)) should haveOneNodeSequenceOf(Seq(3, 1, 2, 4, 7, 6, 3), Seq(3, 6, 7, 4, 2, 1, 3))
- g.findCycleContaining(n(5)) should be(None)
- }
- }
- def `the cycle returned by 'partOfCycle' combined with fluent properties contains the expected nodes`: Unit = {
- withGraph(unDiCyclic_21) { g =>
- (g get 1).withSubgraph(nodes = _.outer != 2).partOfCycle() should be(None)
- }
- withGraph(unDiCyclic_22) { g =>
- (g get 3).withSubgraph(nodes = _.outer != 2).partOfCycle() should be(None)
- }
- }
- }
-
- object `given an undirected multigraph` {
- import scalax.collection.edges.multilabeled._
- val (e1, e2) = (1 ~ 2 %% 0, 1 ~ 2 %% 1)
-
- val g = factory(e1, e2).asAnyGraph
-
- def `the cycle returned by 'findCycle' contains the expected edges`: Unit = {
- val c = (g get 1).findCycle
- c shouldBe defined
- c.get.edges should (be(List(e1, e2)) or be(List(e2, e1)))
- }
-
- def `the cycle returned by 'findCycleContaining' contains the expected edges`: Unit = {
- val c = g.findCycleContaining(g get 1)
- c shouldBe defined
- c.get.edges should (be(List(e1, e2)) or
- be(List(e2, e1)))
- }
- }
-
- object `given some mixed graphs` extends CycleMatcher[Int, AnyEdge[Int]] {
-
- private val mixed = factory.from(Data.elementsOfMixed_1).asAnyGraph
-
- def `'findCycle' finds a cycle following any route`: Unit = {
- withGraph(
- factory[Int, AnyEdge](
- 1 ~> 3,
- 3 ~> 4,
- 3 ~> 20,
- 20 ~> 21,
- 1 ~> 10,
- 10 ~ 11,
- 11 ~ 12,
- 12 ~ 13,
- 12 ~> 3,
- 20 ~> 10
- ).asAnyGraph
- ) { g =>
- g.findCycle pipe { cycle =>
- cycle should (be(defined) and beValid)
- cycle foreach (_.nodes foreach { n =>
- g.innerNodeTraverser(n).findCycle should (be(defined) and beValid)
- })
- }
- (g get 13).innerNodeTraverser.withOrdering(g.NodeOrdering((a, b) => b.outer - a.outer)).findCycle should (be(
- defined
- ) and beValid)
- }
- withGraph(mixed.filterNot(_.outer == 5, _.outer == 4 ~> 4)) { g =>
- (g get 1).findCycle should haveOneNodeSequenceOf(Seq(1, 3, 2, 1))
- }
- }
-
- def `the cycle returned by 'findCycleContaining' contains the expected nodes`: Unit =
- withGraph(mixed) { g =>
- def n(outer: Int) = g get outer
-
- g.findCycleContaining(n(2)) should haveOneNodeSequenceOf(
- Seq(2, 1, 3, 2),
- Seq(2, 3, 4, 5, 1, 2),
- Seq(2, 1, 5, 3, 2),
- Seq(2, 3, 5, 1, 2)
- )
- g.findCycleContaining(n(1)) should haveOneNodeSequenceOf(
- Seq(1, 3, 2, 1),
- Seq(1, 3, 5, 1),
- Seq(1, 2, 3, 5, 1),
- Seq(1, 5, 3, 2, 1),
- Seq(1, 2, 3, 4, 5, 1),
- Seq(1, 3, 4, 5, 1)
- )
- g.findCycleContaining(n(4)) should haveOneNodeSequenceOf(
- Seq(4, 4),
- Seq(4, 5, 3, 4),
- Seq(4, 5, 1, 2, 3, 4),
- Seq(4, 5, 1, 3, 4)
- )
- }
-
- def `the cycle returned by 'partOfCycle' combined with fluent properties contains the expected nodes`: Unit =
- withGraph(mixed) { g =>
- def n(outer: Int) = g get outer
-
- n(2).withSubgraph(edges = _ != DiEdge(1, 3)).partOfCycle should haveOneNodeSequenceOf(
- Seq(2, 3, 4, 5, 1, 2),
- Seq(2, 1, 5, 3, 2),
- Seq(2, 3, 5, 1, 2)
- )
- n(2)
- .withSubgraph(nodes = _.outer != 5)
- .withOrdering(g.BaseInnerEdge.WeightOrdering)
- .partOfCycle should haveOneNodeSequenceOf(Seq(2, 1, 3, 2))
-
- n(1).withSubgraph(nodes = _.outer != 5).partOfCycle should haveOneNodeSequenceOf(Seq(1, 3, 2, 1))
- }
-
- private val cycleEdges = List(1 ~> 2, 1 ~ 2)
- private val g = factory.from[Int, AnyEdge](2 ~ 3 +: cycleEdges).asAnyGraph
-
- def `the cycle returned by 'findCycle' contains the expected edges`: Unit =
- withGraph(g) { g =>
- g.size should be(3)
- g.nodes foreach { n =>
- val c = n.findCycle
- (n, c.isDefined) should be((n, true))
- c.get.edges should (be(cycleEdges) or be(cycleEdges.reverse))
- }
- }
-
- def `the cycle returned by 'findCycleContaining' contains the expected edges`: Unit =
- withGraph(g) { g =>
- g.nodes.filterNot(_.outer == 3) foreach { n =>
- val c = g.findCycleContaining(g get n)
- (n, c.isDefined) should be((n, true))
- c.get.edges should (be(cycleEdges) or be(cycleEdges.reverse))
- }
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/Data.scala b/coreTestScala3/src/test/scala/scalax/collection/Data.scala
deleted file mode 100644
index e95b9c34..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/Data.scala
+++ /dev/null
@@ -1,114 +0,0 @@
-package scalax.collection
-
-import scala.annotation.tailrec
-import scala.collection.BuildFrom
-import scala.util.Random.shuffle
-
-import scalax.collection.generic._
-import scalax.collection.edges._
-import scalax.collection.edges.labeled._
-
-abstract class TGraph[N, E <: Edge[N], G[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, G]](
- val g: G[N, E]
-) {
- def node(outer: N): g.NodeT = g get outer
- def n(outer: N): g.NodeT = node(outer)
- def edge(outer: E): g.EdgeT = g get outer
- def e(outer: E): g.EdgeT = edge(outer)
-}
-
-/** The Graph for Scala representation of graph pictures located in `scala/test/doc`.
- */
-object Data {
-// WDi-1.jpg without weights
- val elementsOfDi_1 = List(
- 1 ~> 2,
- 2 ~> 3,
- 4 ~> 3,
- 3 ~> 5,
- 1 ~> 5,
- 1 ~> 3
- )
-
- // WUnDi-1.jpg without weights
- val elementsOfMixed_1 = List[AnyEdge[Int]](
- 1 ~ 2,
- 2 ~ 3,
- 1 ~> 3,
- 1 ~ 5,
- 3 ~ 5,
- 3 ~ 4,
- 4 ~> 4,
- 4 ~> 5
- )
-
- // WUnDi-2.jpg without weights
- val elementsOfMixed_2 = List[AnyEdge[Int]](
- 1 ~ 2,
- 2 ~ 3,
- 1 ~> 3,
- 1 ~ 3,
- 1 ~> 2,
- 2 ~ 2
- )
-
-// WDi-1.jpg
- val elementsOfWDi_1 = List(
- 1 ~> 2 % 4,
- 2 ~> 3 % 40,
- 4 ~> 3 % 7,
- 3 ~> 5 % 50,
- 1 ~> 5 % 40,
- 1 ~> 3 % 2
- )
-
-// WUnDi-1.jpg
- val elementsOfWMixed_1 = List[AnyEdge[Int]](
- 1 ~ 2 % 4,
- 2 ~ 3 % 2,
- 1 ~> 3 % 5,
- 1 ~ 5 % 3,
- 3 ~ 5 % 2,
- 3 ~ 4 % 1,
- 4 ~> 4 % 1,
- 4 ~> 5 % 0
- )
-
-// WUnDi-2.jpg
- val elementsOfWMixed_2 = List[AnyEdge[Int]](
- 1 ~ 2 % 4,
- 2 ~ 3 % -1,
- 1 ~> 3 % 5,
- 1 ~ 3 % 4,
- 1 ~> 2 % 3,
- 2 ~ 2 % 1
- )
-
- def shuffleNotEqual[A, C <: IterableOnce[A]](xs: IterableOnce[A])(implicit bf: BuildFrom[xs.type, A, C]): C =
- xs match {
- case _: Iterable[A] =>
- @tailrec def loop(): C = {
- val shuffled = shuffle(xs)
- if (shuffled == xs) loop()
- else shuffled
- }
- loop()
-
- case it: Iterator[A] =>
- val source = it.toBuffer
- @tailrec def loop(): C = {
- val shuffled = shuffle(source)
- if (shuffled == source) loop()
- else shuffled.iterator.asInstanceOf[C]
- }
- loop()
- }
-
- def shuffleNotEqual[N, C[X] <: OneOrMore[X]](o: C[N]): OneOrMore[N] = o match {
- case OneOrMore(_, tail) if tail.isEmpty => throw new IllegalArgumentException("Cannot shuffle single element.")
- case more => OneOrMore.fromUnsafe(shuffleNotEqual(more.iterator))
- }
-
- def shuffleNotEqual[N](s: Several[N]): Several[N] =
- Several.fromUnsafe(shuffleNotEqual(s.iterator))
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/DegreeSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/DegreeSpec.scala
deleted file mode 100644
index 785b75a3..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/DegreeSpec.scala
+++ /dev/null
@@ -1,191 +0,0 @@
-package scalax.collection
-
-import scala.collection.{SortedMap, SortedSet}
-
-import org.scalatest.*
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.edges.*
-import scalax.collection.generic.*
-import scalax.collection.visualization.Visualizer
-
-class DegreeSpec
- extends Suites(
- new Degree[immutable.Graph](immutable.Graph),
- new Degree[mutable.Graph](mutable.Graph)
- )
-
-class Degree[CC[N, E <: Edge[N]] <: GraphLike[N, E, CC] with AnyGraph[N, E]](val factory: GenericGraphCoreFactory[CC])
- extends RefSpec
- with Matchers
- with Visualizer
- with IntelliJ[CC] {
-
- private val emptyG: AnyGraph[Int, DiEdge[Int]] = factory.empty[Int, DiEdge[Int]].asAnyGraph
-
- abstract class TestGraph[N, E <: Edge[N]](override val g: CC[N, E]) extends TGraph(g) {
- def degree(outer: N) = node(outer).degree
- val nodeDegrees: List[(g.NodeT, Int)] = g.nodes.iterator.map(n => (n, n.degree)).toList
- val degrees: List[Int] = nodeDegrees map (_._2)
- }
-
- import Data.*
- object UnDi_1 extends TestGraph[Int, AnyEdge[Int]](factory.from(elementsOfMixed_1)) {
- val expectedDegreeSeq = Seq(4, 4, 3, 3, 2)
- val expectedDegreeSet = SortedSet(4, 3, 2)
- val expectedDegreeNodeSeq = Seq((4, node(4)), (4, node(3)), (3, node(5)), (3, node(1)), (2, node(2)))
- val expectedDegreeNodesMap = SortedMap((4, Set(node(3), node(4))), (3, Set(node(1), node(5))), (2, Set(node(2))))
- val expectedDegreeCount = SortedMap((4, 2), (3, 2), (2, 1))
- val expectedInDegreeNodeSeq = Seq((4, node(3)), (3, node(5)), (2, node(4)), (2, node(2)), (2, node(1)))
- val expectedDegreeGT3NodesMap = SortedMap((4, Set(node(3), node(4))))
- }
- object UnDi_2 extends TestGraph[Int, AnyEdge[Int]](factory.from(elementsOfMixed_2)) {
- val expectedDegreeSeq = Seq(5, 4, 3)
- val expectedDegreeSet = SortedSet(5, 4, 3)
- val expectedDegreeNodeSeq = Seq((5, node(2)), (4, node(1)), (3, node(3)))
- val expectedDegreeNodesMap = SortedMap((5, Set(node(2))), (4, Set(node(1))), (3, Set(node(3))))
- val expectedDegreeCount = SortedMap((5, 1), (4, 1), (3, 1))
- }
-
- object `Degrees are calculated properly` {
- def `for nodes`: Unit = {
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph) { _ =>
- degree(1) should be(3)
- degree(2) should be(2)
- degree(3) should be(4)
- degree(4) should be(4)
- degree(5) should be(3)
- }
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph) { _ =>
- degree(1) should be(4)
- degree(2) should be(5)
- degree(3) should be(3)
- }
- }
- }
-
- def `for total graph`: Unit = {
- emptyG.totalDegree shouldBe 0;
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph)(_.totalDegree shouldBe degrees.sum)
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph)(_.totalDegree shouldBe degrees.sum)
- }
- }
- }
-
- object `Degree statistics are calculated properly for` {
- def `minimum degree`: Unit = {
- emptyG.minDegree should be(0);
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph)(_.minDegree should be(degrees.min))
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph)(_.minDegree should be(degrees.min))
- }
- }
-
- def `maximum degree`: Unit = {
- emptyG.maxDegree should be(0);
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph)(_.maxDegree should be(degrees.max))
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph)(_.maxDegree should be(degrees.max))
- }
- }
-
- def `sequence of degrees`: Unit = {
- emptyG.degreeSeq should be(Seq.empty);
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph)(_.degreeSeq should be(expectedDegreeSeq))
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph)(_.degreeSeq should be(expectedDegreeSeq))
- }
- }
-
- def `set of degrees`: Unit = {
- emptyG.degreeSet should be(Set.empty);
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph)(_.degreeSet should be(expectedDegreeSet))
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph)(_.degreeSet should be(expectedDegreeSet))
- }
- }
-
- def `sequence of nodes sorted by degree`: Unit = {
- emptyG.degreeNodeSeq should be(Seq.empty);
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph) { g =>
- val ord = new Ordering[g.DegreeNodeSeqEntry] {
- def compare(a: g.DegreeNodeSeqEntry, b: g.DegreeNodeSeqEntry) = {
- def sortKey(e: g.DegreeNodeSeqEntry) = 100 * e._1 + e._2
-
- sortKey(b) compare sortKey(a)
- }
- }
-
- val ds = g.degreeNodeSeq
- val dsSorted = ds.toList sorted ord
- dsSorted should be(expectedDegreeNodeSeq)
-
- val ids = g.degreeNodeSeq(g.InDegree)
- val idsSorted = ids.toList sorted ord
- idsSorted should be(expectedInDegreeNodeSeq)
- }
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph)(_.degreeNodeSeq should be(expectedDegreeNodeSeq))
- }
- }
-
- def `map of nodes by degree`: Unit = {
- emptyG.degreeNodesMap should be(Map.empty);
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph) { g =>
- g.degreeNodesMap should be(expectedDegreeNodesMap)
- g.degreeNodesMap(degreeFilter = _ > 3) should be(expectedDegreeGT3NodesMap)
- }
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph) { g =>
- g.degreeNodesMap should be(expectedDegreeNodesMap)
- }
- }
- }
-
- def `map of degree by node`: Unit = {
- emptyG.degreeCount should be(Map.empty);
- {
- import UnDi_1.*
- withGraph(g.asAnyGraph)(_.degreeCount should be(expectedDegreeCount))
- }
- {
- import UnDi_2.*
- withGraph(g.asAnyGraph)(_.degreeCount should be(expectedDegreeCount))
- }
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/EditingHyperSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/EditingHyperSpec.scala
deleted file mode 100644
index ac12f855..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/EditingHyperSpec.scala
+++ /dev/null
@@ -1,170 +0,0 @@
-package scalax.collection
-
-import org.scalatest.Suites
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.OneOrMore.{more, one}
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.*
-import scalax.collection.hyperedges.*
-
-/** Editing any kind of hypergraph with unlabeled edges including mixed and multigraphs.
- */
-class EditingHyperSpec
- extends Suites(
- new EditingHyper[immutable.Graph](immutable.Graph),
- new EditingHyper[mutable.Graph](mutable.Graph),
- new EditingHyperMutable
- )
-
-private class EditingHyper[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]](
- val factory: GenericGraphCoreFactory[CC]
-) extends RefSpec
- with Matchers {
-
- object `hypergraph editing` {
-
- def `create HyperEdge`: Unit = {
- "HyperEdge(List(1))" shouldNot compile
- "HyperEdge(List(1): _*)" shouldNot compile
-
- HyperEdge.from(List(1)) shouldBe None
- an[IllegalArgumentException] shouldBe thrownBy {
- HyperEdge.fromUnsafe(List(1))
- }
-
- val h = HyperEdge(1, 2, 3)
- 1 ~~ 2 ~~ 3 shouldEqual h
- h.arity shouldBe 3
- h.toString shouldBe "1 ~~ 2 ~~ 3"
-
- val g = factory[Int, AnyHyperEdge](1, h, 1 ~ 2)
- g.nodes should have size 3
- g.edges should have size 2
- g.elementCount should be(5)
- g.contains(h) should be(true)
- }
-
- def `create DiHyperEdge`: Unit = {
- "DiHyperEdge(List(1), List(1)): DiHyperEdge[Int]" shouldNot compile
- "DiHyperEdge(List(1): _*)(): DiHyperEdge[Int]" shouldNot compile
-
- DiHyperEdge.from(List(1), Nil) shouldBe None
- an[IllegalArgumentException] shouldBe thrownBy {
- DiHyperEdge.fromUnsafe(List(1), Nil)
- }
-
- val sources = more(1, 2)
- val targets = more(2, 3)
- val h = DiHyperEdge(sources, targets)
-
- DiHyperEdge.from(List(1, 2), List(2, 3)) shouldEqual Some(h)
- DiHyperEdge.from(List(1, 2), Nil) shouldEqual None
- sources ~~> targets shouldEqual h
- h.arity shouldBe sources.size + targets.size
- h.toString shouldBe "{1, 2} ~~> {2, 3}"
-
- single ~~> targets shouldEqual DiHyperEdge(single, targets)
- sources ~~> single shouldEqual DiHyperEdge(sources, single)
- single ~~> single shouldEqual DiHyperEdge(1)(1)
-
- val g = factory[Int, AnyHyperEdge](1, h, 1 ~ 2)
- g.nodes should have size 3
- g.edges should have size 2
- g.elementCount shouldBe 5
- g.contains(h) shouldBe true
- }
-
- def `isHyper ` : Unit = {
- def test(g: CC[Int, AnyHyperEdge[Int]], expected: Boolean): Unit = g.isHyper should be(expected)
-
- test(factory.from[Int, AnyHyperEdge](List(1 ~> 2, 1 ~~ 2 ~~ 3)), true)
- test(factory.from[Int, AnyHyperEdge](1 ~ 2 :: Nil), false)
- test(factory.from[Int, AnyHyperEdge](1 ~> 2 :: Nil), false)
- }
- }
-
- val single = one(1)
- val hDi = factory(
- single ~~> more(1, 5),
- single ~~> more(2, 5),
- single ~~> more(3, 5),
- single ~~> more(4, 9)
- )
-
- object `diSuccessors ` {
- def `for DiHyper`: Unit = {
- (hDi get 1).diSuccessors shouldEqual Set(2, 3, 4, 5, 9)
- (hDi get 2).diSuccessors shouldEqual Set.empty
- (hDi get 5).diSuccessors shouldEqual Set.empty
- }
- }
-
- object `diPredecessors ` {
- def `for DiHyper`: Unit = {
- (hDi get 1).diPredecessors should be(Set.empty)
- (hDi get 2).diPredecessors should be(Set(1))
- (hDi get 5).diPredecessors should be(Set(1))
- }
- }
-
- object `neighbors ` {
- def `for DiHyper`: Unit = {
- (hDi get 1).neighbors should be(Set(2, 3, 4, 5, 9))
- (hDi get 2).neighbors should be(Set(1, 5))
- (hDi get 5).neighbors should be(Set(1, 2, 3))
- }
- }
-
- def `match hyperedge`: Unit = {
- val HyperEdge(Several.Seq(n1, n2, n3)) = 1 ~~ 2 ~~ 3
- n1 + n2 + n3 shouldBe 6
- }
-
- def `match directed hyperedge`: Unit = {
- val count = 4
- val sources = OneOrMore.fromUnsafe(List.tabulate(count - 1)(_ + 1))
- val target = one(count)
- val diHyper = sources ~~> target
-
- val OneOrMore.Seq(s1, _*) ~~> (t @ OneOrMore.Seq(c)) = diHyper: @unchecked
- s1 shouldBe sources.head
- c shouldBe count
- t shouldBe target
- }
-}
-
-private class EditingHyperMutable extends RefSpec with Matchers {
- import mutable.Graph
-
- object `mutable graphs with labeled edges` {
- def `'diSuccessors' when directed hypergraph`: Unit = {
- val (_1_to_1_2, _1_to_2_3) = (
- one(1) ~~> more(1, 2),
- one(1) ~~> more(2, 3)
- )
- val g = Graph(_1_to_1_2, _1_to_2_3)
- val (n1, n2) = (g get 1, g get 2)
-
- n2.diSuccessors shouldBe empty
- n1.diSuccessors should be(Set(2, 3))
- n1 findOutgoingTo n1 should be(Some(_1_to_1_2))
-
- g subtractOne _1_to_2_3
- g shouldEqual Graph(_1_to_1_2, 3)
- n1.diSuccessors should be(Set(2))
- n1 findOutgoingTo n1 should be(Some(_1_to_1_2))
-
- g subtractOne 2
- g shouldEqual Graph(1, 3)
- n1.diSuccessors shouldBe empty
- n1 findOutgoingTo n1 should be(None)
-
- g += _1_to_1_2
- g shouldEqual Graph(_1_to_1_2, 3)
- n1.diSuccessors should be(Set(2))
- n1 findOutgoingTo n1 should be(Some(_1_to_1_2))
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/EditingLabeledHyperSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/EditingLabeledHyperSpec.scala
deleted file mode 100644
index 5543bb3a..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/EditingLabeledHyperSpec.scala
+++ /dev/null
@@ -1,550 +0,0 @@
-package scalax.collection
-
-import org.scalatest.Suites
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.Data.shuffleNotEqual
-import scalax.collection.OneOrMore.more
-import scalax.collection.generic.{Edge, GenericGraphCoreFactory}
-
-/** Editing hypergraphs with labeled edges including support for multi-hypergraphs.
- */
-class EditingLabeledHyperSpec
- extends Suites(
- new LabeledHyperEdges,
- new EditingLabeledHyperEdges[immutable.Graph](immutable.Graph),
- new EditingLabeledHyperEdges[mutable.Graph](mutable.Graph)
- )
-
-object EditingLabeledHyperSpec {
- object Labeled {
- import hyperedges.labeled.*
-
- case class MyHyperEdge[+N](override val ends: Several[N], label: Int)
- extends LHyperEdge[N, Int](ends)
- with GenericHyperEdgeMapper[MyHyperEdge] {
- def map[N](ends: Several[N]): MyHyperEdge[N] = copy(ends)
- }
-
- val ends = Several('a', 'b', 'c')
- val label = 1
- val hE = MyHyperEdge(ends, label)
- }
-
- object OrderedLabeled {
- import hyperedges.ordered.labeled.*
-
- case class MyHyperEdge[+N](override val ends: Several[N], label: Int)
- extends LHyperEdge[N, Int](ends)
- with GenericHyperEdgeMapper[MyHyperEdge] {
- def map[N](ends: Several[N]): MyHyperEdge[N] = copy(ends)
- }
-
- val ends = Labeled.ends
- val label = Labeled.label
- val hE = MyHyperEdge(ends, label)
- }
-
- object LabeledDi {
- import hyperedges.labeled.*
-
- case class MyDiHyperEdge[+N](override val sources: OneOrMore[N], override val targets: OneOrMore[N], label: Int)
- extends LDiHyperEdge[N, Int](sources, targets)
- with GenericDiHyperEdgeMapper[MyDiHyperEdge] {
- def map[N](sources: OneOrMore[N], targets: OneOrMore[N]): MyDiHyperEdge[N] = copy(sources, targets)
- }
-
- val sources = more('a', 'b')
- val targets = more('c', 'd')
- val label = 1
- val diHE = MyDiHyperEdge(sources, targets, label)
- }
-
- object OrderedLabeledDi {
- import hyperedges.ordered.labeled.*
-
- case class MyDiHyperEdge[+N](override val sources: OneOrMore[N], override val targets: OneOrMore[N], label: Int)
- extends LDiHyperEdge[N, Int](sources, targets)
- with GenericDiHyperEdgeMapper[MyDiHyperEdge] {
- def map[N](sources: OneOrMore[N], targets: OneOrMore[N]): MyDiHyperEdge[N] = copy(sources, targets)
- }
-
- val sources = more('a', 'b', 'x')
- val targets = more('c', 'd')
- val label = 1
- val diHE = MyDiHyperEdge(sources, targets, label)
- }
-
- object MultiLabeled {
- import hyperedges.multilabeled.*
-
- case class MyHyperEdge[+N](override val ends: Several[N], label: Int)
- extends LHyperEdge[N, Int](ends)
- with GenericHyperEdgeMapper[MyHyperEdge] {
- def map[N](ends: Several[N]): MyHyperEdge[N] = copy(ends)
- }
-
- val ends = Labeled.ends
- val label = Labeled.label
- val hE = MyHyperEdge(ends, label)
- }
-
- object MultiOrderedLabeled {
- import hyperedges.ordered.multilabeled.*
-
- case class MyHyperEdge[+N](override val ends: Several[N], label: Int)
- extends LHyperEdge[N, Int](ends)
- with GenericHyperEdgeMapper[MyHyperEdge] {
- def map[N](ends: Several[N]): MyHyperEdge[N] = copy(ends)
- }
-
- val ends = Labeled.ends
- val label = Labeled.label
- val hE = MyHyperEdge(ends, label)
- }
-
- object MultiLabeledDi {
- import hyperedges.multilabeled.*
-
- case class MyDiHyperEdge[+N](override val sources: OneOrMore[N], override val targets: OneOrMore[N], label: Int)
- extends LDiHyperEdge[N, Int](sources, targets)
- with GenericDiHyperEdgeMapper[MyDiHyperEdge] {
- def map[N](sources: OneOrMore[N], targets: OneOrMore[N]): MyDiHyperEdge[N] = copy(sources, targets)
- }
-
- val sources = LabeledDi.sources
- val targets = LabeledDi.targets
- val label = LabeledDi.label
- val diHE = MyDiHyperEdge(sources, targets, label)
- }
-
- object MultiOrderedLabeledDi {
- import hyperedges.ordered.multilabeled.*
-
- case class MyDiHyperEdge[+N](override val sources: OneOrMore[N], override val targets: OneOrMore[N], label: Int)
- extends LDiHyperEdge[N, Int](sources, targets)
- with GenericDiHyperEdgeMapper[MyDiHyperEdge] {
- def map[N](sources: OneOrMore[N], targets: OneOrMore[N]): MyDiHyperEdge[N] = copy(sources, targets)
- }
-
- val sources = OrderedLabeledDi.sources
- val targets = OrderedLabeledDi.targets
- val label = OrderedLabeledDi.label
- val diHE = MyDiHyperEdge(sources, targets, label)
- }
-
- def endsToString(ends: OneOrMore[_]) = ends.iterator.mkString("{", ", ", "}")
-}
-
-private class LabeledHyperEdges extends RefSpec with Matchers {
- import EditingLabeledHyperSpec.endsToString
-
- object `a generic undirected, mappable labeled hyperedge` {
- import EditingLabeledHyperSpec.Labeled.*
- import hyperedges.*
- import hyperedges.labeled.*
-
- def `meets toString convention`: Unit =
- hE.toString shouldBe s"${ends.iterator mkString " ~~ "} :+ 1"
-
- def `meets equality rules`: Unit = {
- hE.copy(label = 9) shouldEqual hE
- hE shouldEqual HyperEdge(hE.ends)
- hE shouldEqual HyperEdge(shuffleNotEqual(hE.ends))
- }
-
- def `supports infix construction`: Unit = {
- implicit class MyInfixConstructor[N](val hyperedge: HyperEdge[N])
- extends LHyperEdgeInfixConstructor[N, Int, MyHyperEdge](MyHyperEdge.apply)
- 'a' ~~ 'b' ~~ 'c' :+ 1 shouldEqual hE
- }
-
- def `supports infix extraction`: Unit = {
- val +: = MyHyperEdge
-
- hE match {
- case ends +: label =>
- val reconstructed = MyHyperEdge(ends, label)
- "reconstructed: MyHyperEdge[Char]" should compile
- reconstructed shouldEqual hE
- }
- hE match {
- case Several.Seq(n1, n2, n3) +: label =>
- val reconstructed = MyHyperEdge(Several(n1, n2, n3 :: Nil), label)
- "reconstructed: MyHyperEdge[Char]" should compile
- reconstructed shouldEqual hE
- case _ +: _ => fail()
- }
- }
- }
-
- object `generic undirected, mappable, ordered labeled hyperedge` {
- import EditingLabeledHyperSpec.OrderedLabeled.*
- import hyperedges.*
- import hyperedges.ordered.labeled.*
-
- def `meets toString convention`: Unit =
- hE.toString shouldBe s"${ends.iterator mkString " ~~ "} :+ 1"
-
- def `meets equality rules`: Unit = {
- hE.copy(label = 9) shouldEqual hE
- hE.copy(ends = shuffleNotEqual(hE.ends)) shouldNot equal(hE)
- hE shouldNot equal(HyperEdge(hE.ends))
- }
-
- def `supports infix construction`: Unit = {
- implicit class MyInfixConstructor[N](val hyperedge: HyperEdge[N])
- extends LHyperEdgeInfixConstructor[N, Int, MyHyperEdge](MyHyperEdge.apply)
- 'a' ~~ 'b' ~~ 'c' :+ 1 shouldEqual hE
- }
-
- def `supports infix extraction`: Unit = {
- val +: = MyHyperEdge
-
- hE match {
- case ends +: label =>
- val reconstructed = MyHyperEdge(ends, label)
- "reconstructed: MyHyperEdge[Char]" should compile
- reconstructed shouldEqual hE
- }
- hE match {
- case Several.Seq(n1, n2, n3) +: label =>
- val reconstructed = MyHyperEdge(Several(n1, n2, n3 :: Nil), label)
- "reconstructed: MyHyperEdge[Char]" should compile
- reconstructed shouldEqual hE
- case _ +: _ => fail()
- }
- }
- }
-
- object `generic directed, mappable labeled hyperedge` {
- import EditingLabeledHyperSpec.LabeledDi.*
- import hyperedges.*
- import hyperedges.labeled.*
-
- def `meets toString convention`: Unit =
- diHE.toString shouldBe s"${endsToString(sources)} ~~> ${endsToString(targets)} :+ $label"
-
- def `meets equality rules`: Unit = {
- diHE.copy(label = 9) shouldEqual diHE
- diHE shouldEqual DiHyperEdge(diHE.sources, diHE.targets)
- diHE shouldEqual DiHyperEdge(shuffleNotEqual(diHE.sources), shuffleNotEqual(diHE.targets))
- }
-
- def `supports infix construction`: Unit = {
- implicit class MyInfixConstructor[N](val diHyperedge: DiHyperEdge[N])
- extends LDiHyperEdgeInfixConstructor[N, Int, MyDiHyperEdge](MyDiHyperEdge.apply)
- sources ~~> targets :+ 1 shouldEqual diHE
- }
-
- def `supports infix extraction`: Unit = {
- import generic.{UnapplyGenericHyperLabel, UnapplyGenericLabeledDiHyperEdge}
- object :~~> extends UnapplyGenericLabeledDiHyperEdge[MyDiHyperEdge, Int]
- object +: extends UnapplyGenericHyperLabel[Int]
-
- diHE match {
- case sources :~~> targets +: label =>
- val reconstructed = MyDiHyperEdge(sources, targets, label)
- "reconstructed: MyDiHyperEdge[Char]" should compile
- reconstructed shouldEqual diHE
- }
- diHE match {
- case OneOrMore.Seq(s1, s2, _*) :~~> OneOrMore.Seq(t1, t2, _*) +: label =>
- val reconstructed = MyDiHyperEdge(
- more(s1, s2),
- more(t1, t2),
- label
- )
- "reconstructed: MyDiHyperEdge[Char]" should compile
- reconstructed shouldEqual diHE
- case _ :~~> _ +: _ => fail()
- }
- }
- }
-
- object `generic directed, mappable, ordered labeled hyperedge` {
- import EditingLabeledHyperSpec.OrderedLabeledDi.*
- import hyperedges.*
- import hyperedges.ordered.labeled.*
-
- def `meets toString convention`: Unit =
- diHE.toString shouldBe s"${endsToString(sources)} ~~> ${endsToString(targets)} :+ $label"
-
- def `meets equality rules`: Unit = {
- diHE.copy(label = 9) shouldEqual diHE
- diHE shouldNot equal(DiHyperEdge(diHE.sources, diHE.targets))
- diHE shouldNot equal(DiHyperEdge(shuffleNotEqual(diHE.sources), shuffleNotEqual(diHE.targets)))
- }
-
- def `supports infix construction`: Unit = {
- implicit class MyInfixConstructor[N](val diHyperedge: DiHyperEdge[N])
- extends LDiHyperEdgeInfixConstructor[N, Int, MyDiHyperEdge](MyDiHyperEdge.apply)
- sources ~~> targets :+ 1 shouldEqual diHE
- }
-
- def `supports infix extraction`: Unit = {
- import generic.{UnapplyGenericHyperLabel, UnapplyGenericLabeledDiHyperEdge}
- object :~~> extends UnapplyGenericLabeledDiHyperEdge[MyDiHyperEdge, Int]
- object +: extends UnapplyGenericHyperLabel[Int]
-
- diHE match {
- case sources :~~> targets +: label =>
- val reconstructed = MyDiHyperEdge(sources, targets, label)
- "reconstructed: MyDiHyperEdge[Char]" should compile
- reconstructed shouldEqual diHE
- }
- diHE match {
- case OneOrMore.Seq(s1, s2, sRest @ _*) :~~> OneOrMore.Seq(t1, t2, tRest @ _*) +: label =>
- val reconstructed = MyDiHyperEdge(
- more(s1, s2, sRest: _*),
- more(t1, t2, tRest: _*),
- label
- )
- "reconstructed: MyDiHyperEdge[Char]" should compile
- reconstructed shouldEqual diHE
- case _ :~~> _ +: _ => fail()
- }
- }
- }
-
- object `a generic undirected, mappable multilabeled hyperedge` {
- import EditingLabeledHyperSpec.MultiLabeled.*
- import hyperedges.*
- import hyperedges.multilabeled.*
-
- def `meets toString convention`: Unit =
- hE.toString shouldBe s"${ends.iterator mkString " ~~ "} :++ 1"
-
- def `meets equality rules`: Unit = {
- hE.copy(label = 9) shouldNot equal(hE)
- hE shouldNot equal(HyperEdge(hE.ends))
- }
-
- def `supports infix construction`: Unit = {
- implicit class MyInfixConstructor[N](val hyperedge: HyperEdge[N])
- extends LHyperEdgeInfixConstructor[N, Int, MyHyperEdge](MyHyperEdge.apply)
- 'a' ~~ 'b' ~~ 'c' :++ 1 shouldEqual hE
- }
-
- def `supports infix extraction`: Unit = {
- val ++ = MyHyperEdge
-
- hE match {
- case ends ++ label =>
- val reconstructed = MyHyperEdge(ends, label)
- "reconstructed: MyHyperEdge[Char]" should compile
- reconstructed shouldEqual hE
- }
- hE match {
- case Several.Seq(n1, n2, n3) ++ label =>
- val reconstructed = MyHyperEdge(Several(n1, n2, n3 :: Nil), label)
- "reconstructed: MyHyperEdge[Char]" should compile
- reconstructed shouldEqual hE
- case _ ++ _ => fail()
- }
- }
- }
-
- object `generic undirected, mappable, ordered multilabeled hyperedge` {
- import EditingLabeledHyperSpec.MultiOrderedLabeled.*
- import hyperedges.*
- import hyperedges.ordered.multilabeled.*
-
- def `meets toString convention`: Unit =
- hE.toString shouldBe s"${ends.iterator mkString " ~~ "} :++ 1"
-
- def `meets equality rules`: Unit = {
- hE.copy(label = 9) shouldNot equal(hE)
- hE.copy(ends = shuffleNotEqual(hE.ends)) shouldNot equal(hE)
- hE shouldNot equal(HyperEdge(hE.ends))
- }
-
- def `supports infix construction`: Unit = {
- implicit class MyInfixConstructor[N](val hyperedge: HyperEdge[N])
- extends LHyperEdgeInfixConstructor[N, Int, MyHyperEdge](MyHyperEdge.apply)
- 'a' ~~ 'b' ~~ 'c' :++ 1 shouldEqual hE
- }
-
- def `supports infix extraction`: Unit = {
- val ++ = MyHyperEdge
-
- hE match {
- case ends ++ label =>
- val reconstructed = MyHyperEdge(ends, label)
- "reconstructed: MyHyperEdge[Char]" should compile
- reconstructed shouldEqual hE
- }
- hE match {
- case Several.Seq(n1, n2, n3) ++ label =>
- val reconstructed = MyHyperEdge(Several(n1, n2, n3 :: Nil), label)
- "reconstructed: MyHyperEdge[Char]" should compile
- reconstructed shouldEqual hE
- case _ ++ _ => fail()
- }
- }
- }
-
- object `generic directed, mappable multilabeled hyperedge` {
- import EditingLabeledHyperSpec.MultiLabeledDi.*
- import hyperedges.*
- import hyperedges.multilabeled.*
-
- def `meets toString convention`: Unit =
- diHE.toString shouldBe s"${endsToString(sources)} ~~> ${endsToString(targets)} :++ $label"
-
- def `meets equality rules`: Unit = {
- diHE.copy(label = 9) shouldNot equal(diHE)
- diHE shouldNot equal(DiHyperEdge(diHE.sources, diHE.targets))
- }
-
- def `supports infix construction`: Unit = {
- implicit class MyInfixConstructor[N](val diHyperedge: DiHyperEdge[N])
- extends LDiHyperEdgeInfixConstructor[N, Int, MyDiHyperEdge](MyDiHyperEdge.apply)
- sources ~~> targets :++ 1 shouldEqual diHE
- }
-
- def `supports infix extraction`: Unit = {
- import generic.{UnapplyGenericHyperLabel, UnapplyGenericLabeledDiHyperEdge}
- object :~~> extends UnapplyGenericLabeledDiHyperEdge[MyDiHyperEdge, Int]
- object ++: extends UnapplyGenericHyperLabel[Int]
-
- diHE match {
- case sources :~~> targets ++: label =>
- val reconstructed = MyDiHyperEdge(sources, targets, label)
- "reconstructed: MyDiHyperEdge[Char]" should compile
- reconstructed shouldEqual diHE
- }
- diHE match {
- case OneOrMore.Seq(s1, s2, _*) :~~> OneOrMore.Seq(t1, t2, _*) ++: label =>
- val reconstructed = MyDiHyperEdge(
- more(s1, s2),
- more(t1, t2),
- label
- )
- "reconstructed: MyDiHyperEdge[Char]" should compile
- reconstructed shouldEqual diHE
- case _ :~~> _ ++: _ => fail()
- }
- }
- }
-
- object `generic directed, mappable, ordered multilabeled hyperedge` {
- import EditingLabeledHyperSpec.MultiOrderedLabeledDi.*
- import hyperedges.*
- import hyperedges.ordered.multilabeled.*
-
- def `meets toString convention`: Unit =
- diHE.toString shouldBe s"${endsToString(sources)} ~~> ${endsToString(targets)} :++ $label"
-
- def `meets equality rules`: Unit = {
- diHE.copy(label = 9) shouldNot equal(diHE)
- diHE.copy(shuffleNotEqual(diHE.sources), shuffleNotEqual(diHE.targets)) shouldNot equal(diHE)
- diHE shouldNot equal(DiHyperEdge(diHE.sources, diHE.targets))
- }
-
- def `supports infix construction`: Unit = {
- implicit class MyInfixConstructor[N](val diHyperedge: DiHyperEdge[N])
- extends LDiHyperEdgeInfixConstructor[N, Int, MyDiHyperEdge](MyDiHyperEdge.apply)
- sources ~~> targets :++ 1 shouldEqual diHE
- }
-
- def `supports infix extraction`: Unit = {
- import generic.{UnapplyGenericHyperLabel, UnapplyGenericLabeledDiHyperEdge}
- object :~~> extends UnapplyGenericLabeledDiHyperEdge[MyDiHyperEdge, Int]
- object ++: extends UnapplyGenericHyperLabel[Int]
-
- diHE match {
- case sources :~~> targets ++: label =>
- val reconstructed = MyDiHyperEdge(sources, targets, label)
- "reconstructed: MyDiHyperEdge[Char]" should compile
- reconstructed shouldEqual diHE
- }
- diHE match {
- case OneOrMore.Seq(s1, s2, sRest @ _*) :~~> OneOrMore.Seq(t1, t2, tRest @ _*) ++: label =>
- val reconstructed = MyDiHyperEdge(
- more(s1, s2, sRest: _*),
- more(t1, t2, tRest: _*),
- label
- )
- "reconstructed: MyDiHyperEdge[Char]" should compile
- reconstructed shouldEqual diHE
- case _ :~~> _ ++: _ => fail()
- }
- }
- }
-}
-
-private class EditingLabeledHyperEdges[G[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, G]](
- val factory: GenericGraphCoreFactory[G]
-) extends RefSpec
- with Matchers {
-
- object `a generic undirected, mappable labeled edge` {
- import EditingLabeledHyperSpec.Labeled.*
-
- def `is mappable`: Unit = {
- val g = factory.from(hE :: Nil)
- g.map(_.toString).edges.toOuter.head shouldBe hE.copy(ends = hE.ends.map(_.toString))
- }
- }
-
- object `generic undirected, mappable, ordered labeled edge` {
- import EditingLabeledHyperSpec.OrderedLabeled.*
-
- def `is mappable`: Unit = {
- val g = factory.from(hE :: Nil)
- g.map(_.toString).edges.toOuter.head shouldBe hE.copy(ends = hE.ends.map(_.toString))
- }
- }
-
- object `generic directed, mappable labeled edge` {
- import EditingLabeledHyperSpec.LabeledDi.*
-
- def `is mappable`: Unit = {
- val g = factory.from(diHE :: Nil)
- g.map(_.toString).edges.toOuter.head shouldBe diHE
- .copy(diHE.sources.map(_.toString), diHE.targets.map(_.toString))
- }
- }
-
- object `generic directed, mappable, ordered labeled edge` {
- import EditingLabeledHyperSpec.OrderedLabeledDi.*
-
- def `is mappable`: Unit = {
- val g = factory.from(diHE :: Nil)
- g.map(_.toString).edges.toOuter.head shouldBe diHE
- .copy(diHE.sources.map(_.toString), diHE.targets.map(_.toString))
- }
- }
-}
-
-/* TODO
-private class EditingLabeledHyperMutable extends RefSpec with Matchers {
- object `mutable graphs with labeled edges` {
- def `satisfy labeled directed hyperedege equality` {
- import edge.Implicits._
- import edge.LHyperEdge
-
- type StringLabel = String
- val outerLabels = Seq("A", "BC", "CDE")
- val g = mutable.Graph(1 ~ 2 ~ 3, (2 ~+# 3) (outerLabels(0)))
-
- implicit val factory = LHyperEdge
- (g +~+= (3, 4, 5)) (outerLabels(1))
- g should have('order(5), 'size(3))
- g.addLEdge(4, 5, 6)(outerLabels(2)) should be(true)
- g should have('order(6), 'size(4))
-
- val innerLabels: collection.mutable.Set[_ >: StringLabel] =
- g.edges filter (_.isLabeled) map (_.label)
- innerLabels should have size (outerLabels.size)
- /*
- innerLabels forall (outerLabels contains _) should be (true)
- * https://groups.google.com/forum/?fromgroups=#!searchin/scala-internals/both$20method/scala-internals/nPZY2EMtDvY/PivCCtyRM_IJ
- * https://issues.scala-lang.org/browse/SI-5330
- */
- (innerLabels: Iterable[Any]) forall (outerLabels contains _) should be(true)
- }
- }
-}
- */
diff --git a/coreTestScala3/src/test/scala/scalax/collection/EditingLabeledSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/EditingLabeledSpec.scala
deleted file mode 100644
index f4f6f166..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/EditingLabeledSpec.scala
+++ /dev/null
@@ -1,308 +0,0 @@
-package scalax.collection
-
-import org.scalatest.Suites
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.edges.{DiEdge, UnDiEdge}
-import scalax.collection.generic.{Edge, GenericGraphCoreFactory}
-
-/** Editing non-hypergraphs with labeled edges, in particular, editing multigraphs.
- */
-class EditingLabeledSpec
- extends Suites(
- new LabeledEdges,
- new EditingLabeledEdges[immutable.Graph](immutable.Graph),
- new EditingLabeledEdges[mutable.Graph](mutable.Graph)
- )
-
-private class LabeledEdges extends RefSpec with Matchers {
-
- def `toString of labeled edge`: Unit = {
- import edges.labeled.*
-
- WUnDiEdge('a', 'b', 2).toString shouldBe "a ~ b % 2.0"
- WUnDiEdge("A", "B", 3).toString shouldBe "A ~ B % 3.0"
- }
-
- def `toString of multilabeled edge`: Unit = {
- import edges.multilabeled.*
-
- WUnDiEdge('a', 'b', 2).toString shouldBe "a ~ b %% 2.0"
- WUnDiEdge("A", "B", 3).toString shouldBe "A ~ B %% 3.0"
- }
-
- def `mixed infix constructors`: Unit = {
- import edges.UnDiEdgeImplicits
- import edges.labeled.*
- import edges.multilabeled.*
-
- 1 ~ 2 % 3.2 shouldBe a[edges.labeled.WUnDiEdge[_]]
- 1 ~ 2 %% 3.2 shouldBe a[edges.multilabeled.WUnDiEdge[_]]
- }
-
- def `mixed infix extractors`: Unit = {
- import edges.UnDiEdgeImplicits
- import edges.labeled.*
- import edges.multilabeled.*
-
- 1 ~ 2 % 3.2 match {
- case n1 :~ n2 % w => (n1, n2, w) shouldBe (1, 2, 3.2)
- }
- 1 ~ 2 %% 3.2 match {
- case n1 ::~ n2 %% w => (n1, n2, w) shouldBe (1, 2, 3.2)
- }
- }
-}
-
-private class EditingLabeledEdges[G[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, G]](
- val factory: GenericGraphCoreFactory[G]
-) extends RefSpec
- with Matchers {
-
- def `generic directed labeled edge`: Unit = {
- import edges.labeled.LDiEdge
-
- case class MyEdge[+N](source: N, target: N, label: String) extends LDiEdge[N, String]
-
- val e = MyEdge(1, 2, "")
- e shouldEqual DiEdge(1, 2)
-
- val g = factory.from(e :: Nil)
- "g.map(_.toString)" shouldNot compile
- }
-
- def `generic directed, mappable labeled edge`: Unit = {
- import edges.labeled.*
-
- case class MyEdge[+N](source: N, target: N, label: String)
- extends LDiEdge[N, String]
- with GenericEdgeMapper[MyEdge] {
- def map[N](source: N, target: N) = copy(source, target)
- }
-
- val e = MyEdge(1, 2, "")
- e shouldEqual DiEdge(1, 2)
-
- val g = factory.from(e :: Nil)
- g.map(_.toString).edges.toOuter.head shouldBe MyEdge("1", "2", "")
-
- import edges.DiEdgeImplicits
- implicit class MyInfixConstructor[N](val edge: DiEdge[N])
- extends LDiEdgeInfixConstructor[N, String, MyEdge](MyEdge.apply)
- 1 ~> 2 :+ "" shouldEqual e
-
- import generic.{UnapplyGenericLabel, UnapplyGenericLabeledEdge}
- object :~> extends UnapplyGenericLabeledEdge[MyEdge, String]
- object +: extends UnapplyGenericLabel[String]
-
- e match {
- case n1 :~> n2 +: label =>
- val reconstructed = MyEdge(n1, n2, label)
- "reconstructed: MyEdge[Int]" should compile
- reconstructed shouldEqual e
- }
- }
-
- def `generic undirected labeled edge`: Unit = {
- import edges.labeled.LUnDiEdge
-
- case class MyEdge[+N](source: N, target: N, label: String) extends LUnDiEdge[N, String]
-
- val e = MyEdge(1, 2, "")
- e shouldEqual UnDiEdge(1, 2)
-
- val g = factory.from(e :: Nil)
- "g.map(_.toString)" shouldNot compile
- }
-
- def `generic undirected, mappable labeled edge`: Unit = {
- import edges.labeled.*
-
- case class MyEdge[+N](source: N, target: N, label: String)
- extends LUnDiEdge[N, String]
- with GenericEdgeMapper[MyEdge] {
- def map[N](node_1: N, node_2: N) = copy(node_1, node_2)
- }
-
- val e = MyEdge(1, 2, "")
- e shouldEqual UnDiEdge(1, 2)
-
- val g = factory.from(e :: Nil)
- g.map(_.toString).edges.toOuter.head shouldBe MyEdge("1", "2", "")
-
- import edges.UnDiEdgeImplicits
- implicit class MyInfixConstructor[N](val edge: UnDiEdge[N])
- extends LUnDiEdgeInfixConstructor[N, String, MyEdge](MyEdge.apply)
- 1 ~ 2 :+ "" shouldEqual e
-
- import generic.{UnapplyGenericLabel, UnapplyGenericLabeledEdge}
- object :~ extends UnapplyGenericLabeledEdge[MyEdge, String]
- object +: extends UnapplyGenericLabel[String]
-
- e match {
- case n1 :~ n2 +: label =>
- val reconstructed = MyEdge(n1, n2, label)
- "reconstructed: MyEdge[Int]" should compile
- reconstructed shouldEqual e
- }
- }
-
- def `generic directed labeled multiedge`: Unit = {
- import edges.multilabeled.LDiEdge
-
- case class MyEdge[+N](source: N, target: N, label: String) extends LDiEdge[N, String]
-
- val e = MyEdge(1, 2, "")
- e shouldNot equal(DiEdge(1, 2))
-
- val g = factory.from(e :: Nil)
- "g.map(_.toString)" shouldNot compile
- }
-
- def `generic directed, mappable labeled multiedge`: Unit = {
- import edges.multilabeled.*
-
- case class MyEdge[+N](source: N, target: N, label: String)
- extends LDiEdge[N, String]
- with GenericEdgeMapper[MyEdge] {
- def map[N](source: N, target: N) = copy(source, target)
- }
-
- val e = MyEdge(1, 2, "")
- e shouldNot equal(DiEdge(1, 2))
-
- val g = factory.from(e :: Nil)
- g.map(_.toString).edges.toOuter.head shouldBe MyEdge("1", "2", "")
-
- import edges.DiEdgeImplicits
- implicit class MyInfixConstructor[N](val edge: DiEdge[N])
- extends LDiEdgeInfixConstructor[N, String, MyEdge](MyEdge.apply)
- 1 ~> 2 :++ "" shouldEqual e
-
- import generic.{UnapplyGenericLabel, UnapplyGenericLabeledEdge}
- object :~> extends UnapplyGenericLabeledEdge[MyEdge, String]
- object ++: extends UnapplyGenericLabel[String]
-
- e match {
- case n1 :~> n2 ++: label =>
- val reconstructed = MyEdge(n1, n2, label)
- "reconstructed: MyEdge[Int]" should compile
- reconstructed shouldEqual e
- }
- }
-
- def `generic undirected labeled multiedge`: Unit = {
- import edges.multilabeled.LUnDiEdge
-
- case class MyEdge[+N](source: N, target: N, label: String) extends LUnDiEdge[N, String]
-
- val e = MyEdge(1, 2, "")
- e shouldNot equal(UnDiEdge(1, 2))
-
- val g = factory.from(e :: Nil)
- "g.map(_.toString)" shouldNot compile
- }
-
- def `generic undirected, mappable labeled multiedge`: Unit = {
- import edges.multilabeled.*
-
- case class MyEdge[+N](source: N, target: N, label: String)
- extends LUnDiEdge[N, String]
- with GenericEdgeMapper[MyEdge] {
- def map[N](node_1: N, node_2: N) = copy(node_1, node_2)
- }
-
- val e = MyEdge(1, 2, "")
- e shouldNot equal(UnDiEdge(1, 2))
-
- val g = factory.from(e :: Nil)
- g.map(_.toString).edges.toOuter.head shouldBe MyEdge("1", "2", "")
-
- import edges.UnDiEdgeImplicits
- implicit class MyInfixConstructor[N](val edge: UnDiEdge[N])
- extends LUnDiEdgeInfixConstructor[N, String, MyEdge](MyEdge.apply)
- 1 ~ 2 :++ "" shouldEqual e
-
- import generic.{UnapplyGenericLabel, UnapplyGenericLabeledEdge}
- object :~ extends UnapplyGenericLabeledEdge[MyEdge, String]
- object ++: extends UnapplyGenericLabel[String]
-
- e match {
- case n1 :~ n2 ++: label =>
- val reconstructed = MyEdge(n1, n2, label)
- "reconstructed: MyEdge[Int]" should compile
- reconstructed shouldEqual e
- }
- }
-
- /* TODO
- def `isMulti ` {
- import edge.WkDiEdge
- def multi(g: CC[Int, UnDiEdge], expected: Boolean): Unit = g.isMulti should be(expected)
- val (wDi_1, wDi_2) = (WkDiEdge(1, 2)(0), WkDiEdge(1, 2)(1))
-
- multi(factory(1 ~ 2), false)
- multi(factory(1 ~ 2, 1 ~> 2), false)
- multi(factory(wDi_1, wDi_2), true)
- }
-
- def `isDirected ` {
- def directed(g: CC[Int, UnDiEdge], expected: Boolean): Unit = g.isDirected should be(expected)
- val wDi = edge.WDiEdge(1, 2)(0)
-
- factory(wDi).isDirected should be(true)
- directed(factory(wDi), true)
- directed(factory(0 ~> 1, wDi), true)
- }
- */
-}
-
-private class EditingLabeledMutable extends RefSpec with Matchers {
- object `mutable graphs with labeled edges` { // TODO
- /*
- def `satisfy labeled edege equality` {
- import edge.Implicits._
- import edge.LDiEdge
-
- type StringLabel = Option[String]
- val str = "A"
- val label: StringLabel = Some(str)
- val g = mutable.Graph(2 ~ 3, (2 ~+# 3) (label))
- g should have('order(2), 'size(2))
-
- import edge.LBase.{LEdgeImplicits}
- object StringLabelImplicit extends LEdgeImplicits[StringLabel]
- import StringLabelImplicit._
- for (e <- g.edges if e.isLabeled) {
- e.isDefined should be(true)
- e.get should be(str)
- }
-
- type ListLabel = List[Int]
- implicit val factory = LDiEdge
- val listLabel = List(1, 0, 1)
- g.addLEdge(3, 4)(listLabel) should be(true)
- g should have('order(3), 'size(3))
- val findAdded = g.edges find (3 ~> 4)
- findAdded should be('isDefined)
- val added: g.EdgeT = findAdded.get
- added.directed should be(true)
- added.count(_ > 0) should be(List(1, 0, 1).count(_ > 0))
- }
-
- def `are upsertable` {
- import edge.LDiEdge
- val (label, modLabel) = ("A", "B")
- val g = mutable.Graph(LDiEdge(1, 2)(label), LDiEdge(2, 3)(label))
-
- g.edges foreach {
- _.edge match {
- case LDiEdge(s, t, l) => g upsert (LDiEdge(s.value, t.value)(modLabel))
- }
- }
- g should have('size (2))
- g.edges foreach { _.label should be(modLabel) }
- }
- */
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/EditingSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/EditingSpec.scala
deleted file mode 100644
index fb871e3a..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/EditingSpec.scala
+++ /dev/null
@@ -1,436 +0,0 @@
-package scalax.collection
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.Suites
-import org.scalatest.refspec.RefSpec
-import scalax.collection.edges._
-import scalax.collection.generic._
-import scalax.collection.OuterImplicits._
-import scalax.collection.config.GraphConfig
-
-/** Editing any kind of non-hypergraph with unlabeled edges including mixed graphs.
- */
-class EditingSpec
- extends Suites(
- new EditingEdges,
- new Editing[immutable.Graph](new ConfigWrapper[immutable.Graph] {
- val companion = immutable.Graph
- val config = immutable.Graph.defaultConfig
- }),
- new Editing[mutable.Graph](new ConfigWrapper[mutable.Graph] {
- val companion = mutable.Graph
- val config = mutable.Graph.defaultConfig
- }),
- new EditingImmutable,
- new EditingMutable
- )
-
-private class EditingEdges extends RefSpec with Matchers {
-
- def `toString of edges`: Unit = {
- DiEdge(1, 2).toString shouldBe "1 ~> 2"
- UnDiEdge(1, 2).toString shouldBe "1 ~ 2"
- }
-}
-
-class EditingImmutable extends RefSpec with Matchers {
- private val Graph = immutable.Graph
-
- Graph.from(1 ~ 2 :: Nil)
-
- object `graphs ` {
- def `+ Int`: Unit = {
- val g = Graph(1, 2 ~ 3)
- g + 1 should be(g)
- g + 0 should be(Graph(0, 1, 2, 3, 2 ~ 3))
- g + 0 ~ 1 should be(Graph(0, 1, 2, 3, 0 ~ 1, 2 ~ 3))
- }
-
- val gString_A = Graph[String, AnyEdge]("A")
-
- def `- ` : Unit = {
- val g_1 = gString_A - "B"
- g_1.order should be(1)
-
- val g = gString_A - "A"
- g.nodes shouldNot contain("A")
- g should have size 0
- g shouldBe empty
-
- val h = Graph(1, 2, 2 ~ 3)
- h - 0 should be(h)
- h - 1 should be(Graph(2, 2 ~ 3))
- h - 2 should be(Graph(1, 3))
- }
-
- def `-- ` : Unit = {
- val g = Graph(1, 2 ~ 3, 3 ~ 4)
- g -- (List(2), List(3 ~ 3)) should be(Graph(1, 3 ~ 4))
- g -- (List(2), List(3 ~ 4)) should be(Graph(1, 3, 4))
- }
-
- def `+ String ` : Unit = {
- val g = gString_A + "B"
- g.elementCount shouldBe 2
- g.nodes should contain("A")
- g.nodes should contain("B")
-
- val hString_A = Graph[String, UnDiEdge]("A")
- val h = hString_A + "A" ~ "C"
- h.nodes should have size 2
- h.edges should have size 1
- h.elementCount should be(3)
- }
- }
-}
-
-private class EditingMutable extends RefSpec with Matchers {
- private val Graph = mutable.Graph
-
- object `mutable graphs` {
- def `serve += properly`: Unit = {
- val g = Graph[Int, Nothing](1, 3)
- g addOne 2
- g.order should be(3)
- for (i <- 1 to 3)
- g.nodes should contain(i)
- }
-
- def `serve -= properly`: Unit = {
- val g = Graph(1, 2, 2 ~ 3, 4)
- g remove 1 should be(true)
- g should be(Graph(2 ~ 3, 4))
- g remove 5 should be(false)
- g subtractOne 2 should be(Graph(3, 4))
- g.clear()
- g should be(Symbol("empty"))
- }
-
- def `+ String ` : Unit = {
- val g = Graph("A") addOne "B"
- g.elementCount shouldBe 2
- g.contains("A") shouldBe true
- g.contains("B") shouldBe true
-
- val hString_A = Graph[String, UnDiEdge]("A")
- val h = hString_A += "A" ~ "C"
- h.nodes should have size 2
- h.edges should have size 1
- h.elementCount should be(3)
- }
-
- def `serve -= properly (2)` : Unit = {
- val g = Graph(1 ~ 2, 2 ~ 3)
- g subtractOne 2 should be(Graph(1, 3))
- g.size should be(0)
- }
-
- def `serve 'directed' properly`: Unit = {
- val (di, unDi) = (1 ~> 2, 2 ~ 3)
- val g = Graph[Int, AnyEdge](unDi)
- def directed(expected: Boolean): Unit = g.isDirected should be(expected)
-
- directed(false)
- g.clear(); directed(false)
- g += di; directed(true)
- g += unDi; directed(false)
- g.clear(); directed(false)
- }
-
- def `serve 'diSuccessors' when directed`: Unit = {
- val (one, two, oneOne, oneTwo) = (1, 2, 1 ~> 1, 1 ~> 2)
- val g = Graph(oneOne, oneTwo, one ~> 3, one ~> 4)
- val (n1, n2) = (g get one, g get two)
- val e11 = g get oneOne
-
- g subtractOne 1 ~> 4 // Graph(oneOne, oneTwo, one~>3)
- n2.diSuccessors shouldBe empty
- n1.diSuccessors.map(_.outer) shouldBe Set(two, 3)
- n1 findOutgoingTo n1 should be(Some(e11))
-
- g subtractOne oneTwo // Graph(oneOne, one~>3)
- n1.diSuccessors should be(Set(3))
- n1 findOutgoingTo n1 should be(Some(e11))
-
- g subtractOne oneOne // Graph(one~>3)
- n1.diSuccessors should be(Set(3))
- n1 findOutgoingTo n1 should be(None)
-
- g ++= (edges = List(oneOne, oneTwo)) // Graph(oneOne, oneTwo, one~>3)
- n1.diSuccessors should be(Set(two, 3))
- n1 findOutgoingTo n1 should be(Some(e11))
- }
-
- def `serve ++=, unionInPlace`: Unit = {
- val (gBefore, gAfter) = (Graph(1, 2 ~ 3), Graph(0, 1 ~ 2, 2 ~ 3))
- (gBefore ++= (0 :: Nil, List(1 ~ 2, 2 ~ 3))) should equal(gAfter)
- (gBefore |= Graph(0, 1 ~ 2)) should equal(gAfter)
- (gBefore |= Graph[Int, UnDiEdge](0) |= Graph(1 ~ 2)) should equal(gAfter)
- }
- }
-}
-
-private class Editing[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]](val factory: ConfigWrapper[CC])
- extends RefSpec
- with Matchers {
-
- info("factory = " + factory.companion.getClass)
-
- implicit private val config: GraphConfig = factory.config
-
- private val seq_1_3 = Seq(1, 3)
- private val gInt_1_3 = factory.from(nodes = seq_1_3, Nil)
- private val gString_A = factory("A")
-
- object `graph editing` {
- def `empty ` : Unit = {
- val eg = factory.empty[Nothing, Nothing]
- eg shouldBe empty
- eg should have size 0
- }
-
- def `apply ` : Unit = {
- gInt_1_3 should not be empty
- gInt_1_3.order should be(2)
- gInt_1_3(0) shouldBe false
- gInt_1_3(1) shouldBe true
- gInt_1_3(2) shouldBe false
- gInt_1_3(3) shouldBe true
- }
-
- def `nodes of ADT fixes #40`: Unit = {
- sealed trait Node
- case class N1() extends Node
- case class N2() extends Node
- factory(N1() ~> N2(), N1() ~> N1()): CC[Node, DiEdge[Node]] // should typeCheck
- }
-
- def `isDirected ` : Unit = {
- def directed(g: CC[Int, AnyEdge[Int]], expected: Boolean): Unit = g.isDirected should be(expected)
-
- directed(factory(1 ~ 2), false)
- directed(factory(1 ~> 2), true)
- }
-
- def `from ` : Unit = {
- val (n_start, n_end) = (11, 20)
- val nodes = List.range(n_start, n_end)
- val edges = List[DiEdge[Int]](14 ~> 16, 16 ~> 18, 18 ~> 20, 20 ~> 22)
- val g = factory.from(nodes, edges)
- g.nodes.size should be(nodes.size + 2)
- g.edges.size should be(edges.size)
- }
-
- def `contains ` : Unit = {
- seq_1_3 foreach (n => gInt_1_3 contains n should be(true))
- gInt_1_3.iterator.next() shouldBe a[gInt_1_3.InnerNode]
- }
-
- def `toString ` : Unit = {
- gInt_1_3.toString shouldBe "Graph(NodeSet(1, 3), EdgeSet())"
- gString_A.toString shouldBe """Graph(NodeSet(A), EdgeSet())"""
- }
-
- def `render ` : Unit = {
- import ToString._
- gInt_1_3.render(SetElemsOnSeparateLines()) shouldBe
- """Graph(
- | NodeSet(
- | 1,
- | 3),
- | EdgeSet())""".stripMargin
- val g = factory(1 ~ 2)
- g.render(SetsOnSeparateLines()) shouldBe
- """Graph(
- | NodeSet(1, 2),
- | EdgeSet(1 ~ 2))""".stripMargin
- g.render(SetElemsOnSeparateLines()) shouldBe
- """Graph(
- | NodeSet(
- | 1,
- | 2),
- | EdgeSet(
- | 1 ~ 2))""".stripMargin
- g.render(SetElemsOnSeparateLines(), withInnerPrefix = false) shouldBe
- """Graph(
- | 1,
- | 2,
- | 1 ~ 2)""".stripMargin
- }
-
- def `from inner ` : Unit = {
- val gn = factory(2, 3)
- factory.from[Int, Nothing](gn.nodes.outerIterable, Nil) should equal(gn)
-
- val g = factory(2 ~ 3)
- factory(g.edges.head) should equal(g)
- factory.from(g.edges.outerIterable) should equal(g)
- }
-
- def `NodeSet ` : Unit = {
- val o = Vector.range(0, 4)
- val g = factory(o(1) ~ o(2), o(2) ~ o(3))
- val n = o map (g.nodes find _ getOrElse g.nodes.head)
-
- val less = g.nodes - n(3)
- g.order shouldBe 3
- less should have size 2
- less should contain(n(1))
- less.find(_ == n(1)).get.edges should have size 1
- less should contain(n(2))
- less.find(_ == n(2)).get.edges should have size 2
-
- val restored = less.toSet + n(3)
- restored should have size 3
- restored should contain(n(3))
- restored.find(_ == n(1)).get.edges should have size 1
- }
-
- def `EdgeAssoc ` : Unit = {
- val e = 1 ~ 2
- e shouldBe an[UnDiEdge[_]]
-
- val g = factory(3 ~ 4)
- g.edges should contain(3 ~ 4)
-
- val d = 1 ~> 2
- d shouldBe a[DiEdge[_]]
- d.source should be(1)
- d.target should be(2)
- factory[Int, AnyEdge](1, d, 1 ~ 4).nodes should have size 3
- }
-
- def `concat, ++, union`: Unit = {
- val diEdge = 1 ~> 2
- factory.empty[Int, DiEdge[Int]] ++ List(diEdge) shouldBe factory.from(diEdge :: Nil)
-
- val g = gString_A.concat[String, Edge[String]](List("B", "C"), Nil)
- g.elementCount shouldEqual 3
- 'A' to 'C' map (_.toString) foreach (g.contains(_) shouldEqual true)
-
- val (gBefore, gAfter) = (factory(1, 2 ~ 3), factory(0, 1 ~ 2, 2 ~ 3))
- gBefore ++ (edges = List(1 ~ 2, 2 ~ 3), isolatedNodes = List(0)) shouldEqual gAfter
-
- gBefore union factory(0, 1 ~ 2) shouldEqual gAfter
- gBefore union factory[Int, UnDiEdge](0) union factory(1 ~ 2) shouldEqual gAfter
- }
-
- private val gUnDi = factory(1 ~ 1, 1 ~ 2, 1 ~ 3, 1 ~ 4)
- private val gDi = factory(1 ~> 1, 1 ~> 2, 1 ~> 3, 1 ~> 4)
- private val gMixed = factory[Int, AnyEdge](1 ~> 2, 2 ~> 3, 4 ~ 3)
-
- object `diSuccessors ` {
- def `for UnDi`: Unit = {
- (gUnDi get 1).diSuccessors should be(Set(2, 3, 4))
- (gUnDi get 2).diSuccessors should be(Set(1))
- }
- def `for Di`: Unit = {
- (gDi get 1).diSuccessors should be(Set(2, 3, 4))
- (gDi get 2).diSuccessors should be(Set.empty)
- }
- def `for mixed`: Unit = {
- (gMixed get 2).diSuccessors should be(Set(3))
- (gMixed get 3).diSuccessors should be(Set(4))
- }
- }
-
- object `diPredecessors ` {
- def `for UnDi`: Unit = {
- (gUnDi get 1).diPredecessors should be(Set(2, 3, 4))
- (gUnDi get 2).diSuccessors should be(Set(1))
- }
- def `for Di`: Unit = {
- (gDi get 1).diPredecessors should be(Set.empty)
- (gDi get 2).diPredecessors should be(Set(1))
- }
- def `for mixed`: Unit = {
- (gMixed get 2).diPredecessors should be(Set(1))
- (gMixed get 3).diSuccessors should be(Set(4))
- }
- }
-
- object `neighbors ` {
- def `for UnDi`: Unit = {
- (gUnDi get 1).neighbors should be(Set(2, 3, 4))
- (gUnDi get 2).neighbors should be(Set(1))
- }
- def `for Di`: Unit = {
- (gDi get 1).neighbors should be(Set(2, 3, 4))
- (gDi get 2).neighbors should be(Set(1))
- }
- }
-
- def `findOutgoingTo Di`: Unit = {
- val g = factory(1 ~> 1, 1 ~> 2, 2 ~> 1)
- def n(i: Int) = g get i
- n(1) findOutgoingTo n(2) should be(Some(1 ~> 2))
- n(1) findOutgoingTo n(1) should be(Some(1 ~> 1))
- }
-
- def `degree ` : Unit = {
- val g = factory(1 ~ 1, 1 ~ 2, 1 ~ 3, 1 ~ 4)
- (g get 1).degree should be(5)
- (g get 2).degree should be(1)
- }
-
- def `incoming ` : Unit = {
- val uEdges = Seq(1 ~ 1, 1 ~ 2, 1 ~ 3, 1 ~ 4)
- val g = factory(uEdges(0), uEdges(1), uEdges(2), uEdges(3))
- (g get 1).incoming should be(uEdges.toSet)
- (g get 2).incoming should be(Set(uEdges(1)))
-
- val dEdges = Seq(1 ~> 1, 1 ~> 2, 1 ~> 3, 1 ~> 4)
- val h = factory(dEdges(0), dEdges(1), dEdges(2), dEdges(3))
- (h get 1).incoming should be(Set(dEdges(0)))
- (h get 2).incoming should be(Set(dEdges(1)))
- }
-
- def `edgeAdjacents UnDi`: Unit = {
- val g = factory[Int, AnyEdge](1 ~ 2, 2 ~ 3, 1 ~> 3, 1 ~ 5, 3 ~ 5, 3 ~ 4, 4 ~> 4, 4 ~> 5)
- (g get 4 ~> 4).adjacents should be(Set[AnyEdge[Int]](3 ~ 4, 4 ~> 5))
- (g get 1 ~ 2).adjacents should be(Set[AnyEdge[Int]](1 ~> 3, 1 ~ 5, 2 ~ 3))
- }
-
- def `filter ` : Unit = {
- val g: AnyGraph[Int, DiEdge[Int]] = factory(2 ~> 3, 3 ~> 1, 5)
- g filter (_ > 1) should be(factory(2 ~> 3, 5))
- g filter (_ < 2) should be(factory(1))
- g filter (_ < 2) should be(factory(1))
- g filter (_ >= 2) should be(factory(2 ~> 3, 5))
- g filter (edgeP = _.node1.outer == 2) should be(factory(1, 5, 2 ~> 3))
- g filter (nodeP = _ <= 3, edgeP = _ contains 2) should be(factory(1, 2 ~> 3))
- }
-
- def `match ` : Unit = {
- val di = 1 ~> 2
- (di match { case DiEdge(src, _) => src }) should be(1)
- (di match { case src ~> trg => src + trg }) should be(3)
-
- val unDi = 1 ~ 2
- (unDi match { case UnDiEdge(n1, _) => n1 }) should be(1)
- (unDi match { case n1 ~ n2 => n1 + n2 }) should be(3)
- }
-
- def `foldLeft, foldLeftOuter ` : Unit = {
- val g = factory(1 ~> 2, 2 ~> 3, 7)
-
- val sumOfNodes = 13
- g.nodes.foldLeft(0)((cum, n) => cum + n.outer) shouldBe sumOfNodes
- g.nodes.foldLeftOuter(0)((cum, n) => cum + n) shouldBe sumOfNodes
-
- val edgeProducts = 2 + 6
- g.edges.foldLeft(0)((cum, e) => cum + e.outer.source * e.outer.target) shouldBe edgeProducts
- g.edges.foldLeftOuter(0)((cum, e) => cum + e.source * e.target) shouldBe edgeProducts
-
- val expected = sumOfNodes + edgeProducts
- g.foldLeft(0)(
- (cum, n) => cum + n.outer,
- (cum, e) => cum + e.outer.source * e.outer.target
- ) shouldBe expected
- g.foldLeftOuter(0)(
- (cum, n) => cum + n,
- (cum, e) => cum + e.source * e.target
- ) shouldBe expected
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/EditingTypedHyperSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/EditingTypedHyperSpec.scala
deleted file mode 100644
index 8f88e43d..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/EditingTypedHyperSpec.scala
+++ /dev/null
@@ -1,5 +0,0 @@
-package scalax.collection
-
-/** Editing any kind of typed hypergraph including mixed and multigraphs.
- */
-class EditingTypedHyperSpec // TODO extends Suites()
diff --git a/coreTestScala3/src/test/scala/scalax/collection/EditingTypedSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/EditingTypedSpec.scala
deleted file mode 100644
index 7ca909af..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/EditingTypedSpec.scala
+++ /dev/null
@@ -1,140 +0,0 @@
-package scalax.collection
-
-import java.time.DayOfWeek.*
-import java.time.LocalTime
-
-import scala.concurrent.duration.*
-
-import org.scalatest.Suites
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.edges.DiEdge
-import scalax.collection.generic.*
-import scalax.collection.labeled.aviation.*
-
-class EditingTypedSpec
- extends Suites(
- new EditingTypedEdges,
- new EditingTyped(immutable.FlightGraph, scalax.collection.immutable.Graph),
- new EditingTyped(mutable.FlightGraph, scalax.collection.mutable.Graph)
- )
-
-private object Samples {
- val (madrid, rio) = (Airport("MAD"), Airport("GIG"))
- val flightNo = "IB 8711"
- val outer = Flight(
- madrid,
- rio,
- flightNo,
- List(
- TUESDAY -> LocalTime.of(8, 20),
- SATURDAY -> LocalTime.of(8, 20)
- ),
- 12.hour + 30.minutes
- )
-}
-
-private class EditingTypedEdges extends RefSpec with Matchers {
- import Samples.*
-
- def `toString of typed edge`: Unit =
- outer.toString should startWith(s"$madrid ~> $rio :++ ")
-}
-
-private class EditingTyped[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]](
- typedFactory: TypedGraphCoreFactory[Airport, Flight, CC],
- genericFactory: GenericGraphCoreFactory[CC]
-) extends RefSpec
- with Matchers
- with IntelliJ[CC] {
- import Samples.*
-
- object `Custom edge 'Flight'` {
- def `edge methods`: Unit = {
-
- val g = typedFactory.from(Nil, edges = outer :: Nil).asAnyGraph
-
- val e = g.edges.head
- e.ends.head.getClass should be(g.nodes.head.getClass)
- e.departure shouldBe madrid
- e.destination shouldBe rio
- e.flightNo shouldBe flightNo
- e shouldBe outer
- e.## should be(outer.##)
-
- val eqFlight = Flight(madrid, rio, flightNo, Nil, outer.duration + 1.minute)
- e shouldBe eqFlight
- e.## should be(eqFlight.##)
-
- val neFlight = Flight(madrid, rio, flightNo + "x", outer.departures, outer.duration)
- e should not be neFlight
- e.## should not be neFlight.##
- }
-
- def `edge equality`: Unit = {
- val outer_1 = Flight(madrid, rio, flightNo, outer.departures, outer.duration + 1.minute)
- val outer_2 = Flight(madrid, rio, flightNo + "x", outer.departures, outer.duration + 1.minute)
-
- outer_1 should not equal outer_2
-
- val g = typedFactory.from(outer_1 :: outer_2 :: Nil).asAnyGraph
- g.edges.toList match {
- case inner_1 :: inner_2 :: Nil =>
- inner_1 should not equal inner_2
- inner_1 should equal(outer_1)
- case _ => fail()
- }
-
- outer shouldNot equal(DiEdge(madrid, rio))
- DiEdge(madrid, rio) shouldNot equal(outer)
- }
-
- def `infix constructor`: Unit = {
- import scalax.collection.edges.DiEdgeImplicits
- madrid ~> rio :++ (flightNo, outer.departures, outer.duration) shouldBe outer
- }
-
- def `extractor ` : Unit = {
- val g = typedFactory.empty.asAnyGraph
-
- g.nodes foreach { case g.InnerNode(inner, Airport(code)) =>
- code -> inner.outDegree
- }
- g.nodes.outerIterator foreach { case Airport(code) =>
- code
- }
- g.edges foreach { case g.InnerEdge(g.InnerDiEdge(source, _), Flight(_, _, no, _, _)) =>
- no -> source.outDegree
- }
- g.edges.outerIterator foreach { case Flight(from, to, no, _, _) =>
- (from.code, to.code, no)
- }
- }
-
- def `concat adding a generic edge`: Unit = {
- val g = typedFactory.empty.asAnyGraph
-
- g ++ List(outer) shouldBe typedFactory.from(outer :: Nil)
- "g ++ List(outer): AnyFlightGraph" should compile
-
- val diEdge = DiEdge(outer.source, outer.target)
- val widened = g ++ List(diEdge)
- "widened: AnyFlightGraph" shouldNot compile
- "widened: AnyGraph[Airport, DiEdge[Airport]]" shouldNot compile
- "widened: AnyGraph[Airport, AnyDiEdge[Airport] with EdgeMapper with DiEdgeToString]" should compile
- }
-
- def `concat adding a typed edge`: Unit = {
- val g = genericFactory.empty[Airport, DiEdge[Airport]].asAnyGraph
-
- val diEdge = DiEdge(outer.source, outer.target)
- g ++ List(diEdge) shouldBe genericFactory.from(diEdge :: Nil)
- "g ++ List(diEdge): AnyGraph[Airport, DiEdge[Airport]]" should compile
-
- val widened = g ++ List(outer)
- "widened: AnyFlightGraph" shouldNot compile
- "widened: AnyGraph[Airport, DiEdge[Airport]]" shouldNot compile
- "widened: AnyGraph[Airport, AnyDiEdge[Airport] with EdgeMapper with DiEdgeToString]" should compile
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/EqualityHyperSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/EqualityHyperSpec.scala
deleted file mode 100644
index ba8e6e1b..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/EqualityHyperSpec.scala
+++ /dev/null
@@ -1,75 +0,0 @@
-package scalax.collection
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.generic.AbstractDiHyperEdge
-
-class EqualityHyperSpec extends RefSpec with Matchers {
-
- def `hyperedges, bag like ` : Unit = {
- import scalax.collection.hyperedges.*
-
- val nodes = List('A', 'B', 'C', 'C')
- val hEdge = HyperEdge.fromUnsafe(nodes)
- hEdge shouldEqual 'A' ~~ 'B' ~~ 'C' ~~ 'C'
- hEdge shouldEqual 'C' ~~ 'C' ~~ 'B' ~~ 'A'
-
- hEdge.arity shouldBe nodes.size
- for (i <- nodes.indices)
- hEdge.node(i) shouldBe nodes(i)
- }
-
- def `hyperedges, ordered ` : Unit = {
- import scalax.collection.hyperedges.ordered.*
-
- val nodes = List('A', 'B', 'C', 'C')
- val hEdge = HyperEdge.fromUnsafe(nodes)
- hEdge shouldEqual 'A' ~~ 'B' ~~ 'C' ~~ 'C'
- hEdge shouldNot equal('C' ~~ 'C' ~~ 'B' ~~ 'A')
-
- hEdge.arity shouldBe nodes.size
- for (i <- nodes.indices)
- hEdge.node(i) shouldBe nodes(i)
- }
-
- def `directed hyperedges, bag like`: Unit = {
- import scalax.collection.hyperedges.*
-
- val sources = OneOrMore('A', 'B', 'C')
- val targets = OneOrMore('D', 'D', 'E')
- val dhEdge = DiHyperEdge(sources, targets)
- dhEdge shouldEqual sources ~~> targets
- dhEdge shouldEqual sources.reverse ~~> targets.reverse
-
- dhEdge.ends.toList should contain theSameElementsAs (sources ++ targets).toList
-
- val sourcesSize = sources.size
- dhEdge.arity shouldBe sourcesSize + targets.size
-
- checkIndices(sources, dhEdge)
- checkIndices(targets, dhEdge, sourcesSize)
- }
-
- def `directed hyperedges, ordered`: Unit = {
- import scalax.collection.hyperedges.ordered.*
-
- val sources = OneOrMore('A', 'B', 'C')
- val targets = OneOrMore('D', 'D', 'E')
- val dhEdge = DiHyperEdge(sources, targets)
- dhEdge shouldEqual sources ~~> targets
- dhEdge shouldNot equal(sources.reverse ~~> targets.reverse)
-
- dhEdge.ends.toList should contain theSameElementsAs (sources ++ targets).toList
-
- val sourcesSize = sources.size
- dhEdge.arity shouldBe sourcesSize + targets.size
-
- checkIndices(sources, dhEdge)
- checkIndices(targets, dhEdge, sourcesSize)
- }
-
- private def checkIndices(s: OneOrMore[_], dhEdge: AbstractDiHyperEdge[_], plus: Int = 0): Unit = {
- val list = s.iterator.toList
- for (i <- list.indices) dhEdge.node(i + plus) shouldBe list(i)
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/EqualitySpec.scala b/coreTestScala3/src/test/scala/scalax/collection/EqualitySpec.scala
deleted file mode 100644
index 78021002..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/EqualitySpec.scala
+++ /dev/null
@@ -1,58 +0,0 @@
-package scalax.collection
-
-import org.scalatest.Suites
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.{Edge, GenericGraphCoreFactory}
-
-class EqualitySpec
- extends Suites(
- new Equality[immutable.Graph](immutable.Graph),
- new Equality[mutable.Graph](mutable.Graph),
- new EqualityMixed
- )
-
-private class Equality[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]](
- val factory: GenericGraphCoreFactory[CC]
-) extends RefSpec
- with Matchers {
-
- private val seq_1_3 = Seq(1, 3)
- private val gInt_1_3 = factory(seq_1_3.toOuterElems[DiEdge[Int]]: _*)
- private val gString_A = factory("A")
-
- def `Eq ` : Unit = {
- factory[Int, Nothing]() shouldEqual factory[Int, DiEdge]()
- gInt_1_3 shouldEqual factory(1, 3)
- gString_A shouldEqual factory("A")
-
- factory() shouldNot be(factory(1))
- gInt_1_3 shouldNot be(factory(2, 3))
- gString_A shouldNot be(factory("B"))
-
- gInt_1_3 shouldEqual immutable.Graph(1) + 3
- }
-}
-
-private class EqualityMixed extends RefSpec with Matchers {
-
- val oEdgesG = List(1 ~ 2, 2 ~ 3, 2 ~ 4, 3 ~ 5, 4 ~ 5)
- val oEdgesH = List(3 ~ 4, 3 ~ 5, 4 ~ 6, 5 ~ 6)
-
- val (iFactory, mFactory) = (immutable.Graph, mutable.Graph)
-
- def initG = (iFactory(oEdgesG: _*), mFactory(oEdgesG: _*))
- def initH = (iFactory(oEdgesH: _*), mFactory(oEdgesH: _*))
-
- object `equals works properly` {
- def `over immutable and mutable graphs`: Unit = {
- val (iG, mG) = initG
- iG should ===(mG)
-
- val (iH, mH) = initH
- iH should ===(mH)
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/IntelliJ.scala b/coreTestScala3/src/test/scala/scalax/collection/IntelliJ.scala
deleted file mode 100644
index dee95102..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/IntelliJ.scala
+++ /dev/null
@@ -1,13 +0,0 @@
-package scalax.collection
-
-import scalax.collection.generic.Edge
-
-trait IntelliJ[C[N, E <: Edge[N]] <: GraphLike[N, E, C] with AnyGraph[N, E]] {
-
- /** Moves lots of false positive IntelliJ errors on the higher kinded type parameter `C` to this single point.
- * Using this kind of IDE correction is not recommended in production code.
- */
- implicit class ForIntelliJ[N, E <: Edge[N]](val g: C[N, E]) {
- def asAnyGraph: AnyGraph[N, E] = g
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/MappingHyperSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/MappingHyperSpec.scala
deleted file mode 100644
index 6ab8a51f..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/MappingHyperSpec.scala
+++ /dev/null
@@ -1,143 +0,0 @@
-package scalax.collection
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.OneOrMore.{more, one}
-import scalax.collection.OuterImplicits.*
-import scalax.collection.hyperedges.*
-import scalax.collection.immutable.Graph
-
-class MappingHyperSpec extends RefSpec with Matchers {
-
- object `mapping a generic hypergraph you can` {
- val g = Graph(
- 1 ~~ 2 ~~ 3,
- 3 ~~ 4 ~~ 1
- )
-
- def `map by identity`: Unit =
- g.map(identity) shouldEqual g
-
- def `map nodes`: Unit =
- g.map(_.toString) shouldEqual Graph("1" ~~ "2" ~~ "3", "3" ~~ "4" ~~ "1")
-
- def `map both nodes and edges`: Unit =
- g.mapHyper(
- fNode = _.outer + 1, // increment node values
- fHyperEdge = (newEnds: Several[Int]) => newEnds(0) ~~ newEnds(1) // add only the first two ends
- ) shouldEqual Graph(2 ~~ 3, 4 ~~ 5)
- }
-
- object `mapping a generic directed hypergraph you can` {
- val g = Graph(
- more(1, 2) ~~> one(3),
- one(3) ~~> more(4, 1)
- )
-
- def `map by identity`: Unit =
- g.map(identity) shouldEqual g
-
- def `map nodes`: Unit =
- g.map(_.toString) shouldEqual Graph(more("1", "2") ~~> one("3"), one("3") ~~> more("4", "1"))
-
- def `map both nodes and edges`: Unit =
- g.mapDiHyper(
- fNode = _.outer + 1, // increment node values
- fDiHyperEdge =
- // keep newSources as sources, add newSources to targets
- (newSources: OneOrMore[Int], newTargets: OneOrMore[Int]) => newSources ~~> (newTargets ++ newSources)
- ) shouldEqual Graph(
- more(2, 3) ~~> more(4, 2, 3),
- one(4) ~~> more(5, 2, 4)
- )
- }
-
- object `flat-mapping a generic hypergraph you can` {
- val g = Graph(
- 1 ~~ 2 ~~ 3,
- 3 ~~ 4 ~~ 1
- )
-
- def `map elements, change node type and edge cardinality`: Unit =
- g.flatMapHyper(
- fNode = (n: g.NodeT) =>
- /* nodes will be mapped to
- 1 -> 2
- 2 -> 2, -2
- 3 -> 4
- 4 -> 4, -4
- */
- if (n.outer % 2 == 0) n.toString :: (-n).toString :: Nil
- else (n.outer + 1).toString :: Nil,
-
- // `fromUnsafe` is fine here because we know that `fNode` returns at least one mapped node
- fHyperEdge = (nn: Seq[String]) => HyperEdge.fromUnsafe(nn) :: Nil
- ) shouldEqual Graph(
- "-2" ~~ "2" ~~ "2" ~~ "4",
- "-4" ~~ "2" ~~ "4" ~~ "4"
- )
-
- def `change the graph structure`: Unit =
- g.flatMapHyper(
- fNode = (n: g.NodeT) => (n.outer + 1) :: Nil,
- fHyperEdge = (e: g.EdgeT, nn: Seq[Int]) =>
- nn match {
- case Seq(nn1, nn2, nn3) =>
- nn1 ~~ nn2 ~~ nn3 ~~ e.ends.iterator.map(_.degree).max ::
- nn1 ~~ nn2 ~~ -e.ends.size ::
- Nil
- case _ => Nil
- },
- fDiHyperEdge = None,
- fEdge = None
- ) shouldEqual Graph(
- 2 ~~ 3 ~~ 4 ~~ 2,
- 2 ~~ 3 ~~ -3,
- 4 ~~ 5 ~~ 2 ~~ 2,
- 4 ~~ 5 ~~ -3
- )
- }
-
- object `flat-mapping a generic directed hypergraph you can` {
- val g = Graph(
- more(1, 2) ~~> one(3),
- one(3) ~~> more(4, 1)
- )
-
- def `map elements, change node type and edge cardinality`: Unit =
- g.flatMapDiHyper(
- fNode = (n: g.NodeT) =>
- /* nodes will be mapped to
- 1 -> 2
- 2 -> 2, -2
- 3 -> 4
- 4 -> 4, -4
- */
- if (n.outer % 2 == 0) n.toString :: (-n).toString :: Nil
- else (n.outer + 1).toString :: Nil,
- fDiHyperEdge =
- // `fromUnsafe` is fine here because above `fNode` returns at least one mapped node
- (newSources: Seq[String], newTargets: Seq[String]) => DiHyperEdge.fromUnsafe(newSources, newTargets) :: Nil
- ) shouldEqual Graph(
- more("-2", "2", "2") ~~> one("4"),
- one("4") ~~> more("4", "-4", "2")
- )
-
- def `change the graph structure`: Unit =
- g.flatMapDiHyper(
- fNode = (n: g.NodeT) => (n.outer + 1) :: Nil,
- fDiHyperEdge = (e: g.EdgeT, newSources: Seq[Int], newTargets: Seq[Int]) =>
- // `fromUnsafe` is fine here because above `fNode` always returns exactly one mapped node
- DiHyperEdge.fromUnsafe(newSources, newTargets ++ e.targets.iterator.map(_.outDegree)) ::
- DiHyperEdge.fromUnsafe(newTargets, newSources :+ e.sources.size) ::
- Nil,
- fEdge = None
- ) shouldEqual Graph(
- more(2, 3) ~~> more(4, 1),
- one(4) ~~> more(2, 3, 2),
- one(4) ~~> more(5, 2, 0, 1),
- more(5, 2) ~~> more(4, 1)
- )
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/MappingSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/MappingSpec.scala
deleted file mode 100644
index 9ff7afd4..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/MappingSpec.scala
+++ /dev/null
@@ -1,123 +0,0 @@
-package scalax.collection
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.immutable.Graph
-
-class MappingSpec extends RefSpec with Matchers {
-
- object `mapping a generic undirected graph you can` {
- private val edge = 1 ~ 2
- private val originalG = Graph(edge)
-
- private def increment(n: originalG.NodeT) = n.outer + 1
-
- def `create another graph`: Unit = {
- val g = originalG map increment
-
- g shouldBe a[Graph[Int, UnDiEdge[Int]] @unchecked]
- g.nodes.head.outer shouldBe an[Integer]
- g.edges.head shouldBe an[g.InnerUnDiEdge]
- (g.edges.head.outer: UnDiEdge[Int]) shouldBe an[UnDiEdge[_]]
- }
-
- def `map by nodes`: Unit = {
- val g = originalG map increment
-
- originalG.nodes zip g.nodes.outerIterator foreach { case (original, mapped) =>
- increment(original) shouldBe mapped
- }
- g.edges.head shouldBe UnDiEdge(2, 3)
- }
-
- def `change the node type`: Unit = {
- val g = originalG map (_.toString)
-
- g.nodes.head.outer shouldBe a[String]
- (g.edges.head.outer: UnDiEdge[String]) shouldBe an[UnDiEdge[_]]
- g.edges.head.outer shouldBe (edge.node1.toString ~ edge.node2.toString)
- }
-
- def `change the edge type`: Unit = {
- val g = originalG.map(increment, (n1: Int, n2: Int) => n1 ~> n2)
-
- (g: Graph[Int, DiEdge[Int]]) shouldEqual Graph((edge.node1 + 1) ~> (edge.node2 + 1))
- g.isDirected shouldBe true
- }
-
- def `inspect the edges to be mapped`: Unit = {
- val g =
- originalG.map(
- increment,
- (e: originalG.EdgeT, n1: Int, _: Int) => n1 ~> (e.weight.toInt + 2)
- )
- (g: Graph[Int, DiEdge[Int]]) shouldEqual Graph(2 ~> 3)
- }
-
- def `change edge ends`: Unit = {
- val g = originalG.map(_.outer + 1, (n1: Int, _: Int) => n1 ~> 7)
- (g: Graph[Int, DiEdge[Int]]) shouldEqual Graph(3, 2 ~> 7)
- }
- }
-
- object `flat-mapping a generic undirected graph you can` {
- private val edge = 1 ~ 2
- private val originalG = Graph(edge)
-
- def increment(n: Graph[Int, UnDiEdge[Int]]#NodeT): List[Int] = n.outer + 1 :: Nil
-
- def `change nodes`: Unit = {
- val g = originalG flatMap increment
-
- originalG.nodes zip g.nodes.outerIterator foreach { case (original, mapped) =>
- increment(original).head shouldBe mapped
- }
- g.edges.head shouldBe UnDiEdge(2, 3)
- }
-
- def `add nodes`: Unit = {
- val g = originalG flatMap (n => List(n.outer, -n.outer))
- g shouldBe Graph(edge, -edge.node1, -edge.node2)
- }
-
- def `change the node type`: Unit = {
- val g = originalG flatMap (n => List(n.outer.toString, (-n.outer).toString))
- g shouldBe Graph(edge.node1.toString ~ edge.node2.toString, (-edge.node1).toString, (-edge.node2).toString)
- }
-
- def `change the edge type`: Unit = {
- val g = originalG.flatMap(
- fNode = increment,
- fEdge = (n1s: Seq[Int], n2s: Seq[Int]) =>
- (n1s, n2s) match {
- case (Seq(n1, _*), Seq(n2, _*)) => List(n1 ~> n2, n2 ~> n1)
- }
- )
- (g: Graph[Int, DiEdge[Int]]) shouldEqual Graph(2 ~> 3, 3 ~> 2)
- g.isDirected shouldBe true
- }
-
- def `change edge ends and structure`: Unit = {
- val source = Graph(1 ~ 2, 3 ~ 3)
- val g: Graph[Int, DiEdge[Int]] =
- source.flatMap(
- fNode = increment,
- fEdge = (e: source.EdgeT, n1s: Seq[Int], n2s: Seq[Int]) =>
- if (e.isLooping) Nil
- else
- (n1s, n2s) match {
- case (Seq(n1, _*), Seq(n2, _*)) =>
- List(
- n1 ~> (e.weight.toInt + 10),
- n2 ~> (e.weight.toInt + 10)
- )
- }
- )
- g.nodes.outerIterable should contain theSameElementsAs List(2, 3, 4, 11)
- g.edges.outerIterable should contain theSameElementsAs List(2 ~> 11, 3 ~> 11)
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/MappingTypedHyperSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/MappingTypedHyperSpec.scala
deleted file mode 100644
index 5bfde4f6..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/MappingTypedHyperSpec.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package scalax.collection
-
-import org.scalatest.Suites
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.generic.{Edge, GenericGraphCoreFactory}
-
-class MappingTypedHyperSpec
- extends Suites(
- new MappingTypedHyper[immutable.Graph](immutable.Graph),
- new MappingTypedHyper[mutable.Graph](mutable.Graph)
- )
-
-private class MappingTypedHyper[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]](
- val factory: GenericGraphCoreFactory[CC]
-) extends RefSpec
- with Matchers {}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/MappingTypedSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/MappingTypedSpec.scala
deleted file mode 100644
index 2853df38..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/MappingTypedSpec.scala
+++ /dev/null
@@ -1,157 +0,0 @@
-package scalax.collection
-
-import scala.language.implicitConversions
-import scala.util.chaining.*
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.edges.*
-import scalax.collection.generic.*
-import scalax.collection.immutable.{Graph, TypedGraphFactory}
-
-class MappingTypedSpec extends RefSpec with Matchers {
-
- object `mapping a typed graph you can` {
- import MappingTypedSpec.*
- import TGraph.OuterImplicits.*
-
- private val a_1 = A(1)
- private val b_0_0 = B(0, 0)
-
- def `map nodes`: Unit =
- TGraph(Connector(a_1, b_0_0)) pipe { g =>
- g.mapBound { (n: g.NodeT) =>
- n match {
- case g.InnerNode(_, a: A) => a.copy(a.a + 1)
- case g.InnerNode(_, b: B) => b.copy(b.a + 1, b.b + 1)
- }
- } shouldEqual TGraph(Connector(A(2), B(1, 1)))
- }
-
- def `downcast nodes`: Unit =
- TGraph(Connector(a_1, b_0_0)) pipe { g =>
- g.mapBound(_ => b_0_0) shouldEqual TGraph(Connector(b_0_0, b_0_0))
- }
-
- def `not upcast nodes when only passing an node mapper`: Unit =
- TGraph(AConnector(a_1, a_1)) pipe { _ =>
- "g.map(_ => b_0_0): Graph[B, Edge]" shouldNot compile
- "g.map(_.toString)" shouldNot compile
- }
-
- def `upcast nodes to another typed edge within the ADT`: Unit =
- TGraph(AConnector(a_1, a_1)) pipe { g =>
- g.mapBound[Node, Connector](_ => b_0_0, Connector.apply) pipe { mapped =>
- mapped.edges.head.outer shouldEqual Connector(b_0_0, b_0_0)
- }
- }
-
- def `upcast nodes to any type if a generic edge mapper is passed`: Unit =
- TGraph(AConnector(a_1, a_1)) pipe { g =>
- def stringify(a: A): String = s"""string-$a"""
-
- g.map(n => stringify(n.outer), UnDiEdge[String] _) pipe { mapped =>
- mapped.size shouldBe 1
- mapped.edges.head.outer shouldBe (stringify(A(1)) ~ stringify(A(1)))
- }
- }
- }
-
- object `flat-mapping a typed graph you can` {
-
- import MappingTypedSpec.*
- import TGraph.OuterImplicits.*
-
- private val a_1 = A(1)
- private val b_0_0 = B(0, 0)
-
- private def incr(a: A) = a.copy(a.a + 1)
-
- private val g = TGraph(
- Connector(A(1), B(0, 0)),
- AConnector(A(1), A(2))
- )
-
- def `change and add nodes`: Unit =
- g.flatMapBound { (n: g.NodeT) =>
- n match {
- case g.InnerNode(_, a: A) => incr(a) :: a :: Nil
- case g.InnerNode(_, _) => Nil
- }
- } shouldEqual TGraph(AConnector(A(1), A(2)), A(3))
-
- def `downcast nodes`: Unit =
- TGraph(Connector(a_1, b_0_0)) pipe { g =>
- g.flatMapBound(_ => b_0_0 :: Nil) shouldEqual TGraph(Connector(b_0_0, b_0_0))
- }
-
- def `not upcast nodes when only passing an node mapper`: Unit =
- TGraph(AConnector(a_1, a_1)) pipe { _ =>
- "g.flatMap(_ => b_0_0): Graph[B, Edge]" shouldNot compile
- "g.flatMap(_.toString)" shouldNot compile
- }
-
- def `upcast and change structure within the ADT`: Unit =
- TGraph(AConnector(A(1), A(2))) pipe { g =>
- g.flatMapBound[Node, Connector](
- fNode = n => List(incr(n.outer), b_0_0),
- fEdge = (n1s: Seq[Node], n2s: Seq[Node]) =>
- List(
- Connector(n2s.head, n1s.head),
- Connector(n2s.head, b_0_0)
- )
- ) pipe { mapped =>
- mapped.nodes.outerIterable should contain theSameElementsAs List(A(2), A(3), b_0_0)
- mapped.edges.outerIterable should contain theSameElementsAs List(
- Connector(A(3), A(2)),
- Connector(A(3), b_0_0)
- )
- }
- }
-
- def `upcast and change structure to any type if a generic edge mapper is passed`: Unit =
- TGraph(AConnector(A(1), A(2))) pipe { g =>
- def stringify(n: Any): String = s"""string-$n"""
- g.flatMap(
- fNode = n => List(stringify(incr(n.outer)), "B"),
- fEdge = (n1s: Seq[String], n2s: Seq[String]) =>
- List(
- n2s.head ~ n1s.head,
- n2s.head ~ "B"
- )
- ) pipe { (mapped: Graph[String, UnDiEdge[String]]) =>
- mapped.nodes.outerIterable should contain theSameElementsAs List(stringify(A(2)), stringify(A(3)), "B")
- mapped.edges.outerIterable should contain theSameElementsAs List(
- stringify(A(3)) ~ stringify(A(2)),
- stringify(A(3)) ~ "B"
- )
- }
- }
- }
-}
-
-private object MappingTypedSpec {
- private trait Node
- private case class A(a: Int) extends Node
- private case class B(a: Int, b: Int) extends Node
-
- sealed private trait Edge extends AnyDiEdge[Node] with PartialMapper
-
- private case class Connector(override val source: Node, override val target: Node)
- extends AbstractDiEdge[Node](source, target)
- with PartialEdgeMapper[Connector]
- with Edge {
- def map[N]: PartialFunction[(N, N), Connector] = { case (s: Node, t: Node) => copy(s, t) }
- }
-
- private case class AConnector(override val source: A, override val target: A)
- extends AbstractDiEdge[A](source, target)
- with PartialEdgeMapper[AConnector]
- with Edge {
- def map[N]: PartialFunction[(N, N), AConnector] = { case (s: A, t: A) => copy(s, t) }
- }
-
- private object TGraph extends TypedGraphFactory[Node, Edge]
-
- implicit private def aConnectorToOuterEdge(e: AConnector): OuterEdge[A, AConnector] = OuterEdge(e)
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/PathBuilderSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/PathBuilderSpec.scala
deleted file mode 100644
index 50890be1..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/PathBuilderSpec.scala
+++ /dev/null
@@ -1,60 +0,0 @@
-package scalax.collection
-
-import org.scalatest.flatspec.AnyFlatSpec
-import org.scalatest.matchers.should.Matchers
-import scalax.collection.edges.*
-import scalax.collection.generic.*
-import scalax.collection.immutable.Graph
-
-protected trait WalkBehaviors {
- this: AnyFlatSpec with Matchers =>
-
- import UnDi_1.*
-
- protected def walk(builder: => g.WalkBuilder): Unit = {
- it should "accept neighbors" in { builder add n(3) shouldBe true }
- it should "refuse non-neighbors" in { builder add n(4) shouldBe false }
- it should "accept outgoing edge" in { builder add (g get 1 ~ 2) shouldBe true }
- it should "refuse non-outgoing edge" in { builder add (g get 2 ~ 3) shouldBe false }
- }
-}
-
-class PathBuilderSpec extends AnyFlatSpec with WalkBehaviors with Matchers {
-
- import UnDi_1.*
-
- def walkBuilder = g.newWalkBuilder(n(1))
- def pathBuilder = g.newPathBuilder(n(1))
-
- "A WalkBuilder" should behave like walk(walkBuilder)
-
- "A WalkBuilder" should "yield the expected Walk" in {
- val walk = (walkBuilder += n(3) += n(5) += n(1) += n(2)).result()
- walk.nodes.toList shouldBe List(1, 3, 5, 1, 2)
- walk.edges.toList shouldBe List(1 ~> 3, 3 ~ 5, 5 ~ 1, 1 ~ 2)
- }
-
- "A PathBuilder" should behave like walk(pathBuilder)
-
- "A PathBuilder" should "refuse duplicate nodes" in {
- (pathBuilder += n(2)) add n(1) shouldBe false
- (pathBuilder += n(2) += n(3)) add n(2) shouldBe false
- }
-
- "A PathBuilder" should "refuse duplicate edges" in {
- (pathBuilder += n(2) += n(3)) add e(2 ~ 3) shouldBe false
- }
-
- "PathBuilder result" should "discard a terminating edge" in {
- (pathBuilder += n(2) += e(2 ~ 3)).result().edges should have size 1
- }
-
- it should "yield the expected Path" in {
- val path = (pathBuilder += n(3) += n(5)).result()
- path.nodes.toList shouldBe List(1, 3, 5)
- path.edges.toList shouldBe List(1 ~> 3, 3 ~ 5)
- }
-}
-
-// The single graph used for this test
-protected object UnDi_1 extends TGraph[Int, AnyEdge[Int], Graph](Graph.from(Data.elementsOfMixed_1))
diff --git a/coreTestScala3/src/test/scala/scalax/collection/SerializableSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/SerializableSpec.scala
deleted file mode 100644
index 86e7c0c6..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/SerializableSpec.scala
+++ /dev/null
@@ -1,378 +0,0 @@
-package scalax.collection
-
-import java.io.*
-
-import scala.util.{Failure, Success, Try}
-
-import org.scalatest.*
-import org.scalatest.flatspec.AnyFlatSpec
-import org.scalatest.matchers.should.Matchers
-
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.{AnyEdge, Edge, GenericGraphCoreFactory}
-import scalax.collection.visualization.Visualizer
-
-class SerializableSpec
- extends Suites(
- new TSerializable[immutable.Graph](immutable.Graph),
- new TSerializable[mutable.Graph](mutable.Graph)
- )
-
-/** Tests standard java serialization.
- */
-final private class TSerializable[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]](
- val factory: GenericGraphCoreFactory[CC]
-) extends AnyFlatSpec
- with Matchers
- with BeforeAndAfterEach
- with IntelliJ[CC]
- with Visualizer {
- private val factoryName = factory.getClass.getName
- private val isImmutableTest = factoryName contains "immutable"
-
- s"Tests based on $factoryName" should "start" in {}
-
- trait GraphStore {
- protected trait ExecMethods {
- def save[N, E <: Edge[N]](g: CC[N, E]): Unit
- def restore[N, E <: Edge[N]]: CC[N, E]
- }
- protected def newTest: ExecMethods
- def test[N, E <: Edge[N]](g: CC[N, E]): CC[N, E] = {
- val exec = newTest
- exec.save[N, E](g)
- val r = exec.restore[N, E]
- withGraph(r.asAnyGraph)(_ should equal(g))
- r
- }
- }
-
- /** to save and restore graphs to/from files */
- object GraphFile extends GraphStore {
- protected class Exec(filename: String) extends ExecMethods {
- import FileSerialization.*
- def save[N, E <: Edge[N]](g: CC[N, E]): Unit = write(g, filename) recover { case e =>
- fail(s"Couldn't write $g: $e")
- }
-
- def restore[N, E <: Edge[N]]: CC[N, E] = read(filename).recover { case e =>
- fail(s"Couldn't read graph: $e")
- }.get
- }
- private val tmpDir = System.getProperty("java.io.tmpdir")
- private var cnt = 0
- protected def newTest: Exec = {
- cnt += 1
- new Exec( // include the name of the test method
- s"$tmpDir${File.separator}${s"${this.getClass.getSimpleName.init}.${if (isImmutableTest) "i" else "m"}-${testNames.toArray.apply(cnt)}"}.ser"
- )
- }
- }
-
- /** to save and restore graphs to/from byte arrays */
- object GraphByteArray extends GraphStore {
- protected class Exec extends ExecMethods {
- import ByteArraySerialization.*
- private var _saved: Array[Byte] = _
-
- def save[N, E <: Edge[N]](g: CC[N, E]): Unit = write(g) match {
- case Success(s) => _saved = s
- case Failure(e) => fail("Couldn't write: " + g, e)
- }
-
- def restore[N, E <: Edge[N]]: CC[N, E] = read[CC[N, E]](_saved) match {
- case Success(s) => s
- case Failure(e) => fail("Couldn't read graph", e)
- }
- }
- protected def newTest: Exec = new Exec
- }
-
- /** normally we test with byte arrays but may be set to GraphFile instead */
- private lazy val store: GraphStore = GraphByteArray
-
- private val work = "be serializable"
-
- "An empty graph" should work in {
- val g = factory.empty[Nothing, Nothing]
- store.test[Nothing, Nothing](g)
- }
-
- "A graph of type [Int,Nothing]" should work in {
- val g = factory[Int, Nothing](-1, 1, 2)
- store.test[Int, Nothing](g)
- }
-
- "A graph of type [Int,UnDiEdge]" should work in {
- val g = factory[Int, AnyEdge](-1 ~ 1, 2 ~> 1)
- store.test[Int, AnyEdge[Int]](g)
- }
-
- "A graph of type [String,UnDiEdge]" should work in {
- val g = factory[String, AnyEdge]("a" ~ "b", "b" ~> "c")
- store.test[String, AnyEdge[String]](g)
- }
-
- "A graph of type [Int,DiEdge]" should work in {
- import Data.elementsOfDi_1
- val g = factory(elementsOfDi_1: _*)
- store.test[Int, DiEdge[Int]](g)
- }
-
- /* TODO L
- "A graph of [MyNode,WLDiEdge]" should work in {
- import edge.WLDiEdge
-
- val (a1, a2, b1, b2) = ("a1", "a2", "b1", "b2")
- val (n1, n2) = (MyNode(List(a1, b1)), MyNode(List(a2, b2)))
- val label = MyLabel("abab")
- val e = WLDiEdge(n1, n2)(11, label)
-
- {
- /* if MyNode is declared as an inner class, it is not serializable;
- * so we assert first, that both the node class and the label class are serializable
- */
- val bos = new ByteArrayOutputStream
- val out = new ObjectOutputStream(bos)
- out writeObject n1
- out writeObject label
- bos.close
- }
-
- given(factory(e)) { g =>
- val back = store.test[MyNode, WLDiEdge](g)
-
- back.size should be(1)
-
- val inner_1 = back get n1
- inner_1.diSuccessors should have size 1
- inner_1.diSuccessors.head should be(n2)
-
- val backEdge = back.edges.head
- backEdge.source.s should be(List(a1, b1))
- backEdge.target.s should be(List(a2, b2))
- backEdge.label should be(label)
- }
- }
- */
-
- "After calling diSuccessors the graph" should work in {
- import Data.elementsOfDi_1
- val g = factory(elementsOfDi_1: _*)
- g.nodes.head.diSuccessors
- store.test[Int, DiEdge[Int]](g)
- }
-
- "After calling pathTo the graph" should work in {
- import Data.elementsOfDi_1
- val g = factory(elementsOfDi_1: _*)
- g.nodes.head.diSuccessors
- val n = g.nodes.head
- n.pathTo(n)
- store.test[Int, DiEdge[Int]](g)
- }
-
- "A deserialized graph" should "be traversable" in {
- import Data.elementsOfDi_1
- val g = factory(elementsOfDi_1: _*)
- val back = store.test[Int, DiEdge[Int]](g)
- withGraph(g.asAnyGraph) { g =>
- def op(g: AnyGraph[Int, DiEdge[Int]]): Int = g.nodes.head.outerNodeTraverser.size
- op(back.asAnyGraph) shouldBe op(g)
- }
- }
-
- "A deserialized graph" should "have the same successors" in {
- import Data.elementsOfDi_1
- val g = factory(elementsOfDi_1: _*)
-
- def outerSuccessors(g: AnyGraph[Int, DiEdge[Int]]) =
- g.nodes map (innerNode => innerNode.outer -> innerNode.diSuccessors.map(_.outer))
-
- val diSuccBefore = outerSuccessors(g.asAnyGraph)
- val back = store.test[Int, DiEdge[Int]](g)
- withGraph(g.asAnyGraph) { g =>
- outerSuccessors(back.asAnyGraph) shouldBe diSuccBefore
- }
- }
-
- trait EdgeStore {
- def save[N, E <: Edge[N]](e: Iterable[OuterElem[N, E]]): Unit
- def restore[N, E <: Edge[N]]: Iterable[OuterElem[N, E]]
- def test[N, E <: Edge[N]](e: Iterable[OuterElem[N, E]]): Iterable[OuterElem[N, E]] = {
- save[N, E](e)
- val r = restore[N, E]
- r should be(e)
- r
- }
- }
-
- class EdgeByteArray extends EdgeStore {
- import ByteArraySerialization.*
- private var _saved: Array[Byte] = _
-
- def save[N, E <: Edge[N]](it: Iterable[OuterElem[N, E]]): Unit = write(it) match {
- case Success(s) => _saved = s
- case Failure(e) => fail(s"Couldn't write '$it': $e")
- }
-
- def restore[N, E <: Edge[N]]: Iterable[OuterElem[N, E]] =
- readWithCustomClassLoader[Iterable[OuterElem[N, E]]](_saved) match {
- case Success(s) => s
- case Failure(e) => fail(s"Couldn't read iterable: $e")
- }
- }
-
- "A graph of [Int, AnyEdge[Int]]" should work in {
- import Data.elementsOfMixed_2
- withGraph(factory.from(elementsOfMixed_2).asAnyGraph) { _ =>
- (new EdgeByteArray).test[Int, AnyEdge[Int]](elementsOfMixed_2)
- }
- }
-}
-
-object ByteArraySerialization {
- def write(obj: AnyRef, initSize: Int = 8000): Try[Array[Byte]] = {
- val bos = new ByteArrayOutputStream(initSize)
- val out = new ObjectOutputStream(bos)
- Try {
- out writeObject obj
- out.close()
- bos.toByteArray
- } recoverWith { case e =>
- out.close()
- Failure[Array[Byte]](e)
- }
- }
-
- def readWithCustomClassLoader[A](from: Array[Byte]): Try[A] =
- read[A](new CustomObjectInputStream(new ByteArrayInputStream(from), classOf[SerializableSpec].getClassLoader))
-
- def read[A](from: Array[Byte]): Try[A] =
- read(new ObjectInputStream(new ByteArrayInputStream(from)))
-
- def read[A](in: ObjectInputStream): Try[A] =
- Try {
- val read = in.readObject
- in.close()
- read.asInstanceOf[A]
- } recoverWith { case e =>
- in.close()
- Failure[A](e)
- }
-
- // resolves ClassNotFoundException
- private class CustomObjectInputStream(in: InputStream, classLoader: ClassLoader) extends ObjectInputStream(in) {
- import java.lang.reflect.Proxy
- import java.lang.reflect.{InvocationHandler, Method}
-
- override def resolveClass(cd: ObjectStreamClass): Class[_] =
- try
- classLoader.loadClass(cd.getName)
- catch {
- case cnf: ClassNotFoundException =>
- super.resolveClass(cd)
- }
- override def resolveProxyClass(interfaces: Array[String]): Class[_] = {
- val classInterfaces = interfaces map classLoader.loadClass
- try
- Proxy.newProxyInstance(classLoader, classInterfaces, new DummyInvocationHandler).getClass
- catch {
- case e: ClassNotFoundException =>
- super.resolveProxyClass(interfaces)
- }
- }
-
- private class DummyInvocationHandler extends InvocationHandler {
- def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]): AnyRef =
- throw new NotImplementedError(s"${getClass.getSimpleName} should never be called.")
- }
- }
-}
-
-object FileSerialization {
- def write(obj: AnyRef, filename: String): Try[File] = write(obj, new File(filename))
- def write(obj: AnyRef, file: File): Try[File] = {
- var out: ObjectOutputStream = null
- Try {
- out = new ObjectOutputStream(new FileOutputStream(file))
- out writeObject obj
- out.close()
- file
- } recoverWith { case e =>
- if (out ne null) out.close()
- Failure[File](e)
- }
- }
- def read[A](filename: String): Try[A] = read(new File(filename))
- def read[A](file: File): Try[A] = {
- var in: ObjectInputStream = null
- Try {
- in = new ObjectInputStream(new FileInputStream(file))
- val read = in.readObject
- in.close()
- read.asInstanceOf[A]
- } recoverWith { case e =>
- if (in ne null) in.close()
- Failure[A](e)
- }
- }
-}
-
-// to be serializable, the following classes must be defined at top level
-case class MyNode(s: List[String]) extends Serializable
-case class MyLabel(s: String) extends Serializable
-
-// examining https://issues.scala-lang.org/browse/SI-5773?jql=text%20~%20%22%40transient%22
-protected object ScalaObjectSerialization extends App {
-
- private trait Base {
- trait Inner {
- def d: String
- def v: String
- }
- def inner: Inner
- }
-
- private object MyObject extends Base with Serializable {
- @transient // ok: no serialization takes place
- object Inner extends super.Inner {
- def d = "MyDef"
- val v = "MyVal"
- }
- def inner = Inner
- }
-
- private trait MyTrait extends Base with Serializable {
- @transient // !!! ignored so Serializable needs to be mixed in
- object Inner extends super.Inner with Serializable {
- def d = "MyDef"
- val v = "MyVal"
- }
- val inner = Inner
- }
-
- private class MyClass extends Base with Serializable {
- @transient // !!! same as MyTrait
- object Inner extends super.Inner with Serializable {
- def d = "MyDef"
- val v = "MyVal"
- }
- val inner = Inner
- }
-
- import ByteArraySerialization.*
- private def test[A <: Base](my: A): Unit =
- write(my) flatMap { saved =>
- println(s"saved (${saved.length} bytes)=${new String(saved)}")
- println(s" contains MyVal=${new String(saved) contains "MyVal"}")
- read[A](saved)
- } map (my => println(s" okDef=${my.inner.d}, okVal=${my.inner.v}")) recover { case e =>
- println(s"serialization of $my failed with $e")
- }
-
- test(MyObject)
- test(new MyTrait {})
- test(new MyClass)
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/SetOpsSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/SetOpsSpec.scala
deleted file mode 100644
index d6739bb0..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/SetOpsSpec.scala
+++ /dev/null
@@ -1,100 +0,0 @@
-package scalax.collection
-
-import scala.util.chaining.*
-
-import org.scalatest.Suites
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.{Edge, GenericGraphCoreFactory}
-import scalax.collection.visualization.Visualizer
-
-class SetOpsSpec
- extends Suites(
- new SetOps[immutable.Graph](immutable.Graph),
- new SetOps[mutable.Graph](mutable.Graph),
- new SetOpsImmutable,
- new SetOpsMutable
- )
-
-protected trait SetOpExamples[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]] {
-
- protected def factory: GenericGraphCoreFactory[CC]
-
- protected val gEdges = Set(1 ~ 2, 2 ~ 3, 2 ~ 4, 3 ~ 5, 4 ~ 5)
- protected val hEdges = Set(3 ~ 4, 3 ~ 5, 4 ~ 6, 5 ~ 6)
-
- protected def g = factory.from(gEdges)
- protected def h = factory.from(hEdges)
-
- protected object Expected {
- val g_union_h = factory.from(gEdges ++ hEdges)
- val g_diff_h =
- g.nodes.toOuter -- h.nodes.toOuter pipe { nDiff =>
- factory.from(nDiff, gEdges ++ hEdges filter { case n1 ~ n2 => nDiff(n1) && nDiff(n2) })
- }
- }
-}
-
-private class SetOps[CC[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, CC]](
- val factory: GenericGraphCoreFactory[CC]
-) extends RefSpec
- with Matchers
- with SetOpExamples[CC]
- with IntelliJ[CC]
- with Visualizer {
-
- def `concat ` : Unit = {
- factory(1 ~ 2).asAnyGraph concat List(1 ~ 2)
- factory(1 ~ 2).asAnyGraph concat List(1 ~> 2)
- factory(1 ~ 2).asAnyGraph ++ List(1 ~ 2)
-
- factory(1 ~ 2) concat List("a" ~ "b"): AnyGraph[Any, UnDiEdge[Any]]
- factory(1 ~ 2) concat (List('x'), List("a" ~ "b")): AnyGraph[Any, UnDiEdge[Any]]
-
- factory(1 ~ 2).asAnyGraph concat (List('x'), List('a' ~ 'b'))
- factory(1 ~ 2).asAnyGraph ++ (List('x'), List('a' ~ 'b'))
- }
-
- def `union ` : Unit =
- g union h shouldEqual Expected.g_union_h
-
- def `difference ` : Unit =
- g diff h shouldEqual Expected.g_diff_h
-
- def `intersection ` : Unit = {
- val expected = factory(3 ~ 5, 4)
- withGraph(g intersect h)(_ shouldEqual expected)
- withGraph(g & h)(_ shouldEqual expected)
- }
-}
-
-private class SetOpsImmutable extends RefSpec with Matchers with SetOpExamples[immutable.Graph] {
- protected val factory = immutable.Graph
-
-}
-
-private class SetOpsMutable extends RefSpec with Matchers with SetOpExamples[mutable.Graph] {
- protected val factory = mutable.Graph
-
- private val iH = immutable.Graph.from(hEdges)
-
- def `unionInPlace ` : Unit = {
- (g |= h) shouldEqual Expected.g_union_h
- (g |= iH) shouldEqual Expected.g_union_h
- }
-
- def `--= ` : Unit = {
- (g --= h) shouldEqual Expected.g_diff_h
- (g --= iH) shouldEqual Expected.g_diff_h
- }
-
- def `&= ` : Unit = {
- val expected = factory(3 ~ 5, 4)
-
- (g &= h) shouldEqual expected
- (g &= iH) shouldEqual expected
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/StateSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/StateSpec.scala
deleted file mode 100644
index b8376560..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/StateSpec.scala
+++ /dev/null
@@ -1,127 +0,0 @@
-package scalax.collection
-
-import scala.collection.mutable.Map as MutableMap
-import scala.concurrent.ExecutionContext.Implicits.*
-import scala.concurrent.duration.*
-import scala.concurrent.{Await, Future}
-import scala.language.postfixOps
-import scala.util.Random
-
-import org.scalatest.Inspectors.*
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generator.{NodeDegreeRange, RandomGraph}
-import scalax.collection.immutable.Graph
-
-/** Ensure that stateful data handling used for traversals is thread-safe.
- */
-class StateSpec extends RefSpec with Matchers {
- val g = Graph.from(Data.elementsOfMixed_2)
-
- // a sample traversal with recursive calls in its node visitor
- def countNodes(recursion: Int = 0): Int = {
- assert(recursion >= 0)
- var nrNodes = 0
- g.nodes.head.innerNodeTraverser foreach { _ =>
- nrNodes += (
- if (recursion == 0) 1
- else countNodes(recursion - 1)
- )
- }
- nrNodes
- }
-
- val nrNodesExpected = g.order
- val aLotOfTimes = 162 // at least 2 times State.nrOfFlagWordBits
-
- def dump: Unit =
- println(State.dump(g))
-
- object `Single-threaded shared state proves robust` {
- def `when looping`: Unit =
- for (i <- 1 to aLotOfTimes)
- countNodes() should be(nrNodesExpected)
-
- def `when looping at visited nodes`: Unit =
- g.nodes.head.innerNodeTraverser foreach (_ => `when looping`)
-
- def `when called recursively`: Unit = {
- val depth = 5
- countNodes(depth) should be(math.pow(3, depth) * nrNodesExpected)
- }
-
- def `when called deep-recursively`: Unit = {
- val recurseAt = g.nodes.head
- def countNodesDeep(recursion: Int): Int = {
- assert(recursion >= 0)
- var nrNodes = 0
- g.nodes.head.innerNodeTraverser foreach (n =>
- nrNodes += (
- // if (n eq recurseAt) println(State.dump(recurseAt).summary)
- if (recursion == 0) 0
- else if (n eq recurseAt) countNodesDeep(recursion - 1)
- else 1
- )
- )
- nrNodes
- }
- for (i <- 1 to 2) countNodesDeep(aLotOfTimes)
- }
-
- def `when cleaned up after lots of unconnected traversals`: Unit = {
- val order = 5000
- val r = new Random(10 * order)
-
- def intNodeFactory = r.nextInt()
- val g =
- new RandomGraph[Int, DiEdge[Int], Graph](
- Graph,
- order,
- intNodeFactory,
- NodeDegreeRange(0, 2),
- Set(DiEdge),
- false
- ).draw
-
- val rootNodes = List.fill(50)(g.nodes.draw(r))
- for {
- node <- g.nodes
- root <- rootNodes
- } node.hasSuccessor(root)
- }
- }
-
- object `Multi-threaded shared state proves robust` {
- def `when traversing by futures`: Unit = {
- val traversals = Future.sequence(
- for (i <- 1 to aLotOfTimes)
- yield Future(countNodes())
- )
-
- // statistics map with key = nrOfNodesCounted, value = frequency
- val stat = MutableMap.empty[Int, Int]
-
- Await.result(traversals, 1 seconds) foreach { cnt =>
- stat += cnt -> (stat.getOrElse(cnt, 0) + 1)
- }
-
- // each traversal must yield the same result
- stat should be(Map(nrNodesExpected -> aLotOfTimes))
- }
-
- def `when tested under stress fixing #34`: Unit = {
- import Data.*
- object g extends TGraph[Int, DiEdge[Int], Graph](Graph(elementsOfDi_1: _*))
- def n(outer: Int) = g.node(outer)
- val (n1, n2) = (n(2), n(5))
-
- val times = 200000
- def run: Future[Seq[Boolean]] = Future.sequence((1 to times) map (_ => Future(n1 pathTo n2) map (_.nonEmpty)))
- val bulks: Future[Seq[Boolean]] = Future.sequence((1 to 3) map (_ => run)) map (_.flatten)
-
- forAll(Await.result(bulks, 50.seconds))(_ shouldBe true)
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/TopologicalSortSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/TopologicalSortSpec.scala
deleted file mode 100644
index 1f2a2318..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/TopologicalSortSpec.scala
+++ /dev/null
@@ -1,273 +0,0 @@
-package scalax.collection
-
-import org.scalatest.*
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-
-import scalax.collection.GraphTraversal.*
-import scalax.collection.GraphTraversal.Parameters.*
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.{Edge, GenericGraphCoreFactory}
-import scalax.collection.visualization.Visualizer
-
-class TopologicalSortSpec
- extends Suites(
- new TopologicalSort[immutable.Graph](immutable.Graph),
- new TopologicalSort[mutable.Graph](mutable.Graph)
- )
-
-final private class TopologicalSort[G[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, G]](
- val factory: GenericGraphCoreFactory[G]
-) extends RefSpec
- with Matchers
- with ScalaCheckPropertyChecks
- with IntelliJ[G]
- with Visualizer {
-
- private object Topo {
-
- class Checker[N, E <: Edge[N]](val graph: AnyGraph[N, E]) {
-
- def checkOuterNodes(seq: Iterable[N]): Unit =
- checkInnerNodes(seq map (graph get _))
-
- type OrderedInnerNodes = Iterable[graph.NodeT]
-
- def checkInnerNodes(
- seq: OrderedInnerNodes,
- root: Option[graph.NodeT] = None,
- ignorePredecessors: Boolean = false
- ): Unit = {
- def predecessors(maybeRoot: Option[graph.NodeT]): Set[graph.NodeT] =
- maybeRoot.fold(
- ifEmpty = Set.empty[graph.NodeT]
- ) { root =>
- root.innerNodeTraverser().withParameters(Dfs(Predecessors)).toSet - root
- }
-
- def checkOrder(seq: OrderedInnerNodes, ignorePredecessorsOf: Option[graph.NodeT]): Unit =
- seq.foldLeft(predecessors(ignorePredecessorsOf)) { (allowedPredecessors, innerNode) =>
- if (!innerNode.diPredecessors.forall(allowedPredecessors.contains))
- fail(s"$innerNode is misplaced in $seq")
- allowedPredecessors + innerNode
- }
-
- def checkCompleteness(
- seq: OrderedInnerNodes,
- maybeRoot: Option[graph.NodeT],
- ignorePredecessors: Boolean
- ): Unit = {
- val expected = maybeRoot.fold(
- ifEmpty = graph.nodes.toSet
- ) { root =>
- root.innerNodeTraverser().withParameters(Dfs(AnyConnected)).toSet --
- (if (ignorePredecessors) predecessors(maybeRoot) else Nil)
- }
- val set = seq.toSet
- if (set != expected)
- fail(
- s"Ordering is incomplete when root=$maybeRoot and ignorePredecessors=$ignorePredecessors: expected $expected but was $set."
- )
- }
-
- checkOrder(seq, if (ignorePredecessors) root else None)
- checkCompleteness(seq, root, ignorePredecessors)
- }
- }
-
- def unexpectedCycle[N, E <: Edge[N]](cycleNode: AnyGraph[N, E]#TopologicalSortFailure): Nothing =
- fail(s"Unexpected cycle with candidate cycle nodes $cycleNode")
-
- def unexpectedRight[N, E <: Edge[N]](order: AnyGraph[N, E]#TopologicalOrder[_]): Nothing =
- fail(s"Cycle expected but topological order ${order.toLayered} found")
-
- def checkCycleHint(
- g: AnyGraph[Int, DiEdge[Int]]
- )(hint: g.TopologicalSortFailure, expectedDefined: Boolean): Unit =
- (hint.candidateCycleNodes, expectedDefined) match {
- case (ns, true) if ns.nonEmpty =>
- hint.cycle orElse fail(s"Cycle containing any of $ns expected but none found.")
- case (ns, false) if ns.nonEmpty => fail(s"Unexpected cycle node hints $ns found.")
- case (_, true) => fail(s"Non-empty cycle node hint expected.")
- case (_, false) =>
- }
- }
-
- def `empty graph`(): Unit =
- withGraph(factory.empty[Int, DiEdge[Int]].asAnyGraph) {
- _.topologicalSort.fold(
- Topo.unexpectedCycle,
- _ shouldBe empty
- )
- }
-
- def `daily activities`(): Unit = {
-
- object Activities {
- val (coffee, coding, inspiration, shopping, sleeping, supper, gaming) =
- ("coffee", "coding", "inspiration", "shopping", "sleeping", "supper", "gaming")
- val (making_music, driving_to_work, driving_home, listening_to_music) =
- ("making music", "driving to work", "driving home", "listening to music")
- }
- import Activities.*
-
- val typicalDay = factory[String, DiEdge](
- coffee ~> coding,
- inspiration ~> coding,
- shopping ~> coffee,
- coding ~> sleeping,
- supper ~> sleeping,
- gaming ~> sleeping,
- making_music ~> sleeping,
- inspiration ~> making_music,
- shopping ~> supper,
- driving_home ~> supper,
- driving_home ~> sleeping,
- coding ~> driving_home,
- driving_to_work ~> coding,
- driving_to_work ~> driving_home,
- driving_home ~> gaming,
- listening_to_music
- ).asAnyGraph
-
- withGraph(typicalDay) {
- _.topologicalSort.fold(
- Topo.unexpectedCycle,
- order =>
- new Topo.Checker(typicalDay) {
- checkOuterNodes(order.toOuter)
- }
- )
- }
- }
-
- def `connected graph`(): Unit = {
- val someOuter @ n0 :: n1 :: n5 :: Nil = 0 :: 1 :: 5 :: Nil: @unchecked
- val connected = factory[Int, DiEdge](n0 ~> n1, 2 ~> 4, 2 ~> n5, n0 ~> 3, n1 ~> 4, 4 ~> 3).asAnyGraph
- withGraph(connected) { g =>
- g.isMulti shouldBe false
- g.topologicalSort.fold(
- Topo.unexpectedCycle,
- order =>
- new Topo.Checker(connected) {
- checkOuterNodes(order.toOuter)
- for {
- outer <- someOuter
- inner = graph get outer
- ignorePredecessors <- Array(false, true)
- }
- inner
- .topologicalSort(ignorePredecessors)
- .fold(Topo.unexpectedCycle, order => checkInnerNodes(order, Some(inner), ignorePredecessors))
- }
- )
- }
- }
-
- def `multi graph`(): Unit = {
- import scalax.collection.edges.multilabeled.*
-
- val g = factory(1 ~> 2 %% 0, 1 ~> 2 %% 1).asAnyGraph
-
- g.topologicalSort.fold(
- Topo.unexpectedCycle,
- order =>
- new Topo.Checker(g) {
- checkOuterNodes(order.toOuter)
- }
- )
- }
-
- def `unconnected graph`(): Unit = {
- val expectedLayer_0 @ _1 :: _3 :: Nil = List(1, 3): @unchecked
- val expectedLayer_1 @ _2 :: _4 :: Nil = List(2, 4): @unchecked
- withGraph(factory(_1 ~> _2, _3 ~> _4)) {
- _.topologicalSort.fold(
- Topo.unexpectedCycle,
- _.toLayered.toOuter.toList match {
- case (layer_0 :: layer_1 :: Nil) =>
- layer_0._2.toList.sorted should be(expectedLayer_0)
- layer_1._2.toList.sorted should be(expectedLayer_1)
- case _ => fail()
- }
- )
- }
- }
-
- def `minimal cyclic graph`(): Unit =
- withGraph(factory(1 ~> 2, 2 ~> 1)) { g =>
- g.topologicalSort.fold(
- Topo.checkCycleHint(g)(_, expectedDefined = false),
- Topo.unexpectedRight
- )
- }
-
- def `cyclic graph #68`(): Unit =
- withGraph(factory(0 ~> 7, 4 ~> 7, 7 ~> 3, 3 ~> 4, 0 ~> 5)) { g =>
- g.topologicalSort.fold(
- Topo.checkCycleHint(g)(_, expectedDefined = true),
- Topo.unexpectedRight
- )
- }
-
- def `cyclic graphs #264`(): Unit =
- withGraph(
- factory(
- 111 ~> 2,
- 2 ~> 111,
- 111 ~> 33
- ) ++ (for {
- i <- Range.inclusive(33, 230, step = 10)
- j = i + 10
- } yield i ~> j)
- ) { g =>
- g.topologicalSort.fold(
- Topo.checkCycleHint(g)(_, expectedDefined = false),
- Topo.unexpectedRight
- )
- }
-
- def `cyclic unconnected graph`(): Unit =
- withGraph(factory(11100 ~> 2, 6 ~> 7, 2 ~> 11100, 3 ~> 4)) { g =>
- g.topologicalSort.fold(
- Topo.checkCycleHint(g)(_, expectedDefined = false),
- Topo.unexpectedRight
- )
- }
-
- def `cyclic unconnected graph by component`(): Unit =
- withGraph(factory(11100 ~> 2, 6 ~> 7, 2 ~> 11100, 3 ~> 4)) { g =>
- val r = g.topologicalSortByComponent
- r.size shouldBe 3
- r.count(_.isLeft) shouldBe 1
- }
-
- def `proper cycle node out of multiple hints`(): Unit =
- withGraph(factory(0 ~> 11, 0 ~> 20, 1 ~> 20, 11 ~> 20, 11 ~> 30, 30 ~> 11)) { g =>
- g.topologicalSort.fold(
- Topo.checkCycleHint(g)(_, expectedDefined = true),
- Topo.unexpectedRight
- )
- }
-
- def `with filtered edges #104`(): Unit = {
- import scalax.collection.edges.labeled.*
-
- withGraph(factory(1 ~> 3 % 1, 1 ~> 2 % 2, 2 ~> 3 % 1)) { g =>
- val n1 = g get 1
- n1.topologicalSort().isRight shouldBe true
-
- n1.withSubgraph(edges = _.weight == 1)
- .topologicalSort()
- .fold(
- Topo.unexpectedCycle,
- order =>
- new Topo.Checker(g) {
- checkOuterNodes(order.toOuter)
- }
- )
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/TraversalSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/TraversalSpec.scala
deleted file mode 100644
index d23c34eb..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/TraversalSpec.scala
+++ /dev/null
@@ -1,382 +0,0 @@
-package scalax.collection
-
-import scala.collection.mutable.ListBuffer
-
-import org.scalatest.*
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-
-import scalax.collection.GraphTraversal.*
-import scalax.collection.OuterImplicits.*
-import scalax.collection.edges.*
-import scalax.collection.generic.{Edge, GenericGraphCoreFactory}
-import scalax.collection.visualization.Visualizer
-
-class TraversalSpec
- extends Suites(
- new Traversal[immutable.Graph](immutable.Graph),
- new Traversal[mutable.Graph](mutable.Graph)
- )
-
-/** This class contains tests for graph traversals to be run for Graph instances created
- * by the Graph factory and passed to the constructor.
- * It allows the same tests to be run for mutable and immutable Graphs.
- */
-final private class Traversal[G[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, G]](
- val factory: GenericGraphCoreFactory[G]
-) extends RefSpec
- with Matchers
- with ScalaCheckPropertyChecks
- with IntelliJ[G]
- with Visualizer {
-
- implicit val config: PropertyCheckConfiguration =
- PropertyCheckConfiguration(minSuccessful = 5, maxDiscardedFactor = 1.0)
-
- val predecessors = Parameters(direction = Predecessors)
- val anyConnected = Parameters(direction = AnyConnected)
-
- def `find successors in a tiny graph`: Unit =
- withGraph(factory(1 ~> 2).asAnyGraph) { g =>
- val (n1, n2) = (g get 1, g get 2)
-
- List(1, 3) foreach { i =>
- n1 findSuccessor (_.outer == i) shouldBe empty
- }
- n2 findSuccessor (_.outer == 1) shouldBe empty
- n1 findSuccessor (_.outer == 2) shouldBe Some(n2)
- }
-
- def `find predecessors in a tiny graph`: Unit =
- withGraph(factory(1 ~> 2)) { g =>
- val (n1, n2) = (g get 1, g get 2)
-
- 1 to 3 foreach { i =>
- n1 findPredecessor (_.outer == i) shouldBe empty
- }
- val predecessor = n2 findPredecessor (_.outer == 1)
- predecessor shouldBe Some(n1)
- }
-
- def `find connected nodes by predicate in a tiny graph`: Unit =
- withGraph(factory(1 ~> 2)) { g =>
- val (n1, n2) = (g get 1, g get 2)
-
- List(1, 3) foreach { i =>
- n1 findConnected (_.outer == i) shouldBe empty
- }
- n1 findConnected (_.outer == 2) shouldBe Some(n2)
- n2 findConnected (_.outer == 1) shouldBe Some(n1)
- }
-
- import Data.*
- object Di_1 extends TGraph(factory.from(elementsOfDi_1))
- object UnDi_1 extends TGraph(factory.from(elementsOfMixed_1))
-
- def `find successors in a mid-size graph`: Unit =
- withGraph(Di_1.g.asAnyGraph) { g =>
- def n(outer: Int) = g.get(outer)
-
- List(0, 3, 7) foreach { i =>
- n(3) findSuccessor (_.outer == i) shouldBe empty
- }
- n(2) findSuccessor (_.outer == 5) shouldBe Some(5)
- n(3) findSuccessor (_.outer > 4) shouldBe Some(5)
- }
-
- def `find predecessors in a mid-size graph`: Unit =
- withGraph(Di_1.g.asAnyGraph) { g =>
- def n(outer: Int) = g.get(outer)
-
- List(0, 3, 5) foreach { i =>
- n(3) findPredecessor (_.outer == i) shouldBe empty
- }
- n(3) findPredecessor (_.outer == 4) shouldBe Some(4)
- n(3) findPredecessor (_ > 2) shouldBe Some(4)
- }
-
- def `find connected nodes by predicate`: Unit =
- withGraph(Di_1.g.asAnyGraph) { g =>
- def n(outer: Int) = g get outer
-
- List(0, 3) foreach { i =>
- n(3) findConnected (_.outer == i) shouldBe empty
- }
- n(2) findConnected (_.outer == 4) shouldBe Some(4)
- n(3) findConnected (_.outer > 3) should (be(Some(4)) or be(Some(5)))
- }
-
- def `find path to a successor`: Unit =
- withGraph(factory(1, 2 ~ 3, 3 ~ 4, 5 ~ 6, 6 ~ 1)) { g =>
- val n1 = g get 1
- n1 pathUntil (_ == n1) shouldBe None
-
- val n2 = g get 2
- n2 pathUntil (_ == n1) shouldBe None
-
- val n5 = g get 5
- val n6 = g get 6
- val expected = List(n5, n6, n1)
- val r5 = n5 pathUntil (_ < 4)
- r5 shouldBe defined
- val p5 = r5.get
- p5.nodes.toList shouldBe expected
-
- p5.size shouldBe (expected.size + (expected.size - 1))
- p5.length shouldBe (expected.size - 1)
- }
-
- def `find path to a successor in a minimalistic graph`: Unit =
- withGraph(factory(0 ~ 1, 1 ~ 2)) { g =>
- def n(outer: Int) = g get outer
- for (i <- 0 to 2)
- (n(0) pathTo n(i)).get.length shouldBe i
- }
-
- def `assert fix_110409 of shortestPathTo`: Unit =
- withGraph(factory(0 ~ 1, 1 ~ 2, 2 ~ 3)) { g =>
- def n(outer: Int) = g get outer
- (n(0) shortestPathTo n(0)).get.length shouldBe 0
- (n(0) shortestPathTo n(3)).get.nodes.toList shouldBe List(0, 1, 2, 3)
- (n(1) shortestPathTo n(3)).get.nodes.toList shouldBe List(1, 2, 3)
- }
-
- def `traverser to graph`: Unit =
- withGraph(Di_1.g.asAnyGraph) { g =>
- def innerNode(outer: Int) = g get outer
-
- innerNode(1).outerNodeTraverser.to(factory) should equal(factory(1 ~> 2, 2 ~> 3, 3 ~> 5, 1 ~> 5, 1 ~> 3))
-
- innerNode(2).outerNodeTraverser(anyConnected).to(factory) should equal(
- factory(1 ~> 2, 2 ~> 3, 4 ~> 3, 3 ~> 5, 1 ~> 5, 1 ~> 3)
- )
-
- innerNode(3).outerNodeTraverser(predecessors).to(factory) should equal(factory(4 ~> 3, 1 ~> 3, 2 ~> 3, 1 ~> 2))
- }
-
- def `traverser with an extended visitor`: Unit =
- withGraph(UnDi_1.g.asAnyGraph) { g =>
- import g.ExtendedNodeVisitor
- def n(outer: Int) = g get outer
-
- var lastCount = 0
- n(1).innerNodeTraverser.withKind(DepthFirst) foreach
- ExtendedNodeVisitor { (node, count, depth, _) =>
- count shouldBe (lastCount + 1)
- lastCount += 1
-
- node.outer match {
- case 1 => depth shouldBe 0
- case 2 => depth should (be(1) or be(2) or be(3))
- case 3 => depth should (be(1) or be(2))
- case 4 => depth should (be(2) or be(3))
- case 5 => depth should (be > 0 and be < 5)
- }
- }
- }
-
- def `traverser withMaxDepth`: Unit = {
- import Data.*
- object UnDi_1 extends TGraph(factory.from(elementsOfMixed_1)) {
- val expectedSumAll = 15
- val expectedSumLayer1 = 12
- val expectedSumLayer2 = 15
- val expectedSumAllExclGt4 = 10
- val expectedSumLayer2ExclGt4 = 9
- }
- import UnDi_1.*
- withGraph(g.asAnyGraph) { g =>
- def n(outer: Int) = g get outer
-
- val bfs_4 = n(4).outerNodeTraverser
- bfs_4.sum shouldBe expectedSumAll
- bfs_4.withMaxDepth(1).sum shouldBe expectedSumLayer1
- bfs_4.withMaxDepth(2).sum shouldBe expectedSumLayer2
-
- val dfs_4 = bfs_4.withKind(DepthFirst)
- dfs_4.withMaxDepth(1).sum shouldBe expectedSumLayer1
- dfs_4.withMaxDepth(2).sum shouldBe expectedSumLayer2
-
- val sub_4 = bfs_4.withSubgraph(nodes = _ <= 4)
- sub_4.sum shouldBe expectedSumAllExclGt4
- sub_4.withMaxDepth(2).sum shouldBe expectedSumLayer2ExclGt4
- sub_4.withKind(DepthFirst).sum shouldBe expectedSumAllExclGt4
- }
- }
-
- def `DownUp traverser`: Unit =
- withGraph(Di_1.g.asAnyGraph) { g =>
- def innerNode(outer: Int) = g get outer
- var stack = List.empty[Int]
-
- innerNode(4).innerNodeDownUpTraverser foreach { case (down, node) =>
- if (down) stack = node.outer +: stack
- else {
- stack.head shouldBe node.outer
- stack = stack.tail
- }
- }
- stack shouldBe empty
- }
-
- def `DownUp traverser for computing braces`: Unit = {
- val root = "A"
- withGraph(factory(root ~> "B1", root ~> "B2")) { g =>
- val innerRoot = g get root
- val result = innerRoot.innerNodeDownUpTraverser.foldLeft(ListBuffer.empty[String]) { (buf, param) =>
- param match {
- case (down, node) =>
- if (down) buf += (if (node eq innerRoot) "(" else "[") += node.toString
- else buf += (if (node eq innerRoot) ")" else "]")
- }
- }
- result.foldLeft("")(_ + _) should (
- be("(A[B1][B2])") or
- be("(A[B2][B1])")
- )
- }
- }
-
- def `DownUp traverser for computing sums`: Unit = {
- abstract class Elem(val name: String) {
- def balance: Int
- }
- case class Node(override val name: String) extends Elem(name) {
- var sum: Int = 0
- def balance = sum
- }
- case class Leaf(override val name: String, override val balance: Int) extends Elem(name)
-
- val root = Node("R")
- val (nA, nB, nBA) = (Node("A"), Node("B"), Node("BA"))
-
- withGraph(
- factory[Elem, DiEdge](
- root ~> nA,
- root ~> nB,
- nA ~> Leaf("LA1", 1),
- nA ~> Leaf("LA2", 2),
- nB ~> Leaf("B1", 3),
- nB ~> nBA,
- nBA ~> Leaf("BA1", 10),
- nBA ~> Leaf("BA2", 11),
- nBA ~> Leaf("BA3", 12)
- ).asAnyGraph
- ) { g =>
- (g get root).innerNodeDownUpTraverser foreach { case (down, node) =>
- if (!down)
- node.outer match {
- case n: Node => n.sum = node.diSuccessors.foldLeft(0)(_ + _.balance)
- case _ =>
- }
- }
- val expected = Map(root -> 39, nA -> 3, nB -> 36, nBA -> 33)
- g.nodes foreach {
- _.outer match {
- case n: Node => n.balance shouldBe (expected(n))
- case _ =>
- }
- }
- }
- }
-
- def `traverser withDirection`: Unit = {
- // https://groups.google.com/forum/?fromgroups=#!topic/scala-internals/9NMPfU4xdhU
- object DDi_1 extends TGraph(factory.from(elementsOfDi_1)) {
- val expectedSumSuccessorsOf_4 = 12
- val expectedSumPredecessorsOf_4 = 4
- val expectedSumSuccessorsOf_2 = 10
- val expectedSumPredecessorsOf_2 = 3
- val expectedSumAnyConnected = 15
-
- val expectedSumLayer1SuccessorsOf_2 = 5
- val expectedSumLayer1PredecessorsOf_2 = 3
- val expectedSumLayer1AnyConnectedWith_2 = 6
- }
- import DDi_1.*
- withGraph(DDi_1.g.asAnyGraph) { g =>
- def n(outer: Int) = g get outer
-
- val maxDepth_1 = Parameters(maxDepth = 1)
-
- n(4).outerNodeTraverser.sum shouldBe expectedSumSuccessorsOf_4
- n(4).outerNodeTraverser(predecessors).sum shouldBe expectedSumPredecessorsOf_4
-
- n(2).outerNodeTraverser.sum shouldBe expectedSumSuccessorsOf_2
- n(2).outerNodeTraverser(predecessors).sum shouldBe expectedSumPredecessorsOf_2
- n(2).outerNodeTraverser(anyConnected).sum shouldBe expectedSumAnyConnected
-
- n(2).outerNodeTraverser(maxDepth_1).sum shouldBe expectedSumLayer1SuccessorsOf_2
- n(2).outerNodeTraverser(maxDepth_1.withDirection(Predecessors)).sum shouldBe expectedSumLayer1PredecessorsOf_2
-
- n(2).outerNodeTraverser(maxDepth_1.withDirection(AnyConnected)).sum shouldBe
- expectedSumLayer1AnyConnectedWith_2
-
- an[IllegalArgumentException] should be thrownBy {
- n(2).innerNodeTraverser(anyConnected) pathTo n(2)
- }
- an[IllegalArgumentException] should be thrownBy {
- n(2).innerNodeTraverser(anyConnected) shortestPathTo n(2)
- }
- }
- }
-
- def `traverser withOrdering for nodes`: Unit =
- withGraph(
- factory(
- 0 ~> 4,
- 0 ~> 2,
- 0 ~> 3,
- 0 ~> 1,
- 1 ~> 13,
- 1 ~> 11,
- 1 ~> 12,
- 2 ~> 22,
- 2 ~> 21,
- 2 ~> 23,
- 3 ~> 32,
- 3 ~> 33,
- 3 ~> 31,
- 4 ~> 42,
- 4 ~> 41,
- 4 ~> 43
- )
- ) { g =>
- val root = g get 0
- val nodeOrdering = g.NodeOrdering(Ordering.Int.compare(_, _))
-
- val orderedTraverser = root.outerNodeTraverser.withOrdering(nodeOrdering)
- orderedTraverser.toList shouldBe (
- List(0 to 4: _*) ++
- List(11 to 13: _*) ++ List(21 to 23: _*) ++
- List(31 to 33: _*) ++ List(41 to 43: _*)
- )
-
- orderedTraverser.withKind(DepthFirst).toList shouldBe (
- 0 ::
- List(1) ::: List(11 to 13: _*) ::: List(2) ::: List(21 to 23: _*) :::
- List(3) ::: List(31 to 33: _*) ::: List(4) ::: List(41 to 43: _*)
- )
- }
-
- def `map Traverser result`: Unit =
- withGraph(Di_1.g.asAnyGraph) { g =>
- val t = g.nodes.head.outerNodeTraverser
- t map (_ + 1) shouldBe (t.toList map (_ + 1))
- }
-
- def `traverser for inner elements`: Unit =
- withGraph(Di_1.g.asAnyGraph) { g =>
- val t = g.nodes.head.innerElemTraverser
-
- def nodePred(n: g.NodeT) = n.degree > 1
- def edgePred(e: g.EdgeT) = e.ends forall nodePred
-
- val nodes = t collect { case g.InnerNode(n, _) if nodePred(n) => n }
- val edges = t collect { case g.InnerEdge(e, _) if edgePred(e) => e }
-
- nodes.toSet shouldBe (g.nodes filter nodePred)
- edges.toSet shouldBe (g.edges filter edgePred)
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/generator/GraphGenSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/generator/GraphGenSpec.scala
deleted file mode 100644
index df28a088..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/generator/GraphGenSpec.scala
+++ /dev/null
@@ -1,82 +0,0 @@
-package scalax.collection.generator
-
-import org.scalacheck.{Arbitrary, Gen}
-import org.scalacheck.Arbitrary.arbitrary
-import org.scalatest.matchers.should.Matchers
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.edges.*
-import scalax.collection.immutable.Graph
-
-class GraphGenSpec extends RefSpec with Matchers with ScalaCheckPropertyChecks {
-
- final val minSuccessful = 5
- implicit val config: PropertyCheckConfiguration =
- PropertyCheckConfiguration(minSuccessful = minSuccessful, maxDiscardedFactor = 1.0)
-
- object `nr of minimum successful tests` {
- def `should be met`: Unit = {
- var count = 0
- forAll { (i: Int) =>
- count += 1
- }
- count should be(minSuccessful)
- }
- }
-
- object `outer node set` {
- val order = 5
- implicit val arbitraryOuterNodes: Arbitrary[Set[Int]] =
- new GraphGen[Int, DiEdge[Int], Graph](
- Graph,
- order,
- Gen.choose(0, 10 * order),
- NodeDegreeRange(1, 4),
- Set(DiEdge)
- ).outerNodeSet
-
- def `should conform to the passed size`: Unit =
- forAll(arbitrary[Set[Int]]) { (outerNodes: Set[Int]) =>
- outerNodes should have size order
- }
- }
-
- type IntDiGraph = Graph[Int, DiEdge[Int]]
-
- def checkMetrics(g: IntDiGraph, metrics: GraphGen.Metrics[Int]): Unit = {
- import metrics._
-
- val degrees = g.degreeSeq
- val tolerableMaxExceed: Int = if (g.isHyper) 8 else 1
-
- g.order should be(order)
- g.isConnected should be(connected)
-
- degrees.min should be >= (nodeDegrees.min)
- degrees.max should be <= (nodeDegrees.max + tolerableMaxExceed)
-
- g.totalDegree should (
- be >= (expectedTotalDegree - maxDegreeDeviation) and
- be <= (expectedTotalDegree + maxDegreeDeviation)
- )
- }
-
- object `tiny connected graph of [Int,DiEdge]` {
- implicit val arbitraryGraph: Arbitrary[Graph[Int, DiEdge[Int]]] = GraphGen.tinyConnectedIntDi[Graph](Graph)
-
- def `should conform to tiny metrics`: Unit =
- forAll(arbitrary[IntDiGraph]) { (g: IntDiGraph) =>
- checkMetrics(g, GraphGen.TinyInt)
- }
- }
-
- object `small connected graph of [Int,DiEdge]` {
- implicit val arbitraryGraph: Arbitrary[Graph[Int, DiEdge[Int]]] = GraphGen.smallConnectedIntDi[Graph](Graph)
-
- def `should conform to small metrics`: Unit =
- forAll(arbitrary[IntDiGraph]) { (g: IntDiGraph) =>
- checkMetrics(g, GraphGen.SmallInt)
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/generator/RandomGraphSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/generator/RandomGraphSpec.scala
deleted file mode 100644
index c1889fb1..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/generator/RandomGraphSpec.scala
+++ /dev/null
@@ -1,122 +0,0 @@
-package scalax.collection.generator
-
-import scala.reflect.ClassTag
-
-import org.scalatest.Ignore
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-import scalax.collection.AnyGraph
-import scalax.collection.edges.*
-import scalax.collection.generic.{Edge, EdgeCompanionBase, GenericGraphFactory}
-import scalax.collection.GraphLike
-import scalax.collection.immutable.Graph
-import scalax.collection.mutable.{Graph => MGraph}
-
-class RandomGraphSpec extends RefSpec with Matchers {
-
- import RandomGraph._
- val normal = new IntFactory {
- val order = 1000
- val nodeDegrees = NodeDegreeRange(4, 15)
- }
-
- /** Creates a `RandomGraph` generator that produces a graph
- * with a constant order, constant `NodeDegreeRange` and a single edge type.
- */
- def generator[N, E <: Edge[N], G[X, Y <: Edge[X]] <: AnyGraph[X, Y] with GraphLike[X, Y, G]](
- edgeCompanion: EdgeCompanionBase,
- gCompanion: GenericGraphFactory[G],
- connected: Boolean
- )(implicit nodeTag: ClassTag[N], metrics: Metrics[N]) =
- new RandomGraph[N, E, G](
- gCompanion,
- metrics.order,
- metrics.nodeGen,
- metrics.nodeDegrees,
- Set(edgeCompanion),
- connected
- )
-
- def checkOrder(g: AnyGraph[Int, DiEdge[Int]])(implicit metrics: Metrics[Int]): Unit =
- g.order should be(metrics.order)
-
- def checkSize(g: AnyGraph[Int, DiEdge[Int]])(implicit metrics: Metrics[Int]): Unit = {
- import metrics._
- val totalDegree = g.totalDegree
- val deviation = totalDegree - expectedTotalDegree
- if (false)
- println(f""" total degree=$totalDegree,
- | isDense=$isDense,
- | maxDev=$maxDegreeDeviation,
- | deviation=$deviation,
- | (${100f * deviation / totalDegree}%2.2f percent)""".stripMargin.linesIterator.mkString)
- totalDegree should (be >= (expectedTotalDegree - maxDegreeDeviation) and
- be <= (expectedTotalDegree + maxDegreeDeviation))
- }
-
- object `disconnected random graph` {
- def `should have expected size`: Unit = {
- implicit val metrics: Metrics[Int] = normal
- val g = generator[Int, DiEdge[Int], Graph](DiEdge, Graph, false).draw
- checkOrder(g)
- checkSize(g)
- }
- }
-
- object `connected random graph` {
- def `should have expected size`: Unit = {
- implicit lazy val metrics: Metrics[Int] = normal
- val g = generator[Int, DiEdge[Int], MGraph](DiEdge, MGraph, true).draw
- checkOrder(g)
- checkSize(g)
- }
- }
-
- object `dense random graph` {
- @Ignore def `should have expected size`: Unit = {
- implicit val dense: Metrics[Int] = new IntFactory {
- val order = 100
- val nodeDegrees = NodeDegreeRange(55, 90)
- }
- dense.isDense shouldBe true
- val g = generator[Int, DiEdge[Int], Graph](DiEdge, Graph, true).draw
-
- checkOrder(g)
- checkSize(g)
- }
- }
-
- /* TODO L
- object `default weighted random graph edges` {
- def `should have distinct weights`: Unit = {
- implicit val metrics: Metrics[Int] = RandomGraph.TinyInt
- val g = generator[Int, WDiEdge[Int], Graph](WDiEdge, Graph, true).draw
- val weights = MSet.empty[Long] ++ (g.edges map (_.weight))
- weights.size should be(g.size)
- }
- }
-
- object `default labeled random graph edges` {
- def `should have distinct labels`: Unit = {
- implicit val metrics: Metrics[Int] = RandomGraph.SmallInt
- val g = generator[Int, LDiEdge, Graph](LDiEdge, Graph, true).draw
- val labels = MSet.empty[Any] ++ (g.edges map (_.label))
- labels.size should be(g.size)
- }
- }
- */
-
- object `huge graph` {
- @Ignore def `should have expected size`: Unit = {
- implicit val huge: Metrics[Int] = new IntFactory {
- val order = 100000
- val nodeDegrees = normal.nodeDegrees
- }
- val g = generator[Int, DiEdge[Int], MGraph](DiEdge, MGraph, true).draw
- // TODO should be fast enough
- checkOrder(g)
- checkSize(g)
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/labeled/TraversalSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/labeled/TraversalSpec.scala
deleted file mode 100644
index ae5953b3..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/labeled/TraversalSpec.scala
+++ /dev/null
@@ -1,299 +0,0 @@
-package scalax.collection.labeled
-
-import scala.concurrent.duration.*
-
-//import scala.util.Random
-//import org.scalacheck.Arbitrary.arbitrary
-//import org.scalacheck.*
-import org.scalatest.*
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
-
-import scalax.collection.Data.*
-import scalax.collection.OuterImplicits.*
-//import generator.GraphGen
-import scalax.collection.generic.{AnyEdge, Edge, GenericGraphCoreFactory}
-import scalax.collection.edges.*
-import scalax.collection.edges.labeled.*
-import scalax.collection.edges.multilabeled.*
-import scalax.collection.GraphTraversal.*
-import scalax.collection.visualization.Visualizer
-import scalax.collection.{immutable, mutable, AnyGraph, GraphLike, IntelliJ, MSet, TGraph}
-
-import scala.collection.mutable.ListBuffer
-
-class TraversalSpec
- extends Suites(
- new Traversal[immutable.Graph](immutable.Graph),
- new Traversal[mutable.Graph](mutable.Graph)
- )
-
-final private class Traversal[G[N, E <: Edge[N]] <: AnyGraph[N, E] with GraphLike[N, E, G]](
- val factory: GenericGraphCoreFactory[G]
-) extends RefSpec
- with Matchers
- with ScalaCheckPropertyChecks
- with IntelliJ[G]
- with Visualizer {
-
- implicit val config: PropertyCheckConfiguration =
- PropertyCheckConfiguration(minSuccessful = 5, maxDiscardedFactor = 1.0)
-
- val predecessors = Parameters(direction = Predecessors)
- val anyConnected = Parameters(direction = AnyConnected)
-
- def `assert bug 9 of shortestPathTo is fixed`: Unit =
- withGraph(factory(0 ~> 1 % 3, 0 ~> 2 % 4, 1 ~> 3 % 3, 2 ~> 3 % 1)) { g =>
- def n(outer: Int) = g get outer
- (n(0) shortestPathTo n(3)).get.nodes.toList should be(List(0, 2, 3))
- }
-
- def `shortestPathTo in WDi_1`: Unit =
- withGraph(factory(elementsOfWDi_1: _*)) { g =>
- def n(outer: Int) = g get outer
-
- n(5) shortestPathTo n(4) shouldBe None
- n(5) shortestPathTo n(1) shouldBe None
- n(3) shortestPathTo n(1) shouldBe None
-
- (n(1) shortestPathTo n(3)).get.nodes.toList shouldBe List(1, 3)
- (n(4) shortestPathTo n(5)).get.nodes.toList shouldBe List(4, 3, 5)
- (n(1) shortestPathTo n(5)).get.nodes.toList shouldBe List(1, 5)
- }
-
- def `shortestPathTo in WDi_1 using Float`: Unit =
- withGraph(factory(elementsOfWDi_1: _*)) { g =>
- def n(outer: Int) = g get outer
-
- def weight(e: g.EdgeT): Float = 0.5f + e.weight.toFloat
- def reverseWeight(e: g.EdgeT): Double = 41 - e.weight
-
- n(5) shortestPathTo (n(4), weight) shouldBe empty
-
- (n(1) shortestPathTo (n(3), weight)).get.nodes.to(LazyList) should contain theSameElementsInOrderAs Array(1, 3)
- (n(1) shortestPathTo (n(3), reverseWeight)).get.nodes.to(LazyList) should contain theSameElementsInOrderAs Array(
- 1,
- 2,
- 3
- )
- }
-
- def `shortestPathTo in WUnDi_1`: Unit =
- withGraph(factory(elementsOfWMixed_1: _*)) { g =>
- def shortestPathNodes(from: Int, to: Int): LazyList[g.NodeT] = {
- def n(value: Int): g.NodeT = g get value
-
- val path = n(from) shortestPathTo n(to)
- path shouldBe defined
- path.get.nodes.to(LazyList)
- }
- shortestPathNodes(2, 5) should contain theSameElementsInOrderAs Array(2, 3, 4, 5)
- shortestPathNodes(4, 5) should contain theSameElementsInOrderAs Array(4, 5)
- shortestPathNodes(1, 3) should (contain theSameElementsInOrderAs (Array(1, 3)) or
- contain theSameElementsInOrderAs (Array(1, 5, 3)))
- shortestPathNodes(5, 4) should contain theSameElementsInOrderAs Array(5, 3, 4)
- shortestPathNodes(3, 1) should contain theSameElementsInOrderAs Array(3, 4, 5, 1)
- }
-
- def `shortestPathTo withMaxDepth`: Unit =
- withGraph(factory(elementsOfWMixed_1: _*)) { g =>
- def n(value: Int): g.NodeT = g get value
-
- n(2).innerNodeTraverser.withMaxDepth(2).shortestPathTo(n(5)).get.nodes.toList should be(List(2, 3, 5))
- }
-
- def `shortestPathTo withMaxWeight`: Unit =
- withGraph(factory(elementsOfWMixed_1: _*)) { g =>
- def n(value: Int): g.NodeT = g get value
-
- val t = n(2).innerNodeTraverser
- t.withMaxWeight(3).shortestPathTo(n(5)) shouldBe defined
- t.withMaxWeight(2).shortestPathTo(n(5)) shouldBe empty
- }
-
- // see diagram WUnDi-2.jpg
- val eUnDi_2 = List[AnyEdge[Int]](1 ~ 2 %% 4, 2 ~ 3 %% -1, 1 ~> 3 %% 5, 1 ~ 3 %% 4, 1 ~> 2 %% 3, 2 ~ 2 %% 1)
- val gUnDi_2 =
- factory.from[Int, AnyEdge[Int]](Set.empty, eUnDi_2).asAnyGraph
-
- def `shortestPathTo in UnDi_2`: Unit =
- withGraph(gUnDi_2) { g =>
- def n(value: Int) = g get value
-
- val p1_3 = n(1).shortestPathTo(n(3)).get
- p1_3.nodes.toList should be(List(1, 2, 3))
- p1_3.edges.toList should be(List(eUnDi_2(4), eUnDi_2(1)))
-
- val p2_1 = (n(2) shortestPathTo n(1)).get
- p2_1.nodes.toList should be(List(2, 3, 1))
- p2_1.edges.toList should be(List(eUnDi_2(1), eUnDi_2(3)))
-
- val p3_1 = (n(3) shortestPathTo n(1)).get
- p3_1.nodes.toList should be(List(3, 2, 1))
- p3_1.edges.toList should be(List(eUnDi_2(1), eUnDi_2(0)))
-
- val p3_3 = (n(3) shortestPathTo n(3)).get
- p3_3.nodes.toList should be(List(3))
- p3_3.edges.toList shouldBe empty
- }
-
- def `traverser withSubgraph`: Unit =
- withGraph(gUnDi_2) { g =>
- def n(value: Int) = g get value
-
- val p2_1_nNE3 = n(2).withSubgraph(nodes = _.outer != 3).pathTo(n(1)).get
- p2_1_nNE3.nodes.toList should be(List(2, 1))
- p2_1_nNE3.edges.toList should be(List(2 ~ 1 %% 4))
-
- val p1_3_wGT4 = n(1).withSubgraph(edges = _.weight > 4).pathTo(n(3)).get
- p1_3_wGT4.nodes.toList should be(List(1, 3))
- p1_3_wGT4.edges.toList should be(List(eUnDi_2(2)))
-
- val p1_3_wLT4 = n(1).withSubgraph(edges = _.weight < 4).pathTo(n(3)).get
- p1_3_wLT4.nodes.toList should be(List(1, 2, 3))
- p1_3_wLT4.edges.toList should be(List(eUnDi_2(4), eUnDi_2(1)))
- }
-
- object `traverser withMaxWeight` {
- object WMixed_1 extends TGraph[Int, AnyEdge[Int], G](factory.from(elementsOfWMixed_1))
- import WMixed_1._
-
- private def check(kind: Kind): Unit =
- List[Long](Long.MaxValue, 5, 4, 3, 2, 1, 0).map(max => n(1).withKind(kind).withMaxWeight(max).size) shouldBe
- List(5, 4, 3, 2, 1, 1, 1)
-
- def `calling DepthFirst`: Unit = withGraph(WMixed_1.g) { _ =>
- check(DepthFirst)
- }
- def `calling BreadthFirst`: Unit = withGraph(WMixed_1.g) { _ =>
- check(BreadthFirst)
- }
- }
-
- def `traverser to graph`: Unit = {
- object Di_1 extends TGraph(factory(elementsOfDi_1: _*))
- withGraph(Di_1.g) { g =>
- def innerNode(outer: Int) = g get outer
-
- innerNode(1).outerNodeTraverser.to(factory) should equal(factory(1 ~> 2, 2 ~> 3, 3 ~> 5, 1 ~> 5, 1 ~> 3))
-
- innerNode(2).outerNodeTraverser(anyConnected).to(factory) should equal(
- factory(1 ~> 2, 2 ~> 3, 4 ~> 3, 3 ~> 5, 1 ~> 5, 1 ~> 3)
- )
-
- innerNode(3).outerNodeTraverser(predecessors).to(factory) should equal(factory(4 ~> 3, 1 ~> 3, 2 ~> 3, 1 ~> 2))
- }
- }
-
- def `traverser with a visitor`: Unit =
- withGraph(gUnDi_2) { g =>
- def n(value: Int) = g get value
-
- val nodes = ListBuffer[g.NodeT]()
- val edges = ListBuffer[g.EdgeT]()
- val traverser = n(2).innerElemTraverser.withSubgraph(nodes = _.outer != 3)
- traverser.pathTo(n(1)) {
- case n: g.InnerNode => nodes += n.asNodeT
- case e: g.InnerEdge => edges += e.asEdgeT
- }
-
- nodes shouldBe List(n(2), n(1))
- edges.toList.sorted(g.BaseInnerEdge.WeightOrdering) shouldBe List(eUnDi_2(1), eUnDi_2(5), eUnDi_2(0))
- }
-
- def `shortestPathTo in the flight example graph`: Unit = {
- import scalax.collection.labeled.aviation._
-
- val (jfc, lhr, dme, svx, fra, prg) =
- (Airport("JFC"), Airport("LHR"), Airport("DME"), Airport("SVX"), Airport("FRA"), Airport("PRG"))
-
- val flights: List[Flight] =
- List(
- jfc ~> dme :++ ("UN 2222", Nil, 8.hours + 50.minutes),
- dme ~> svx :++ ("UN 109", Nil, 2.hours + 15.minutes),
- jfc ~> lhr :++ ("BA 174", Nil, 6.hours + 50.minutes),
- jfc ~> fra :++ ("LH 400", Nil, 8.hours + 20.minutes),
- jfc ~> fra :++ ("UA 8840", Nil, 7.hours + 35.minutes),
- lhr ~> dme :++ ("BA 872", Nil, 4.hours),
- lhr ~> dme :++ ("SU 242", Nil, 3.hours + 50.minutes),
- lhr ~> fra :++ ("LH 903", Nil, 1.hours + 35.minutes),
- lhr ~> prg :++ ("BA 860", Nil, 2.hours),
- fra ~> lhr :++ ("LH 920", Nil, 1.hours + 35.minutes),
- fra ~> dme :++ ("LH 1444", Nil, 3.hours + 10.minutes),
- fra ~> svx :++ ("LH 1480", Nil, 4.hours + 35.minutes),
- prg ~> svx :++ ("U6 902", Nil, 4.hours + 25.minutes)
- )
-
- def flight(flightNo: String) = flights.find(_.flightNo == flightNo).get
-
- val g = factory.from[Airport, Flight](Set.empty, flights)
-
- withGraph(g.asAnyGraph) { g =>
- val shp1 = (g get jfc).withSubgraph(edges = _.airline != "UN") shortestPathTo (g get dme)
- shp1.get.nodes.toList should be(List(jfc, lhr, dme))
- shp1.get.edges.toList should be(List(flight("BA 174"), flight("SU 242")))
-
- val shp2 = (g get lhr).withSubgraph(edges = _.airline != "SU") shortestPathTo (g get svx)
- shp2.get.edges.toList should be(List(flight("LH 903"), flight("LH 1480")))
-
- val shp3 = (g get dme).withSubgraph(nodes = _ != fra) shortestPathTo (g get jfc)
- shp3 should be(None)
-
- val shp4 = (g get jfc).withSubgraph(nodes = _ != dme) shortestPathTo (g get svx)
- shp4.get.nodes.toList should be(List(jfc, fra, svx))
- shp4.get.edges.toList should be(List(flight("UA 8840"), flight("LH 1480")))
-
- val visited = MSet[g.EdgeT]()
- (g get jfc).innerEdgeTraverser.shortestPathTo(g get lhr) { (e: g.EdgeT) =>
- visited += e
- }
- val visitedSorted = visited.toList.sortWith((a: g.EdgeT, b: g.EdgeT) => a.flightNo < b.flightNo)
- visitedSorted.sameElements(
- List(flight("BA 174"), flight("LH 400"), flight("UA 8840"), flight("UN 2222"))
- ) should be(true)
- }
- }
-
- def `traverser withOrdering for edges`: Unit = {
- val outerEdges = List(
- 1 ~> 4 % 2,
- 1 ~> 2 % 5,
- 1 ~> 3 % 4,
- 3 ~> 6 % 4,
- 3 ~> 5 % 5,
- 3 ~> 7 % 2
- )
- withGraph(factory(outerEdges: _*)) { g =>
- val root = g get 1
-
- def edgeOrdering = g EdgeOrdering (g.BaseInnerEdge.WeightOrdering.reverse.compare _)
-
- val orderedTraverser = root.outerNodeTraverser.withOrdering(edgeOrdering)
- orderedTraverser.toList should be(List(1 to 7: _*))
- orderedTraverser.withKind(DepthFirst).toList should be(List(1, 2, 3, 5, 6, 7, 4))
- }
- }
-
- /* TODO GraphGen
- def `shortest path exists if path exists`: Unit = {
- implicit val arbitraryWDiGraph = Arbitrary {
- import GraphGen.SmallInt._
- new GraphGen[Int, WDiEdge[Int], G](factory, order, nodeGen, nodeDegrees, Set(WDiEdge), connected).apply
- }
- val r = new Random
-
- forAll(arbitrary[G[Int, WDiEdge]]) {
- given(_) { g =>
- def drawNode = g.nodes.draw(r)
-
- val (n1, n2) = (drawNode, drawNode)
- val path = n1 pathTo n2
- val shortestPath = n1 shortestPathTo n2
-
- path.isDefined should equal(shortestPath.isDefined)
- }
- }
- }
- */
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/Airport.scala b/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/Airport.scala
deleted file mode 100644
index 6f5b765f..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/Airport.scala
+++ /dev/null
@@ -1,5 +0,0 @@
-package scalax.collection.labeled.aviation
-
-case class Airport(code: String) {
- override def toString: String = code // leave out Airport-prefix
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/Flight.scala b/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/Flight.scala
deleted file mode 100644
index 9797daa5..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/Flight.scala
+++ /dev/null
@@ -1,47 +0,0 @@
-package scalax.collection.labeled.aviation
-
-import scalax.collection.OneOrMore
-import scalax.collection.generic.{AbstractDiEdge, LDiEdgeToString, MultiEdge, MultiLEdgeToString, PartialEdgeMapper}
-
-import java.time.{DayOfWeek, LocalTime}
-import scala.concurrent.duration.FiniteDuration
-
-/** A labeled edge to represent flights between airports.
- *
- * Defines a custom edge type that can be used for a flight route map.
- *
- * A `Flight` has several attributes like `departure` and `duration`.
- * To enable multiple flights between airports, the key is extended by `flightNo`.
- *
- * @see EditingTypedSpec.scala.
- *
- * @param departure The departure airport
- * @param destination The destination airport
- * @param flightNo The flight Id as a key attribute consisting of the airline short and a flight number of that airline.
- * @param departures daytime of departure
- * @param duration of flight
- */
-case class Flight(
- departure: Airport,
- destination: Airport,
- flightNo: String,
- departures: List[(DayOfWeek, LocalTime)],
- duration: FiniteDuration
-) extends AbstractDiEdge[Airport](departure, destination)
- with MultiEdge
- with LDiEdgeToString
- with MultiLEdgeToString
- with PartialEdgeMapper[Flight] {
-
- override def weight: Double = duration.toMinutes.toDouble
-
- def airline: String = flightNo.takeWhile(_.isLetter)
-
- override def extendKeyBy: OneOrMore[String] = OneOrMore(flightNo)
-
- override protected def labelToString: String = s"($flightNo, $departures, $duration)"
-
- override def map[N]: PartialFunction[(N, N), Flight] = { case (from: Airport, to: Airport) =>
- copy(from, to)
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/package.scala b/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/package.scala
deleted file mode 100644
index 4505306c..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/labeled/aviation/package.scala
+++ /dev/null
@@ -1,46 +0,0 @@
-package scalax.collection.labeled
-
-import scalax.collection.AnyGraph
-import scalax.collection.edges.DiEdge
-import scalax.collection.generic.{UnapplyLabel, UnapplyLabeledEdge}
-
-import java.time.{DayOfWeek, LocalTime}
-import scala.concurrent.duration._
-
-/** Convenience infix constructors and extractors for the `Flight` edge.
- */
-package object aviation {
-
- type AnyFlightGraph = AnyGraph[Airport, Flight]
-
- object immutable {
- import scalax.collection.immutable.{Graph, TypedGraphFactory}
-
- type FlightGraph = Graph[Airport, Flight]
- object FlightGraph extends TypedGraphFactory[Airport, Flight]
- }
-
- object mutable {
- import scalax.collection.mutable.{Graph, TypedGraphFactory}
-
- type FlightGraph = Graph[Airport, Flight]
- object FlightGraph extends TypedGraphFactory[Airport, Flight]
- }
-
- /** Optionally facilitate infix constructors like `airportA ~> airportB :++ (flightNo, departures, duration)`
- */
- implicit class InfixFlightConstructor(val e: DiEdge[Airport]) extends AnyVal {
-
- def :++(flightNo: String, departures: List[(DayOfWeek, LocalTime)], duration: FiniteDuration) =
- Flight(e.source, e.target, flightNo, departures, duration)
- }
-
- type Labels = (String, List[(DayOfWeek, LocalTime)], FiniteDuration)
-
- /** Optionally allow for pattern matching like `airportA :~> airportB ++: (flightNo, departures, duration)`
- */
- object :~> extends UnapplyLabeledEdge[Airport, Flight, Labels] {
- protected def label(edge: Flight): Labels = (edge.flightNo, edge.departures, edge.duration)
- }
- object ++: extends UnapplyLabel[Airport, Labels]
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/mutable/ArraySetSpec.scala b/coreTestScala3/src/test/scala/scalax/collection/mutable/ArraySetSpec.scala
deleted file mode 100644
index 437ffbf9..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/mutable/ArraySetSpec.scala
+++ /dev/null
@@ -1,160 +0,0 @@
-package scalax.collection.mutable
-
-import scala.collection.mutable.{Set => MutableSet}
-import scala.util.chaining._
-
-import scalax.collection.immutable.SortedArraySet
-
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-class ArraySetSpec extends RefSpec with Matchers {
-
- implicit val hints: ArraySet.Hints = ArraySet.Hints(
- initialCapacity = 4,
- capacityIncrement = 4,
- hashTableThreshold = 12,
- compactUpToUsed = 100
- )
-
- private class IntSequence {
- private var i = 1
- def draw(): Int = i tap (_ => i += 1)
- }
-
- object `ArraySet ` {
- def `can grow`: Unit = {
- val arr = ArraySet.emptyWithHints[Int]
- arr.capacity shouldBe hints.initialCapacity
-
- val integers = new IntSequence
- def add(numberOfAdditions: Int, expectedCapacity: Int): Unit =
- for (i <- 0 until numberOfAdditions) {
- arr += integers.draw()
- arr.capacity shouldBe expectedCapacity
- }
-
- var toAdd, nextCapacity = hints.initialCapacity
- while (nextCapacity <= hints.hashTableThreshold) {
- add(toAdd, nextCapacity)
- nextCapacity += hints.capacityIncrement
- toAdd = hints.capacityIncrement
- }
- add(1, 0)
- arr.isArray shouldBe false
- }
-
- def `may be compacted`: Unit = {
- val integers = new IntSequence
- val toAdd = hints.initialCapacity + 1
- val arr = ArraySet.emptyWithHints[Int] ++=
- (for (i <- 1 to toAdd) yield integers.draw())
- arr.compact()
- arr.capacity shouldBe toAdd
- }
-
- def `may be configured to be represented solely by a HashSet`: Unit = {
- val edges = new IntSequence
- val arr = ArraySet.emptyWithHints[Int](ArraySet.Hints.HashOnly)
- def check(): Unit = {
- arr.isArray shouldBe false
- arr.capacity shouldBe 0
- }
- check()
-
- arr += edges.draw()
- check()
-
- arr.compact()
- check()
- }
-
- def `supports hints`: Unit = {
- val edges = new IntSequence
- val arr = ArraySet.emptyWithHints[Int](ArraySet.Hints(0, 4, 8, 0))
- arr += edges.draw()
- arr.capacity shouldBe 4
- }
-
- def `supports hints properly when filtered`: Unit = {
- val integers = new IntSequence
- type E = Int
- val arr = ArraySet.emptyWithHints[E]
- val size = hints.initialCapacity + 1
- for (i <- 1 to size) arr += integers.draw()
-
- val taken = arr take size
- taken.isInstanceOf[ArraySet[_]] shouldBe true
- taken should have size size
-
- def setInterface[A](set: MutableSet[A], n: Int): MutableSet[A] = set take n
- setInterface(arr, size - 1).isInstanceOf[ArraySet[_]] shouldBe true
-
- val filtered0 = arr filter (_ => false)
- filtered0.isInstanceOf[ArraySet[_]] shouldBe true
- taken should have size size
- filtered0.hints.initialCapacity should equal(arr.size)
-
- for (i <- 1 to hints.capacityIncrement) arr += integers.draw()
- val filteredEven = arr filter (_ % 2 == 0)
- filteredEven.hints.initialCapacity should equal(arr.size)
- }
-
- def `is sortable`: Unit = {
- val sorted = ArraySet(3, 6, 0, -3).sorted
-
- sorted.isInstanceOf[SortedArraySet[_]] shouldBe true
- sorted.filter(_ < 0).isInstanceOf[SortedArraySet[_]] shouldBe true
- sorted.toList shouldBe List(-3, 0, 3, 6)
- sorted.rangeFrom(1) shouldBe SortedArraySet(3, 6)
- sorted.rangeUntil(0) shouldBe SortedArraySet(-3)
- sorted.range(-10, 10) shouldBe sorted
- sorted.range(-10, 1) shouldBe SortedArraySet(-3, 0)
- sorted.range(-10, -3) shouldBe SortedArraySet.empty[Int]
- sorted.range(-10, -4) shouldBe SortedArraySet.empty[Int]
- }
-
- def `supports ++` : Unit = {
- val a = ArraySet.empty[Int]
- val b = ArraySet(1)
- val c = ArraySet(2)
-
- a.clone shouldBe empty
- a ++ b shouldBe b
- b ++ c shouldBe (b.toSet ++ c.toSet)
- }
-
- object `supports upsert` {
- case class Mutable(key: Int)(var i: Int = 0)
-
- def upsert(setSize: Int): Unit = {
- val integers = new IntSequence
- val pos = 1
- pos shouldBe <(setSize)
-
- val arr = ArraySet.emptyWithHints[Mutable] ++=
- (for (i <- 1 to setSize) yield Mutable(integers.draw())())
- arr should have size setSize
-
- def mutable = arr.drop(pos).head
- val newI = mutable.i + 1
- val toUpsert = Mutable(mutable.key)(newI)
- toUpsert should equal(mutable)
-
- val inserted = arr.upsert(toUpsert)
- inserted shouldBe false
- mutable.i shouldBe newI
-
- arr.size shouldBe setSize
- arr.upsert(Mutable(integers.draw())()) should ===(true)
- arr.size shouldBe (setSize + 1)
- }
-
- def `when represented by an Array`: Unit =
- upsert(hints.hashTableThreshold - 3)
-
- def `when represented by a HashSet`: Unit =
- upsert(hints.hashTableThreshold + 3)
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/collection/visualization/Visualizer.scala b/coreTestScala3/src/test/scala/scalax/collection/visualization/Visualizer.scala
deleted file mode 100644
index 806d76dd..00000000
--- a/coreTestScala3/src/test/scala/scalax/collection/visualization/Visualizer.scala
+++ /dev/null
@@ -1,54 +0,0 @@
-package scalax.collection.visualization
-
-import org.scalatest.exceptions.TestFailedException
-
-import scalax.collection.AnyGraph
-import scalax.collection.ToString.*
-import scalax.collection.generic.Edge
-
-/** Scalatest support for graph visualization in case of failures.
- *
- * Drawing is commented out because
- * - org.gephi with all it's dependencies is rather heavy
- * - managing Gephi releases proved cumbersome over time
- * - there was no frequent usage
- * - permission to write files needs be additionally configured in the CI.
- *
- * However it's intended to add a more lightweight drawing implementation in future.
- */
-trait Visualizer /*extends Drawable*/ {
-
- final def withGraph[N, E <: Edge[N]](graph: AnyGraph[N, E])(test: AnyGraph[N, E] => Unit): Unit = {
-
- def reThrow(ex: TestFailedException, messageExtension: String) =
- throw ex.modifyMessage(_.map { testMessage =>
- s"""$testMessage
- |------------ given ------------
- |$messageExtension
- |-------------------------------""".stripMargin
- })
-
- try test(graph)
- catch {
- case ex: TestFailedException =>
- /*
- makeImage(
- graph,
- path = "log/",
- name = (ex.failedCodeFileName match {
- case Some(fileName) => fileName
- case None => "failed_test"
- }) + (ex.failedCodeLineNumber match {
- case Some(number) => "_line" + number.toString
- case None => ""
- }) + ".png"
- ) match {
- case Success(f) => reThrow(ex, s"The graph image is available at file://${f.getAbsolutePath}")
- case Failure(e) => reThrow(ex, s"Graph image generation failed with `${e.getMessage}`.")
- }
- */
- val small = graph.edges.size < 10 && graph.edges.toString.length < 100
- reThrow(ex, graph.render(if (small) SetsOnSeparateLines() else SetElemsOnSeparateLines()))
- }
- }
-}
diff --git a/coreTestScala3/src/test/scala/scalax/time/MicroBenchmark.scala b/coreTestScala3/src/test/scala/scalax/time/MicroBenchmark.scala
deleted file mode 100644
index 23319304..00000000
--- a/coreTestScala3/src/test/scala/scalax/time/MicroBenchmark.scala
+++ /dev/null
@@ -1,135 +0,0 @@
-package scalax.time
-
-import scala.collection.mutable.ArrayBuffer
-import scala.language.implicitConversions
-
-/** Provides lightweight syntax for simple time measurement and the comparison of results.
- * Not aimed at sophisticated JVM benchmarking.
- *
- * Use `time`, `measure` or `measureAll` to get absolute times.
- * Use `relativeTime` or `relativeTimes` to get relative times.
- * Except `time`, all methods return `Result` that is comprised of the computation result(s) and elapsed times.
- * `warmUp` is the number of repeated computations prior to any measurement.
- * `repetitions` is the number of the repeated computation that will be measured.
- */
-object MicroBenchmark {
- import scala.math.BigInt.*
- import scala.math.Numeric
-
- implicit final class NanoSecond(val value: Long) extends AnyVal {
- def relativeTo(decimals: Int = 2)(that: NanoSecond): Float =
- round(this.value.toFloat / that.value.toFloat, decimals)
- }
-
- // allows to call functions requiring implicit Numeric such as sum
- implicit object NanoSecondNumeric extends Numeric[NanoSecond] {
- implicit def nanoSecondToLong(ns: NanoSecond): Long = ns.value
- val num = Numeric.LongIsIntegral
- def plus(x: NanoSecond, y: NanoSecond) = num.plus(x, y)
- def minus(x: NanoSecond, y: NanoSecond) = num.minus(x, y)
- def times(x: NanoSecond, y: NanoSecond) = num.times(x, y)
- def negate(x: NanoSecond) = num.negate(x)
- def fromInt(x: Int) = x.toLong
- def toInt(x: NanoSecond) = x.value.toInt
- def toLong(x: NanoSecond) = x.value.toLong
- def toFloat(x: NanoSecond) = x.value.toFloat
- def toDouble(x: NanoSecond) = x.value.toDouble
- def compare(x: NanoSecond, y: NanoSecond) = num.compare(x, y)
- def parseString(str: String) = throw new UnsupportedOperationException
- }
-
- sealed abstract class MeasurementResult[A](result: A) {
- def mediumNanoSecs: Long
- def relativeTo(decimals: Int = 2)(that: MeasurementResult[A]) =
- this.mediumNanoSecs.relativeTo(decimals)(that.mediumNanoSecs)
- protected def toStringPrefix: String
- protected def optToStringParams = ""
- override def toString = s"$toStringPrefix($mediumNanoSecs ns, $result$optToStringParams)"
- }
-
- case class SingleResult[A](nanoSecs: Long, result: A) extends MeasurementResult(result) {
- def mediumNanoSecs = nanoSecs
- protected def toStringPrefix = "Result"
- }
-
- case class Result[A](result: A, times: ArrayBuffer[Long] = ArrayBuffer.empty) extends MeasurementResult(result) {
- def this(result: A, firstNanoSecs: Long) = this(result, ArrayBuffer(firstNanoSecs))
- def mediumNanoSecs: Long = times.sum / times.size
- def +=(nanoSecs: Long): this.type = { this.times += nanoSecs; this }
- def nanoSecs = times.iterator
- protected def toStringPrefix = "Results"
- override protected def optToStringParams = s""", {${nanoSecs mkString " "}}"""
- }
-
- case class Results[A](list: List[Result[A]]) {
- def relativeTimes(decimals: Int = 2): List[Float] = {
- val mA = list.head
- 1f :: (list.tail map (r => r.relativeTo(decimals)(mA)))
- }
- }
-
- private def requireEq[A](r1: A, r2: A): Unit = require(
- r1 == r2,
- s"'$r1' != '$r2' but blocks are expected to return the same result. Otherwise set requireEqualResults to false."
- )
-
- def once[A](block: => A): SingleResult[A] = {
- val start = System.nanoTime
- val res = block
- val end = System.nanoTime
- SingleResult(end - start, res)
- }
-
- private def once[A](byName: ByName[A]): SingleResult[A] = once(byName())
-
- def measure[A](warmUp: Int = 1, repetitions: Int = 1)(block: => A): Result[A] =
- measureAll[A](warmUp, repetitions)(block).list.head
-
- def time[A](warmUp: Int = 1, repetitions: Int = 1)(block: => A): Long =
- measure(warmUp, repetitions)(block).mediumNanoSecs
-
- private def round(float: Float, decimals: Int) = {
- val fact = (10 pow decimals).toInt
- (float * fact).floor / fact
- }
-
- // relation of elapsed times b : a
- def relativeTime[A](warmUp: Int = 1, repetitions: Int = 1, decimals: Int = 2, requireEqualResults: Boolean = true)(
- a: => A,
- b: => A
- ): Float =
- measureAll[A](warmUp, repetitions, requireEqualResults)(a, b).list match {
- case mA :: mB :: Nil => mB.relativeTo(decimals)(mA)
- case x => throw new MatchError(x)
- }
-
- final class ByName[+A](x: => A) { def apply(): A = x }
- implicit def toHolder[A](block: => A): ByName[A] = new ByName(block)
-
- def measureAll[A](warmUp: Int = 1, repetitions: Int = 1, requireEqualResults: Boolean = true)(
- blocks: ByName[A]*
- ): Results[A] = {
- require(repetitions > 0, "'repetitions' must be positive")
- for (i <- 1 to warmUp) blocks foreach once
-
- val results: Array[Result[A]] = (blocks map once map (r => new Result(r.result, r.nanoSecs))).toArray
- val zippedBlocks = blocks.zipWithIndex
- for {
- i <- 1 until repetitions
- zB <- zippedBlocks
- } {
- val (b, j) = zB
- once(b) match {
- case SingleResult(t, r) =>
- results(j) += t
- if (requireEqualResults) requireEq(r, results(j).result)
- }
- }
- Results(results.toList)
- }
-
- def relativeTimes[A](warmUp: Int = 1, repetitions: Int = 1, decimals: Int = 2, requireEqualResults: Boolean = true)(
- blocks: ByName[A]*
- ): Seq[Float] =
- measureAll[A](warmUp, repetitions, requireEqualResults)(blocks: _*).relativeTimes(decimals)
-}
diff --git a/coreTestScala3/src/test/scala/scalax/time/MicroBenchmarkTest.scala b/coreTestScala3/src/test/scala/scalax/time/MicroBenchmarkTest.scala
deleted file mode 100644
index 6517c303..00000000
--- a/coreTestScala3/src/test/scala/scalax/time/MicroBenchmarkTest.scala
+++ /dev/null
@@ -1,73 +0,0 @@
-package scalax.time
-
-import scala.collection.immutable.ArraySeq
-import scala.collection.mutable
-
-import org.scalactic.Equality
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.refspec.RefSpec
-
-/* Intentionally excluded from SBT tests by means of a class name suffix different from "Spec".
- */
-class MicroBenchmarkTest extends RefSpec with Matchers {
-
- import MicroBenchmark.*
-
- object `relativeTimes() reflects` {
- def `relative execution times`: Unit = {
- val r = 1 to 20
- val relTimes = relativeTimes(warmUp = 2)(
- r.toList.sorted,
- r.toList.sorted.toArray.toList.sorted,
- r.toList.sorted.toSet.toArray.toList.sorted
- )
- relTimes sliding 2 foreach {
- case a :: b :: _ => a should be < b
- case x => throw new MatchError(x)
- }
- }
- }
-
- class FloatTolerance(maxDeviation: Float) extends Equality[Float] {
- private def eq(a: Float, b: Float): Boolean = if (a > b) a < b * maxDeviation else a > b / maxDeviation
- def areEqual(a: Float, b: Any) = b match {
- case f: Float => eq(a, f)
- case i: Int => eq(a, i.toFloat)
- }
- }
-
- object `relativeTime() roughly reflects` {
- def `O(N) complexity of List.size`: Unit = {
- def fill(size: Int): (Int, List[Int]) = (size, List.fill(size)(0))
- val (small, big) = (fill(100), fill(1000))
-
- implicit val tolerance = new FloatTolerance(4f)
- val expected = big._1.toFloat / small._1.toFloat
- val results = measureAll(warmUp = 5, repetitions = 10)(small._2.size == small._1, big._2.size == big._1)
- val actual = results.relativeTimes()(1)
-
- actual should ===(expected)
- }
- }
-
- def `traversing immutable.Set takes marginally longer than mutable.Set`: Unit = {
- val size = 10000
- val seq = ArraySeq.tabulate(size)(identity)
- val sum = seq.sum
- val imm = Set(seq: _*)
- val m = mutable.Set(seq: _*)
-
- relativeTime(repetitions = 6)(m.sum == sum, imm.sum == sum) should be > 1.05f
- }
-
- /* assumption not correct
- def `traversing mutable.Set takes longer than mutable.BitSet`: Unit = {
- val size = 10000
- val seq = ArraySeq.tabulate(size)(_ % (size / 10))
- val s = Set(seq: _*)
- val b = mutable.BitSet(seq: _*)
-
- relativeTime(warmUp = 20, repetitions = 6)(b.sum, s.sum) should be > 1.1f
- }
- */
-}
diff --git a/misc/src/main/scala/scalax/collection/centrality/Katz.scala b/misc/src/main/scala/scalax/collection/centrality/Katz.scala
index 8cfb2449..e76204da 100644
--- a/misc/src/main/scala/scalax/collection/centrality/Katz.scala
+++ b/misc/src/main/scala/scalax/collection/centrality/Katz.scala
@@ -41,11 +41,10 @@ object Katz {
import g.ExtendedNodeVisitor
var weight = 0f
- n.innerNodeTraverser.withMaxDepth(maxDepth) foreach {
+ n.innerNodeTraverser.withMaxDepth(maxDepth) foreach
ExtendedNodeVisitor { (node, count, depth, informer) =>
weight += degrees(node.asInstanceOf[G#NodeT]) * Factor(depth)
}
- }
weightBuilder += ((n.asInstanceOf[G#NodeT], weight))
}
diff --git a/project/Version.scala b/project/Version.scala
index 54704f62..7e291bed 100644
--- a/project/Version.scala
+++ b/project/Version.scala
@@ -1,8 +1,6 @@
object Version {
- val compiler_2_13 = "2.13.15"
- val compiler_3 = "3.5.1"
-
- val compiler_3_fallback = "3.3.0"
+ val compiler_2_13 = "2.13.16"
+ val compiler_3 = "3.3.5"
private val isSnapshot = false
private def snapshot = if (isSnapshot) "-SNAPSHOT" else ""
@@ -11,8 +9,8 @@ object Version {
private val minor = 0
private def version(patch: Int) = s"$major.$minor.$patch$snapshot"
- val highest = version(2)
- val core = version(2)
+ val highest = version(3)
+ val core = version(3)
val dot = version(0)
- val json = version(0)
+ val json = version(3)
}
diff --git a/project/build.properties b/project/build.properties
index 0b699c30..cc68b53f 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=1.10.2
+sbt.version=1.10.11
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 9a000078..a150d90d 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,7 +1,7 @@
-addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2")
-addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.12.1")
-addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0")
-addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.5")
+addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4")
+addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.14.3")
+addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.19.0")
+addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.8")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2")
addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.3.2")
-addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1")
+addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1")