Compare commits

..

No commits in common. "main" and "0.1.6" have entirely different histories.
main ... 0.1.6

8 changed files with 17 additions and 138 deletions

View file

@ -1,4 +1,4 @@
val scala3: String = "3.8.2" val scala3: String = "3.8.1"
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.13.0" val Core: ModuleID = "co.fs2" %% "fs2-core" % "3.12.2"
} }
val Gs = new { val Gs = new {
val Datagen: ModuleID = "gs" %% "gs-datagen-core-v0" % "0.4.1" val Datagen: ModuleID = "gs" %% "gs-datagen-core-v0" % "0.4.0"
} }
val MUnit: ModuleID = "org.scalameta" %% "munit" % "1.2.4" val MUnit: ModuleID = "org.scalameta" %% "munit" % "1.2.1"
} }
lazy val testSettings = Seq( lazy val testSettings = Seq(

View file

@ -32,7 +32,7 @@ final class Adjacency(val neighbors: Vector[Vector[Vertex]]):
if vertex.ordinal >= neighbors.length then Vector.empty if vertex.ordinal >= neighbors.length then Vector.empty
else else
neighbors.zipWithIndex neighbors.zipWithIndex
.filter { .filterNot {
// ignore the neighbors of the input vertex // ignore the neighbors of the input vertex
case (_, index) => index != vertex.ordinal case (_, index) => index != vertex.ordinal
} }
@ -51,9 +51,10 @@ final class Adjacency(val neighbors: Vector[Vector[Vertex]]):
tos.map(to => Edge(from, to)).distinct tos.map(to => Edge(from, to)).distinct
} }
/** The number of vertices represented by this adjacency list. /** @return
* The number of vertices represented by this adjacency list.
*/ */
lazy val numberOfVertices: Size = Size.fromVector(neighbors) def 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.
@ -61,11 +62,9 @@ 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.
*/ */
lazy val numberOfEdges: Size = Size(neighbors.map(_.length).reduce(_ + _)) def numberOfEdges: Size = Size(neighbors.map(_.length).reduce(_ + _))
/** All vertices that do not have inbound connections. def findRoots(): Vector[Vertex] =
*/
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
@ -95,17 +94,6 @@ 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
@ -118,8 +106,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.

View file

@ -1,7 +1,5 @@
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`.
@ -43,11 +41,6 @@ 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:

View file

@ -1,10 +1,5 @@
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 =
@ -20,12 +15,7 @@ object GraphDisposition:
given CanEqual[GraphDisposition, GraphDisposition] = CanEqual.derived given CanEqual[GraphDisposition, GraphDisposition] = CanEqual.derived
/** The graph has directed relationships between vertices.
*/
case object Directed extends GraphDisposition("directed") 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

View file

@ -29,8 +29,6 @@ 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 =>
@ -80,7 +78,7 @@ object Digraph:
new Digraph( new Digraph(
numberOfVertices = adjacency.numberOfVertices, numberOfVertices = adjacency.numberOfVertices,
adjacency = adjacency, adjacency = adjacency,
roots = adjacency.roots roots = adjacency.findRoots()
) )
/** Find all roots for the given collection of [[Edge]]. /** Find all roots for the given collection of [[Edge]].

View file

@ -6,30 +6,14 @@ 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,
root: Vertex r: Vertex
) extends Digraph(n, a, Vector(root)) ) extends Digraph(n, a, Vector(r))
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(
@ -41,18 +25,6 @@ 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],
@ -66,17 +38,6 @@ 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]
@ -92,19 +53,6 @@ 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
@ -117,20 +65,10 @@ 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.roots val roots = adjacency.findRoots()
if roots.size == 1 then if roots.size == 1 then
Some( Some(
new SingleRootDigraph( new SingleRootDigraph(

View file

@ -1,27 +0,0 @@
package gs.graph.v0
class AdjacencyTests extends munit.FunSuite:
test("should provide incoming connections") {
val N = Size(7)
val vs = (0 until N.value).map(Vertex(_)).toArray
val E = List(
Edge(vs(0), vs(1)),
Edge(vs(0), vs(2)),
Edge(vs(0), vs(3)),
Edge(vs(1), vs(4)),
Edge(vs(2), vs(4)),
Edge(vs(3), vs(4)),
Edge(vs(3), vs(5)),
Edge(vs(4), vs(6))
)
val A = Adjacency.fromDirectedEdges(N, E)
assertEquals(A.incoming(vs(0)), Vector.empty)
assertEquals(A.incoming(vs(1)), Vector(vs(0)))
assertEquals(A.incoming(vs(2)), Vector(vs(0)))
assertEquals(A.incoming(vs(3)), Vector(vs(0)))
assertEquals(A.incoming(vs(4)), Vector(vs(1), vs(2), vs(3)))
assertEquals(A.incoming(vs(5)), Vector(vs(3)))
assertEquals(A.incoming(vs(6)), Vector(vs(4)))
}

View file

@ -1 +1 @@
sbt.version=1.12.8 sbt.version=1.12.0