Some minor improvements to construction.
This commit is contained in:
parent
eeb8a7400b
commit
80284f8013
9 changed files with 160 additions and 38 deletions
|
|
@ -8,7 +8,7 @@ import scala.collection.mutable.ListBuffer
|
||||||
* the corresponding vector is a "to" [[Vertex]] -- there are edges _from_ some
|
* the corresponding vector is a "to" [[Vertex]] -- there are edges _from_ some
|
||||||
* vertex _to_ another vertex.
|
* vertex _to_ another vertex.
|
||||||
*/
|
*/
|
||||||
final class Adjacency(val neighbors: Vector[Vector[Vertex]]):
|
final class Adjacency private (val neighbors: Vector[Vector[Vertex]]):
|
||||||
/** Get the vector of [[Vertex]] that receive a connection _from_ the input
|
/** Get the vector of [[Vertex]] that receive a connection _from_ the input
|
||||||
* [[Vertex]].
|
* [[Vertex]].
|
||||||
*
|
*
|
||||||
|
|
@ -118,8 +118,7 @@ object Adjacency:
|
||||||
*/
|
*/
|
||||||
final val Single: Adjacency = new Adjacency(Vector(Vector.empty))
|
final val Single: Adjacency = new Adjacency(Vector(Vector.empty))
|
||||||
|
|
||||||
/** Calculate an [[Adjacency]] from some collection of [[Edge]], where those
|
/** Calculate an [[Adjacency]] from some collection of [[Edge]].
|
||||||
* edges are assumed to be directed.
|
|
||||||
*
|
*
|
||||||
* @param numberOfVertices
|
* @param numberOfVertices
|
||||||
* The number of [[Vertex]] (`N`) in this graph.
|
* The number of [[Vertex]] (`N`) in this graph.
|
||||||
|
|
@ -128,14 +127,44 @@ object Adjacency:
|
||||||
* @return
|
* @return
|
||||||
* The calculated [[Adjacency]].
|
* The calculated [[Adjacency]].
|
||||||
*/
|
*/
|
||||||
def fromDirectedEdges(
|
def fromEdges(
|
||||||
numberOfVertices: Size,
|
numberOfVertices: Size,
|
||||||
edges: Iterable[Edge]
|
edges: Iterable[Edge]
|
||||||
): Adjacency =
|
): Adjacency =
|
||||||
|
val buffs = Vector.fill(numberOfVertices.value)(ListBuffer.empty[Vertex])
|
||||||
|
val _ = edges.foreach { edge =>
|
||||||
|
if edge.v1 >= numberOfVertices || edge.v2 >= numberOfVertices then
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
s"Edge (${edge.v1}, ${edge.v2}) is out of bounds. Maximum vertex value is ${numberOfVertices.value - 1}"
|
||||||
|
)
|
||||||
|
else
|
||||||
|
val _ = buffs(edge.from.ordinal).addOne(edge.to)
|
||||||
|
}
|
||||||
|
new Adjacency(buffs.map(_.distinct.toVector))
|
||||||
|
|
||||||
|
/** Calculate an [[Adjacency]] from some collection of [[Edge]].
|
||||||
|
*
|
||||||
|
* @param edges
|
||||||
|
* The collection of [[Edge]] present in this graph.
|
||||||
|
* @return
|
||||||
|
* The calculated [[Adjacency]].
|
||||||
|
*/
|
||||||
|
def fromEdges(
|
||||||
|
edges: Iterable[Edge]
|
||||||
|
): Adjacency =
|
||||||
|
val numberOfVertices = findMaximumVertex(edges)
|
||||||
val buffs = Vector.fill(numberOfVertices.value)(ListBuffer.empty[Vertex])
|
val buffs = Vector.fill(numberOfVertices.value)(ListBuffer.empty[Vertex])
|
||||||
val _ = edges.foreach { edge =>
|
val _ = edges.foreach { edge =>
|
||||||
val _ = buffs(edge.from.ordinal).addOne(edge.to)
|
val _ = buffs(edge.from.ordinal).addOne(edge.to)
|
||||||
}
|
}
|
||||||
new Adjacency(buffs.map(_.distinct.toVector))
|
new Adjacency(buffs.map(_.distinct.toVector))
|
||||||
|
|
||||||
|
private def findMaximumVertex(edges: Iterable[Edge]): Vertex =
|
||||||
|
var maximum = Vertex.Zero
|
||||||
|
edges.foreach { edge =>
|
||||||
|
if edge.max > maximum then maximum = edge.max
|
||||||
|
else ()
|
||||||
|
}
|
||||||
|
maximum
|
||||||
|
|
||||||
end Adjacency
|
end Adjacency
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ final class Edge private (
|
||||||
val v2: Vertex
|
val v2: Vertex
|
||||||
):
|
):
|
||||||
|
|
||||||
|
def max: Vertex = if v1 >= v2 then v1 else v2
|
||||||
|
|
||||||
/** When considering this edge as _directed_, this function returns the
|
/** When considering this edge as _directed_, this function returns the
|
||||||
* [[Vertex]] that is the beginning of the connection.
|
* [[Vertex]] that is the beginning of the connection.
|
||||||
*
|
*
|
||||||
|
|
@ -103,4 +105,14 @@ object Edge:
|
||||||
v2: Int
|
v2: Int
|
||||||
): Edge = Edge(Vertex(v1), Vertex(v2))
|
): Edge = Edge(Vertex(v1), Vertex(v2))
|
||||||
|
|
||||||
|
/** Instantiate a list of Edge.
|
||||||
|
*
|
||||||
|
* @param edges
|
||||||
|
* The list of Edge.
|
||||||
|
* @return
|
||||||
|
* The captured list of Edge.
|
||||||
|
*/
|
||||||
|
def list(edges: (Int, Int)*): List[Edge] =
|
||||||
|
edges.map(e => apply(e._1, e._2)).toList
|
||||||
|
|
||||||
end Edge
|
end Edge
|
||||||
|
|
|
||||||
|
|
@ -58,3 +58,41 @@ trait Graph:
|
||||||
case _ => false
|
case _ => false
|
||||||
|
|
||||||
end Graph
|
end Graph
|
||||||
|
|
||||||
|
object Graph:
|
||||||
|
|
||||||
|
/** Construct a new [[UndirectedGraph]] from the given [[Edge]].
|
||||||
|
*
|
||||||
|
* @param numberOfVertices
|
||||||
|
* The number of vertices in this [[Graph]].
|
||||||
|
* @param edges
|
||||||
|
* The [[Edge]] in this graph.
|
||||||
|
* @return
|
||||||
|
* The new [[UndirectedGraph]].
|
||||||
|
*/
|
||||||
|
def undirected(
|
||||||
|
numberOfVertices: Size,
|
||||||
|
edges: (Int, Int)*
|
||||||
|
): UndirectedGraph =
|
||||||
|
new UndirectedGraph(
|
||||||
|
numberOfVertices,
|
||||||
|
Adjacency.fromEdges(numberOfVertices, Edge.list(edges*))
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Construct a new [[UndirectedGraph]] from the given [[Edge]].
|
||||||
|
*
|
||||||
|
* @param edges
|
||||||
|
* The [[Edge]] in this graph.
|
||||||
|
* @return
|
||||||
|
* The new [[UndirectedGraph]].
|
||||||
|
*/
|
||||||
|
def undirected(
|
||||||
|
edges: (Int, Int)*
|
||||||
|
): UndirectedGraph =
|
||||||
|
val adj = Adjacency.fromEdges(Edge.list(edges*))
|
||||||
|
new UndirectedGraph(
|
||||||
|
adj.numberOfVertices,
|
||||||
|
adj
|
||||||
|
)
|
||||||
|
|
||||||
|
end Graph
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@ package gs.graph.v0
|
||||||
*/
|
*/
|
||||||
final class Vertex private (val ordinal: Int) extends Ordered[Vertex]:
|
final class Vertex private (val ordinal: Int) extends Ordered[Vertex]:
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
* The value (ordinal) of the Vertex.
|
||||||
|
*/
|
||||||
|
def value: Int = ordinal
|
||||||
|
|
||||||
/** @inheritDocs
|
/** @inheritDocs
|
||||||
*/
|
*/
|
||||||
override def compare(that: Vertex): Int =
|
override def compare(that: Vertex): Int =
|
||||||
|
|
@ -37,6 +42,16 @@ final class Vertex private (val ordinal: Int) extends Ordered[Vertex]:
|
||||||
*/
|
*/
|
||||||
infix def <(value: Int): Boolean = ordinal < value
|
infix def <(value: Int): Boolean = ordinal < value
|
||||||
|
|
||||||
|
/** Is the ordinal of this vertex less than or equal to some integer value?
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The integer value.
|
||||||
|
* @return
|
||||||
|
* True if the ordinal is less than or equal to the integer value. False
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
infix def <=(value: Int): Boolean = ordinal <= value
|
||||||
|
|
||||||
/** Is the ordinal of this vertex greater than some integer value?
|
/** Is the ordinal of this vertex greater than some integer value?
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value
|
||||||
|
|
@ -46,6 +61,16 @@ final class Vertex private (val ordinal: Int) extends Ordered[Vertex]:
|
||||||
*/
|
*/
|
||||||
infix def >(value: Int): Boolean = ordinal > value
|
infix def >(value: Int): Boolean = ordinal > value
|
||||||
|
|
||||||
|
/** Is the ordinal of this vertex greater than or equal to some integer value?
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The integer value.
|
||||||
|
* @return
|
||||||
|
* True if the ordinal is greater than or equal to the integer value. False
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
infix def >=(value: Int): Boolean = ordinal >= value
|
||||||
|
|
||||||
/** Is the ordinal of this vertex less than some [[Size]] value?
|
/** Is the ordinal of this vertex less than some [[Size]] value?
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value
|
||||||
|
|
@ -55,6 +80,16 @@ final class Vertex private (val ordinal: Int) extends Ordered[Vertex]:
|
||||||
*/
|
*/
|
||||||
infix def <(size: Size): Boolean = ordinal < size.value
|
infix def <(size: Size): Boolean = ordinal < size.value
|
||||||
|
|
||||||
|
/** Is the ordinal of this vertex less than or equal to some [[Size]] value?
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The [[Size]] value.
|
||||||
|
* @return
|
||||||
|
* True if the ordinal is less than or equal to the [[Size]] value. False
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
infix def <=(size: Size): Boolean = ordinal <= size.value
|
||||||
|
|
||||||
/** Is the ordinal of this vertex greater than some [[Size]] value?
|
/** Is the ordinal of this vertex greater than some [[Size]] value?
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value
|
||||||
|
|
@ -64,6 +99,17 @@ final class Vertex private (val ordinal: Int) extends Ordered[Vertex]:
|
||||||
*/
|
*/
|
||||||
infix def >(size: Size): Boolean = ordinal > size.value
|
infix def >(size: Size): Boolean = ordinal > size.value
|
||||||
|
|
||||||
|
/** Is the ordinal of this vertex greater than or equal to some [[Size]]
|
||||||
|
* value?
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The [[Size]] value.
|
||||||
|
* @return
|
||||||
|
* True if the ordinal is greater than or equal to the [[Size]] value.
|
||||||
|
* False otherwise.
|
||||||
|
*/
|
||||||
|
infix def >=(size: Size): Boolean = ordinal >= size.value
|
||||||
|
|
||||||
object Vertex:
|
object Vertex:
|
||||||
|
|
||||||
/** The fixed value 0 expressed as a [[Vertex]].
|
/** The fixed value 0 expressed as a [[Vertex]].
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ object Digraph:
|
||||||
): Digraph =
|
): Digraph =
|
||||||
new Digraph(
|
new Digraph(
|
||||||
numberOfVertices = numberOfVertices,
|
numberOfVertices = numberOfVertices,
|
||||||
adjacency = Adjacency.fromDirectedEdges(numberOfVertices, edges),
|
adjacency = Adjacency.fromEdges(numberOfVertices, edges),
|
||||||
roots = findRootsForDirectedEdges(numberOfVertices, edges)
|
roots = findRootsForDirectedEdges(numberOfVertices, edges)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ object SingleRootDigraph:
|
||||||
if root < numberOfVertices then
|
if root < numberOfVertices then
|
||||||
new SingleRootDigraph(
|
new SingleRootDigraph(
|
||||||
numberOfVertices,
|
numberOfVertices,
|
||||||
Adjacency.fromDirectedEdges(numberOfVertices, edges),
|
Adjacency.fromEdges(numberOfVertices, edges),
|
||||||
root
|
root
|
||||||
)
|
)
|
||||||
else throw GraphException.RootOutOfBounds(root, numberOfVertices)
|
else throw GraphException.RootOutOfBounds(root, numberOfVertices)
|
||||||
|
|
@ -86,7 +86,7 @@ object SingleRootDigraph:
|
||||||
Some(
|
Some(
|
||||||
new SingleRootDigraph(
|
new SingleRootDigraph(
|
||||||
numberOfVertices,
|
numberOfVertices,
|
||||||
Adjacency.fromDirectedEdges(numberOfVertices, edges),
|
Adjacency.fromEdges(numberOfVertices, edges),
|
||||||
roots(0)
|
roots(0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,17 @@ class AdjacencyTests extends munit.FunSuite:
|
||||||
test("should provide incoming connections") {
|
test("should provide incoming connections") {
|
||||||
val N = Size(7)
|
val N = Size(7)
|
||||||
val vs = (0 until N.value).map(Vertex(_)).toArray
|
val vs = (0 until N.value).map(Vertex(_)).toArray
|
||||||
val E = List(
|
val E = Edge.list(
|
||||||
Edge(vs(0), vs(1)),
|
0 -> 1,
|
||||||
Edge(vs(0), vs(2)),
|
0 -> 2,
|
||||||
Edge(vs(0), vs(3)),
|
0 -> 3,
|
||||||
Edge(vs(1), vs(4)),
|
1 -> 4,
|
||||||
Edge(vs(2), vs(4)),
|
2 -> 4,
|
||||||
Edge(vs(3), vs(4)),
|
3 -> 4,
|
||||||
Edge(vs(3), vs(5)),
|
3 -> 5,
|
||||||
Edge(vs(4), vs(6))
|
4 -> 6
|
||||||
)
|
)
|
||||||
val A = Adjacency.fromDirectedEdges(N, E)
|
val A = Adjacency.fromEdges(N, E)
|
||||||
|
|
||||||
assertEquals(A.incoming(vs(0)), Vector.empty)
|
assertEquals(A.incoming(vs(0)), Vector.empty)
|
||||||
assertEquals(A.incoming(vs(1)), Vector(vs(0)))
|
assertEquals(A.incoming(vs(1)), Vector(vs(0)))
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ class EdgeTests extends FunSuite:
|
||||||
val v3 = Vertex(3)
|
val v3 = Vertex(3)
|
||||||
val edge1 = Edge(v1, v2)
|
val edge1 = Edge(v1, v2)
|
||||||
val edge2 = Edge(v1 -> v2)
|
val edge2 = Edge(v1 -> v2)
|
||||||
val edge3 = new Edge(v3, v1)
|
val edge3 = Edge(v3, v1)
|
||||||
assertEquals(edge1, edge2)
|
assertEquals(edge1, edge2)
|
||||||
assertNotEquals(edge1, edge3)
|
assertNotEquals(edge1, edge3)
|
||||||
assertEquals(edge1.toString(), s"($v1, $v2)")
|
assertEquals(edge1.toString(), s"($v1, $v2)")
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package gs.graph.v0.directed
|
||||||
import gs.graph.v0.Adjacency
|
import gs.graph.v0.Adjacency
|
||||||
import gs.graph.v0.Edge
|
import gs.graph.v0.Edge
|
||||||
import gs.graph.v0.Size
|
import gs.graph.v0.Size
|
||||||
import gs.graph.v0.Vertex
|
|
||||||
import munit.*
|
import munit.*
|
||||||
|
|
||||||
class DagTests extends FunSuite:
|
class DagTests extends FunSuite:
|
||||||
|
|
@ -23,20 +22,19 @@ class DagTests extends FunSuite:
|
||||||
|
|
||||||
test("should validate a single-root graph") {
|
test("should validate a single-root graph") {
|
||||||
val size = Size(8)
|
val size = Size(8)
|
||||||
val vs = (0 until size.value).map(Vertex(_))
|
|
||||||
val digraph: Digraph = Digraph.fromAdjacency(
|
val digraph: Digraph = Digraph.fromAdjacency(
|
||||||
Adjacency.fromDirectedEdges(
|
Adjacency.fromEdges(
|
||||||
numberOfVertices = size,
|
numberOfVertices = size,
|
||||||
edges = Seq(
|
edges = Edge.list(
|
||||||
Edge(vs(0) -> vs(1)),
|
0 -> 1,
|
||||||
Edge(vs(0) -> vs(2)),
|
0 -> 2,
|
||||||
Edge(vs(0) -> vs(3)),
|
0 -> 3,
|
||||||
Edge(vs(1) -> vs(4)),
|
1 -> 4,
|
||||||
Edge(vs(2) -> vs(4)),
|
2 -> 4,
|
||||||
Edge(vs(3) -> vs(5)),
|
3 -> 5,
|
||||||
Edge(vs(4) -> vs(6)),
|
4 -> 6,
|
||||||
Edge(vs(5) -> vs(6)),
|
5 -> 6,
|
||||||
Edge(vs(6) -> vs(7))
|
6 -> 7
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -48,15 +46,14 @@ class DagTests extends FunSuite:
|
||||||
|
|
||||||
test("should NOT validate a single-root digraph with a cycle") {
|
test("should NOT validate a single-root digraph with a cycle") {
|
||||||
val size = Size(4)
|
val size = Size(4)
|
||||||
val vs = (0 until size.value).map(Vertex(_))
|
|
||||||
val digraph: Digraph = Digraph.fromAdjacency(
|
val digraph: Digraph = Digraph.fromAdjacency(
|
||||||
Adjacency.fromDirectedEdges(
|
Adjacency.fromEdges(
|
||||||
numberOfVertices = size,
|
numberOfVertices = size,
|
||||||
edges = Seq(
|
edges = Edge.list(
|
||||||
Edge(vs(0) -> vs(1)),
|
0 -> 1,
|
||||||
Edge(vs(1) -> vs(2)),
|
1 -> 2,
|
||||||
Edge(vs(2) -> vs(3)),
|
2 -> 3,
|
||||||
Edge(vs(3) -> vs(1))
|
3 -> 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue