diff --git a/build.gradle.kts b/build.gradle.kts index fefbf94..f14c616 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,10 @@ kotlin { sourceSets { val commonMain by getting { dependencies { implementation(kotlin("stdlib-common")) } } val commonTest by getting { dependencies { implementation(kotlin("test")) } } - all { languageSettings.optIn("kotlin.contracts.ExperimentalContracts") } + all { + languageSettings.optIn("kotlin.contracts.ExperimentalContracts") + languageSettings.optIn("kotlin.time.ExperimentalTime") + } } } diff --git a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/algorithms/KosarajuTests.kt b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/algorithms/KosarajuTests.kt index 5b7545e..323173a 100644 --- a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/algorithms/KosarajuTests.kt +++ b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/algorithms/KosarajuTests.kt @@ -1,10 +1,13 @@ package io.github.alexandrepiveteau.graphs.algorithms +import io.github.alexandrepiveteau.graphs.DirectedGraph import io.github.alexandrepiveteau.graphs.VertexArray import io.github.alexandrepiveteau.graphs.arcTo import io.github.alexandrepiveteau.graphs.asIntArray import io.github.alexandrepiveteau.graphs.builder.buildDirectedGraph +import io.github.alexandrepiveteau.graphs.builder.erdosRenyi import io.github.alexandrepiveteau.graphs.util.Repeats +import kotlin.random.Random import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals @@ -125,4 +128,15 @@ class KosarajuTests { assertNotEquals(scc[map[graph[2]]], scc[map[graph[4]]]) assertNotEquals(scc[map[graph[3]]], scc[map[graph[4]]]) } + + @Test + fun randomGraphsHaveTopologicalSortAfterScc() { + val random = Random(42) + repeat(Repeats) { + val graph = DirectedGraph.erdosRenyi(n = 1_000, p = 0.1, random = random) + val (scc, map) = graph.stronglyConnectedComponentsKosaraju() + val order = scc.topologicalSort() + assertEquals(map.values().asIntArray().distinct().count(), order.size) + } + } } diff --git a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/builder/ErdosRenyi.kt b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/builder/ErdosRenyi.kt new file mode 100644 index 0000000..0b16d6e --- /dev/null +++ b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/builder/ErdosRenyi.kt @@ -0,0 +1,50 @@ +package io.github.alexandrepiveteau.graphs.builder + +import io.github.alexandrepiveteau.graphs.* +import kotlin.random.Random + +/** + * Creates a random [UndirectedGraph] with [n] vertices and an edge between each pair of vertices + * with probability [p]. + * + * @param n the number of vertices in the graph. + * @param p the probability of an edge between two vertices. + * @param random the [Random] instance to use. + */ +fun UndirectedGraph.Companion.erdosRenyi( + n: Int, + p: Double, + random: Random = Random, +) = buildUndirectedGraph { + val vertices = VertexArray(n) { addVertex() } + for (i in 0 until n) { + for (j in i + 1 until n) { + if (random.nextDouble() < p) { + addEdge(vertices[i] edgeTo vertices[j]) + } + } + } +} + +/** + * Creates a random [DirectedGraph] with [n] vertices and an arc between each pair of vertices with + * probability [p]. + * + * @param n the number of vertices in the graph. + * @param p the probability of an arc between two vertices. + * @param random the [Random] instance to use. + */ +fun DirectedGraph.Companion.erdosRenyi( + n: Int, + p: Double, + random: Random = Random, +) = buildDirectedGraph { + val vertices = VertexArray(n) { addVertex() } + for (i in 0 until n) { + for (j in 0 until n) { + if (random.nextDouble() < p) { + addArc(vertices[i] arcTo vertices[j]) + } + } + } +}