Back to passing tests
This commit is contained in:
parent
00174ae81d
commit
44a3bb6a22
6 changed files with 59 additions and 65 deletions
|
|
@ -93,12 +93,16 @@ sealed trait Adjacency:
|
||||||
override def equals(that: Any): Boolean =
|
override def equals(that: Any): Boolean =
|
||||||
val tuple = (this, that)
|
val tuple = (this, that)
|
||||||
tuple match
|
tuple match
|
||||||
|
// Optimize when two default implementations are present.
|
||||||
case (me: DefaultAdjacency, other: DefaultAdjacency) =>
|
case (me: DefaultAdjacency, other: DefaultAdjacency) =>
|
||||||
me.neighbors.length == other.neighbors.length
|
me.neighbors.length == other.neighbors.length
|
||||||
&& me.neighbors
|
&& me.neighbors
|
||||||
.zip(other.neighbors)
|
.zip(other.neighbors)
|
||||||
.map { case (x, y) => x.sameElements(y) }
|
.map { case (x, y) => x.sameElements(y) }
|
||||||
.forall(result => result)
|
.forall(result => result)
|
||||||
|
// Any two adjcency lists.
|
||||||
|
case (me: Adjacency, other: Adjacency) =>
|
||||||
|
me.entries.equals(other.entries)
|
||||||
case _ => false
|
case _ => false
|
||||||
|
|
||||||
object Adjacency:
|
object Adjacency:
|
||||||
|
|
@ -136,6 +140,15 @@ object Adjacency:
|
||||||
*/
|
*/
|
||||||
final val Single: Adjacency = DefaultAdjacency.Single
|
final val Single: Adjacency = DefaultAdjacency.Single
|
||||||
|
|
||||||
|
/** Instantiate a single-vertex adjacency list.
|
||||||
|
*
|
||||||
|
* @param vertex
|
||||||
|
* The vertex.
|
||||||
|
* @return
|
||||||
|
* The new [[Adjacency]].
|
||||||
|
*/
|
||||||
|
def single(vertex: Vertex): Adjacency = MappedAdjacency.single(vertex)
|
||||||
|
|
||||||
/** Calculate an [[Adjacency]] from some collection of [[Edge]].
|
/** Calculate an [[Adjacency]] from some collection of [[Edge]].
|
||||||
*
|
*
|
||||||
* @param numberOfVertices
|
* @param numberOfVertices
|
||||||
|
|
@ -152,6 +165,13 @@ object Adjacency:
|
||||||
DefaultAdjacency.fromEdges(numberOfVertices, edges)
|
DefaultAdjacency.fromEdges(numberOfVertices, edges)
|
||||||
|
|
||||||
/** Calculate an [[Adjacency]] from some collection of [[Edge]].
|
/** Calculate an [[Adjacency]] from some collection of [[Edge]].
|
||||||
|
*
|
||||||
|
* This function uses the maximum vertex value as an upper bound and assumes
|
||||||
|
* that there are vertices with no neighbors within that bound -- it creates
|
||||||
|
* some [[DefaultAdjacency]].
|
||||||
|
*
|
||||||
|
* Used the mapped version if you want to ensure that _only_ the vertices
|
||||||
|
* referenced are contained in the result.
|
||||||
*
|
*
|
||||||
* @param edges
|
* @param edges
|
||||||
* The collection of [[Edge]] present in this graph.
|
* The collection of [[Edge]] present in this graph.
|
||||||
|
|
@ -163,6 +183,18 @@ object Adjacency:
|
||||||
): Adjacency =
|
): Adjacency =
|
||||||
DefaultAdjacency.fromEdges(edges)
|
DefaultAdjacency.fromEdges(edges)
|
||||||
|
|
||||||
|
/** Calculate an [[Adjacency]] from some collection of [[Edge]].
|
||||||
|
*
|
||||||
|
* @param edges
|
||||||
|
* The collection of [[Edge]] present in this graph.
|
||||||
|
* @return
|
||||||
|
* The calculated [[Adjacency]].
|
||||||
|
*/
|
||||||
|
def fromEdgesMapped(
|
||||||
|
edges: Iterable[Edge]
|
||||||
|
): Adjacency =
|
||||||
|
MappedAdjacency.fromEdges(edges)
|
||||||
|
|
||||||
end Adjacency
|
end Adjacency
|
||||||
|
|
||||||
/** An immutable adjacency list representation.
|
/** An immutable adjacency list representation.
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ import gs.graph.v0.Vertex
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
import scala.collection.mutable.Queue
|
import scala.collection.mutable.Queue
|
||||||
|
|
||||||
/** Represents a _ Connected Component_.
|
/** Represents a _Connected Component_.
|
||||||
*
|
|
||||||
* TODO: ADD EDGES!
|
|
||||||
*/
|
*/
|
||||||
final class ConnectedComponent private (val value: Set[Vertex]):
|
final class ConnectedComponent private (
|
||||||
|
val value: Set[Vertex],
|
||||||
|
val adjacency: Adjacency
|
||||||
|
):
|
||||||
|
|
||||||
/** @inheritDocs
|
/** @inheritDocs
|
||||||
*/
|
*/
|
||||||
|
|
@ -25,9 +26,13 @@ final class ConnectedComponent private (val value: Set[Vertex]):
|
||||||
*/
|
*/
|
||||||
override def toString(): String =
|
override def toString(): String =
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
sb.append("[")
|
sb.append("entries:[\n")
|
||||||
sb.append(value.mkString(","))
|
sb.append(
|
||||||
sb.append("]")
|
adjacency.entries
|
||||||
|
.map { case (v, ns) => s"$v -> ${ns.mkString(",")}" }
|
||||||
|
.mkString("\n")
|
||||||
|
)
|
||||||
|
sb.append("\n]")
|
||||||
sb.toString()
|
sb.toString()
|
||||||
|
|
||||||
/** @return
|
/** @return
|
||||||
|
|
@ -53,30 +58,6 @@ end ConnectedComponent
|
||||||
|
|
||||||
object ConnectedComponent:
|
object ConnectedComponent:
|
||||||
|
|
||||||
/** Instantiate a new Connected Component from the given collection of
|
|
||||||
* [[Vertex]].
|
|
||||||
*
|
|
||||||
* This constructor ensures that each [[Vertex]] only occurs once.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* The input collection.
|
|
||||||
* @return
|
|
||||||
* The new Connected Component.
|
|
||||||
*/
|
|
||||||
def apply(value: Vertex*): ConnectedComponent =
|
|
||||||
if value.isEmpty then
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Empty connected components are not allowed."
|
|
||||||
)
|
|
||||||
else new ConnectedComponent(value.toSet)
|
|
||||||
|
|
||||||
def of(value: Int*): ConnectedComponent =
|
|
||||||
if value.isEmpty then
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Empty connected components are not allowed."
|
|
||||||
)
|
|
||||||
else new ConnectedComponent(value.map(Vertex.apply).toSet)
|
|
||||||
|
|
||||||
/** Instantiate a new Connected Component that contains a single [[Vertex]].
|
/** Instantiate a new Connected Component that contains a single [[Vertex]].
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value
|
||||||
|
|
@ -85,7 +66,7 @@ object ConnectedComponent:
|
||||||
* The new Connected Component.
|
* The new Connected Component.
|
||||||
*/
|
*/
|
||||||
def single(value: Vertex): ConnectedComponent =
|
def single(value: Vertex): ConnectedComponent =
|
||||||
new ConnectedComponent(Set(value))
|
new ConnectedComponent(Set(value), Adjacency.single(value))
|
||||||
|
|
||||||
given CanEqual[ConnectedComponent, ConnectedComponent] = CanEqual.derived
|
given CanEqual[ConnectedComponent, ConnectedComponent] = CanEqual.derived
|
||||||
|
|
||||||
|
|
@ -120,7 +101,8 @@ object ConnectedComponent:
|
||||||
else ()
|
else ()
|
||||||
}
|
}
|
||||||
|
|
||||||
new ConnectedComponent(b.toSet)
|
val vs = b.toSet
|
||||||
|
new ConnectedComponent(vs, g.adjacency.subset(vs))
|
||||||
|
|
||||||
private class Tracker(val data: Array[Boolean]):
|
private class Tracker(val data: Array[Boolean]):
|
||||||
def visit(v: Vertex): Unit = data(v.ordinal) = true
|
def visit(v: Vertex): Unit = data(v.ordinal) = true
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ class AdjacencyTests extends munit.FunSuite:
|
||||||
private val adj = Adjacency.fromEdges(size, edges)
|
private val adj = Adjacency.fromEdges(size, edges)
|
||||||
|
|
||||||
test("should provide equality") {
|
test("should provide equality") {
|
||||||
val a2 = Adjacency(adj.neighbors)
|
val a2 = MappedAdjacency.validate(adj.entries)
|
||||||
val a3 = Adjacency.Single
|
val a3 = Adjacency.Single
|
||||||
|
|
||||||
assertEquals(adj, a2)
|
assertEquals(adj, a2)
|
||||||
|
|
|
||||||
|
|
@ -37,20 +37,3 @@ class UndirectedGraphTests extends FunSuite:
|
||||||
assertEquals(g.neighbors(Vertex(0)), Vector(Vertex(1), Vertex(2)))
|
assertEquals(g.neighbors(Vertex(0)), Vector(Vertex(1), Vertex(2)))
|
||||||
assertEquals(g.neighbors(Vertex(4)), Vector.empty)
|
assertEquals(g.neighbors(Vertex(4)), Vector.empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("should calculate roots for each connected component") {
|
|
||||||
val N = Size(10)
|
|
||||||
val g = Graph.undirected(
|
|
||||||
numberOfVertices = N,
|
|
||||||
edges = 0 -> 1,
|
|
||||||
1 -> 2,
|
|
||||||
2 -> 3,
|
|
||||||
4 -> 5,
|
|
||||||
5 -> 6,
|
|
||||||
4 -> 6,
|
|
||||||
7 -> 8
|
|
||||||
)
|
|
||||||
val expectedRoots = Vertex.of(0, 4, 7, 9)
|
|
||||||
|
|
||||||
assertEquals(g.roots, expectedRoots)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ class DigraphTests extends FunSuite:
|
||||||
val dg = Digraph.Empty
|
val dg = Digraph.Empty
|
||||||
assertEquals(dg.numberOfVertices, Size.Zero)
|
assertEquals(dg.numberOfVertices, Size.Zero)
|
||||||
assertEquals(dg.isSingle, false)
|
assertEquals(dg.isSingle, false)
|
||||||
assertEquals(dg.roots, Vector.empty)
|
|
||||||
assertEquals(dg.isEmpty, true)
|
assertEquals(dg.isEmpty, true)
|
||||||
assertEquals(dg.neighbors(Vertex.Zero), Vector.empty)
|
assertEquals(dg.neighbors(Vertex.Zero), Vector.empty)
|
||||||
assertEquals(dg.hasCycle, false)
|
assertEquals(dg.hasCycle, false)
|
||||||
|
|
@ -21,7 +20,6 @@ class DigraphTests extends FunSuite:
|
||||||
val dg = Digraph.Single
|
val dg = Digraph.Single
|
||||||
assertEquals(dg.numberOfVertices, Size.One)
|
assertEquals(dg.numberOfVertices, Size.One)
|
||||||
assertEquals(dg.isSingle, true)
|
assertEquals(dg.isSingle, true)
|
||||||
assertEquals(dg.roots, Vertex.of(0))
|
|
||||||
assertEquals(dg.isEmpty, false)
|
assertEquals(dg.isEmpty, false)
|
||||||
assertEquals(dg.neighbors(Vertex.Zero), Vector.empty)
|
assertEquals(dg.neighbors(Vertex.Zero), Vector.empty)
|
||||||
assertEquals(dg.hasCycle, false)
|
assertEquals(dg.hasCycle, false)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import gs.graph.v0.Edge
|
||||||
import gs.graph.v0.Graph
|
import gs.graph.v0.Graph
|
||||||
import gs.graph.v0.Size
|
import gs.graph.v0.Size
|
||||||
import gs.graph.v0.Vertex
|
import gs.graph.v0.Vertex
|
||||||
|
import gs.graph.v0.syntax.V
|
||||||
import munit.*
|
import munit.*
|
||||||
|
|
||||||
class TarjansTests extends FunSuite:
|
class TarjansTests extends FunSuite:
|
||||||
|
|
@ -13,13 +14,13 @@ class TarjansTests extends FunSuite:
|
||||||
val v0 = Vertex.Zero
|
val v0 = Vertex.Zero
|
||||||
val v1 = Vertex(1)
|
val v1 = Vertex(1)
|
||||||
val v2 = Vertex(2)
|
val v2 = Vertex(2)
|
||||||
val s1 = StronglyConnectedComponent(v0)
|
val s1 = StronglyConnectedComponent.single(v0)
|
||||||
val s2 = StronglyConnectedComponent(v0, v1, v2)
|
val s2 = StronglyConnectedComponent.of(0 -> 1, 1 -> 2, 2 -> 0)
|
||||||
val s3 = StronglyConnectedComponent(v0)
|
val s3 = StronglyConnectedComponent.single(v0)
|
||||||
|
|
||||||
assertEquals(s1, s3)
|
assertEquals(s1, s3)
|
||||||
assertNotEquals(s1, s2)
|
assertNotEquals(s1, s2)
|
||||||
assertEquals(s2.value, Set(v0, v1, v2))
|
assertEquals(s2.vertices, Set(v0, v1, v2))
|
||||||
assertEquals(s2.vertices, Set(v0, v1, v2))
|
assertEquals(s2.vertices, Set(v0, v1, v2))
|
||||||
assertEquals(s2.size, 3)
|
assertEquals(s2.size, 3)
|
||||||
assertEquals(s2.isSingle, false)
|
assertEquals(s2.isSingle, false)
|
||||||
|
|
@ -60,13 +61,12 @@ class TarjansTests extends FunSuite:
|
||||||
)
|
)
|
||||||
|
|
||||||
val sccs = StronglyConnectedComponent.findAll(g)
|
val sccs = StronglyConnectedComponent.findAll(g)
|
||||||
assertEquals(g.roots, Vector(Vertex.Zero))
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
sccs.toSet,
|
sccs.toSet,
|
||||||
Set(
|
Set(
|
||||||
StronglyConnectedComponent.of(0),
|
StronglyConnectedComponent.single(V(0)),
|
||||||
StronglyConnectedComponent.of(1),
|
StronglyConnectedComponent.single(V(1)),
|
||||||
StronglyConnectedComponent.of(2)
|
StronglyConnectedComponent.single(V(2))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -99,13 +99,12 @@ class TarjansTests extends FunSuite:
|
||||||
)
|
)
|
||||||
|
|
||||||
val sccs = StronglyConnectedComponent.findAll(g)
|
val sccs = StronglyConnectedComponent.findAll(g)
|
||||||
assertEquals(g.roots, Vector.empty)
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
sccs.toSet,
|
sccs.toSet,
|
||||||
Set(
|
Set(
|
||||||
StronglyConnectedComponent.of(0, 1, 2),
|
StronglyConnectedComponent.of(0 -> 1, 1 -> 2, 2 -> 0),
|
||||||
StronglyConnectedComponent.of(3, 4, 5),
|
StronglyConnectedComponent.of(3 -> 4, 4 -> 5, 5 -> 3),
|
||||||
StronglyConnectedComponent.of(6, 7, 8)
|
StronglyConnectedComponent.of(6 -> 7, 7 -> 8, 8 -> 6)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue