(patch) general code improvements and more documentation #8
8 changed files with 111 additions and 17 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
val scala3: String = "3.8.1"
|
val scala3: String = "3.8.2"
|
||||||
|
|
||||||
ThisBuild / scalaVersion := scala3
|
ThisBuild / scalaVersion := scala3
|
||||||
ThisBuild / versionScheme := Some("semver-spec")
|
ThisBuild / versionScheme := Some("semver-spec")
|
||||||
|
|
@ -31,14 +31,14 @@ val Deps = new {
|
||||||
}
|
}
|
||||||
|
|
||||||
val Fs2 = new {
|
val Fs2 = new {
|
||||||
val Core: ModuleID = "co.fs2" %% "fs2-core" % "3.12.2"
|
val Core: ModuleID = "co.fs2" %% "fs2-core" % "3.13.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
val Gs = new {
|
val Gs = new {
|
||||||
val Datagen: ModuleID = "gs" %% "gs-datagen-core-v0" % "0.4.0"
|
val Datagen: ModuleID = "gs" %% "gs-datagen-core-v0" % "0.4.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
val MUnit: ModuleID = "org.scalameta" %% "munit" % "1.2.1"
|
val MUnit: ModuleID = "org.scalameta" %% "munit" % "1.2.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val testSettings = Seq(
|
lazy val testSettings = Seq(
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,9 @@ final class Adjacency(val neighbors: Vector[Vector[Vertex]]):
|
||||||
tos.map(to => Edge(from, to)).distinct
|
tos.map(to => Edge(from, to)).distinct
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return
|
/** The number of vertices represented by this adjacency list.
|
||||||
* The number of vertices represented by this adjacency list.
|
|
||||||
*/
|
*/
|
||||||
def numberOfVertices: Size = Size.fromVector(neighbors)
|
lazy val numberOfVertices: Size = Size.fromVector(neighbors)
|
||||||
|
|
||||||
/** Perform a linear traversal for each [[gs.graph.v0.Vertex]] to calculate
|
/** Perform a linear traversal for each [[gs.graph.v0.Vertex]] to calculate
|
||||||
* the total number of edges in this adjacency list.
|
* the total number of edges in this adjacency list.
|
||||||
|
|
@ -62,9 +61,11 @@ final class Adjacency(val neighbors: Vector[Vector[Vertex]]):
|
||||||
* @return
|
* @return
|
||||||
* The number of edges in this adjacency list.
|
* The number of edges in this adjacency list.
|
||||||
*/
|
*/
|
||||||
def numberOfEdges: Size = Size(neighbors.map(_.length).reduce(_ + _))
|
lazy val numberOfEdges: Size = Size(neighbors.map(_.length).reduce(_ + _))
|
||||||
|
|
||||||
def findRoots(): Vector[Vertex] =
|
/** All vertices that do not have inbound connections.
|
||||||
|
*/
|
||||||
|
lazy val roots: Vector[Vertex] =
|
||||||
val counts = Array.fill(neighbors.length)(0)
|
val counts = Array.fill(neighbors.length)(0)
|
||||||
neighbors.foreach { ns =>
|
neighbors.foreach { ns =>
|
||||||
// Each vertex listed here is receiving an inbound connection, if we
|
// Each vertex listed here is receiving an inbound connection, if we
|
||||||
|
|
@ -94,6 +95,17 @@ object Adjacency:
|
||||||
*/
|
*/
|
||||||
def apply(adj: Vector[Vector[Vertex]]): Adjacency = new Adjacency(adj)
|
def apply(adj: Vector[Vector[Vertex]]): Adjacency = new Adjacency(adj)
|
||||||
|
|
||||||
|
/** Create an empty adjacency list for some number of vertices. No vertex has
|
||||||
|
* any connections to another vertex.
|
||||||
|
*
|
||||||
|
* @param numberOfVertices
|
||||||
|
* The number of vertices in this disconnected graph.
|
||||||
|
* @return
|
||||||
|
* Some new empty adjacency.
|
||||||
|
*/
|
||||||
|
def empty(numberOfVertices: Size): Adjacency =
|
||||||
|
new Adjacency(Vector.fill(numberOfVertices.value)(Vector.empty))
|
||||||
|
|
||||||
given CanEqual[Adjacency, Adjacency] = CanEqual.derived
|
given CanEqual[Adjacency, Adjacency] = CanEqual.derived
|
||||||
|
|
||||||
/** @return
|
/** @return
|
||||||
|
|
@ -106,7 +118,8 @@ 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]].
|
/** Calculate an [[Adjacency]] from some collection of [[Edge]], where those
|
||||||
|
* 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.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package gs.graph.v0
|
package gs.graph.v0
|
||||||
|
|
||||||
|
import java.util.Objects
|
||||||
|
|
||||||
/** Represents a relationship between two [[Vertex]].
|
/** Represents a relationship between two [[Vertex]].
|
||||||
*
|
*
|
||||||
* When used is a directed context, the edge goes _from_ `v1` _to_ `v2`.
|
* When used is a directed context, the edge goes _from_ `v1` _to_ `v2`.
|
||||||
|
|
@ -41,6 +43,11 @@ final class Edge(
|
||||||
case other: Edge => v1 == other.v1 && v2 == other.v2
|
case other: Edge => v1 == other.v1 && v2 == other.v2
|
||||||
case _ => false
|
case _ => false
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def hashCode(): Int =
|
||||||
|
Objects.hash(v1, v2)
|
||||||
|
|
||||||
end Edge
|
end Edge
|
||||||
|
|
||||||
object Edge:
|
object Edge:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
package gs.graph.v0
|
package gs.graph.v0
|
||||||
|
|
||||||
|
/** Describes the fundamental disposition of some graph.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The string value of this disposition.
|
||||||
|
*/
|
||||||
sealed abstract class GraphDisposition(val name: String):
|
sealed abstract class GraphDisposition(val name: String):
|
||||||
|
|
||||||
override def equals(that: Any): Boolean =
|
override def equals(that: Any): Boolean =
|
||||||
|
|
@ -15,7 +20,12 @@ object GraphDisposition:
|
||||||
|
|
||||||
given CanEqual[GraphDisposition, GraphDisposition] = CanEqual.derived
|
given CanEqual[GraphDisposition, GraphDisposition] = CanEqual.derived
|
||||||
|
|
||||||
case object Directed extends GraphDisposition("directed")
|
/** The graph has directed relationships between vertices.
|
||||||
|
*/
|
||||||
|
case object Directed extends GraphDisposition("directed")
|
||||||
|
|
||||||
|
/** The graph has relationships between vertices with no logical direction.
|
||||||
|
*/
|
||||||
case object Undirected extends GraphDisposition("undirected")
|
case object Undirected extends GraphDisposition("undirected")
|
||||||
|
|
||||||
end GraphDisposition
|
end GraphDisposition
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ class Digraph(
|
||||||
*/
|
*/
|
||||||
override def selectRoots(): Vector[Vertex] = roots
|
override def selectRoots(): Vector[Vertex] = roots
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
override def equals(that: Any): Boolean =
|
override def equals(that: Any): Boolean =
|
||||||
that match
|
that match
|
||||||
case other: Digraph =>
|
case other: Digraph =>
|
||||||
|
|
@ -78,7 +80,7 @@ object Digraph:
|
||||||
new Digraph(
|
new Digraph(
|
||||||
numberOfVertices = adjacency.numberOfVertices,
|
numberOfVertices = adjacency.numberOfVertices,
|
||||||
adjacency = adjacency,
|
adjacency = adjacency,
|
||||||
roots = adjacency.findRoots()
|
roots = adjacency.roots
|
||||||
)
|
)
|
||||||
|
|
||||||
/** Find all roots for the given collection of [[Edge]].
|
/** Find all roots for the given collection of [[Edge]].
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,30 @@ import gs.graph.v0.GraphException
|
||||||
import gs.graph.v0.Size
|
import gs.graph.v0.Size
|
||||||
import gs.graph.v0.Vertex
|
import gs.graph.v0.Vertex
|
||||||
|
|
||||||
|
/** Specialization of [[Digraph]] that always has a single root vertex.
|
||||||
|
*
|
||||||
|
* @param n
|
||||||
|
* The number of [[Vertex]] present in this graph.
|
||||||
|
* @param a
|
||||||
|
* The [[Adjacency]] that describes this graph.
|
||||||
|
* @param r
|
||||||
|
* The singular root [[Vertex]].
|
||||||
|
*/
|
||||||
class SingleRootDigraph(
|
class SingleRootDigraph(
|
||||||
n: Size,
|
n: Size,
|
||||||
a: Adjacency,
|
a: Adjacency,
|
||||||
r: Vertex
|
root: Vertex
|
||||||
) extends Digraph(n, a, Vector(r))
|
) extends Digraph(n, a, Vector(root))
|
||||||
|
|
||||||
object SingleRootDigraph:
|
object SingleRootDigraph:
|
||||||
|
|
||||||
|
/** Attempt to show that the given [[Digraph]] has a single root.
|
||||||
|
*
|
||||||
|
* @param dg
|
||||||
|
* The input [[Digraph]].
|
||||||
|
* @return
|
||||||
|
* [[SingleRootDigraph]] or `None` if the number of roots is not 1.
|
||||||
|
*/
|
||||||
def fromDirectedGraph(dg: Digraph): Option[SingleRootDigraph] =
|
def fromDirectedGraph(dg: Digraph): Option[SingleRootDigraph] =
|
||||||
if dg.roots.size == 1 then
|
if dg.roots.size == 1 then
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -25,6 +41,18 @@ object SingleRootDigraph:
|
||||||
)
|
)
|
||||||
else None
|
else None
|
||||||
|
|
||||||
|
/** Given some edges, build a [[SingleRootDigraph]]. Throw an exception if
|
||||||
|
* this operation fails.
|
||||||
|
*
|
||||||
|
* @param numberOfVertices
|
||||||
|
* The number of [[Vertex]] in the graph.
|
||||||
|
* @param edges
|
||||||
|
* The collection of [[Edge]] that describe the graph.
|
||||||
|
* @param root
|
||||||
|
* The root [[Vertex]].
|
||||||
|
* @return
|
||||||
|
* The new [[SingleRootDigraph]].
|
||||||
|
*/
|
||||||
def fromEdgesUnsafe(
|
def fromEdgesUnsafe(
|
||||||
numberOfVertices: Size,
|
numberOfVertices: Size,
|
||||||
edges: Iterable[Edge],
|
edges: Iterable[Edge],
|
||||||
|
|
@ -38,6 +66,17 @@ object SingleRootDigraph:
|
||||||
)
|
)
|
||||||
else throw GraphException.RootOutOfBounds(root, numberOfVertices)
|
else throw GraphException.RootOutOfBounds(root, numberOfVertices)
|
||||||
|
|
||||||
|
/** Given some edges, build a [[SingleRootDigraph]] if that collection
|
||||||
|
* represents a graph with a single root.
|
||||||
|
*
|
||||||
|
* @param numberOfVertices
|
||||||
|
* The number of [[Vertex]] in the graph.
|
||||||
|
* @param edges
|
||||||
|
* The collection of [[Edge]] that describe the graph.
|
||||||
|
* @return
|
||||||
|
* The new [[SingleRootDigraph]], or `None` if the edges do not describe a
|
||||||
|
* digraph with a single root.
|
||||||
|
*/
|
||||||
def fromEdges(
|
def fromEdges(
|
||||||
numberOfVertices: Size,
|
numberOfVertices: Size,
|
||||||
edges: Iterable[Edge]
|
edges: Iterable[Edge]
|
||||||
|
|
@ -53,6 +92,19 @@ object SingleRootDigraph:
|
||||||
)
|
)
|
||||||
else None
|
else None
|
||||||
|
|
||||||
|
/** Given some [[Adjacency]] and a given root [[Vertex]], instantiate a new
|
||||||
|
* [[SingleRootDigraph]].
|
||||||
|
*
|
||||||
|
* Throws an exception if the given root is not contained within the
|
||||||
|
* [[Adjacency]].
|
||||||
|
*
|
||||||
|
* @param adjacency
|
||||||
|
* The [[Adjacency]] which describes the graph.
|
||||||
|
* @param root
|
||||||
|
* The root [[Vertex]].
|
||||||
|
* @return
|
||||||
|
* New [[SingleRootDigraph]]
|
||||||
|
*/
|
||||||
def fromAdjacencyUnsafe(
|
def fromAdjacencyUnsafe(
|
||||||
adjacency: Adjacency,
|
adjacency: Adjacency,
|
||||||
root: Vertex
|
root: Vertex
|
||||||
|
|
@ -65,10 +117,20 @@ object SingleRootDigraph:
|
||||||
)
|
)
|
||||||
else throw GraphException.RootOutOfBounds(root, adjacency.numberOfVertices)
|
else throw GraphException.RootOutOfBounds(root, adjacency.numberOfVertices)
|
||||||
|
|
||||||
|
/** Given some [[Adjacency]] and a given root [[Vertex]], instantiate a new
|
||||||
|
* [[SingleRootDigraph]] if the [[Vertex]] is within the graph..
|
||||||
|
*
|
||||||
|
* @param adjacency
|
||||||
|
* The [[Adjacency]] which describes the graph.
|
||||||
|
* @param root
|
||||||
|
* The root [[Vertex]].
|
||||||
|
* @return
|
||||||
|
* New [[SingleRootDigraph]], or `None` if the given root is not valid.
|
||||||
|
*/
|
||||||
def fromAdjacency(
|
def fromAdjacency(
|
||||||
adjacency: Adjacency
|
adjacency: Adjacency
|
||||||
): Option[SingleRootDigraph] =
|
): Option[SingleRootDigraph] =
|
||||||
val roots = adjacency.findRoots()
|
val roots = adjacency.roots
|
||||||
if roots.size == 1 then
|
if roots.size == 1 then
|
||||||
Some(
|
Some(
|
||||||
new SingleRootDigraph(
|
new SingleRootDigraph(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package gs.graph.v0
|
||||||
|
|
||||||
class AdjacencyTests extends munit.FunSuite:
|
class AdjacencyTests extends munit.FunSuite:
|
||||||
|
|
||||||
test("should provide incoming") {
|
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 = List(
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
sbt.version=1.12.0
|
sbt.version=1.12.8
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue