Skip to content

Commit d2ceaa8

Browse files
William FisetWilliam Fiset
William Fiset
authored and
William Fiset
committed
Added tests for Kahn's algorithm
1 parent 3d2af97 commit d2ceaa8

File tree

3 files changed

+140
-2
lines changed

3 files changed

+140
-2
lines changed

src/main/java/com/williamfiset/algorithms/graphtheory/Kahns.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
// ./gradlew run -Palgorithm=graphtheory.Kahns
2-
1+
/**
2+
* Implementation of Kahn's algorithm
3+
*
4+
* <p>./gradlew run -Palgorithm=graphtheory.Kahns
5+
*/
36
package com.williamfiset.algorithms.graphtheory;
47

58
import java.util.*;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.williamfiset.algorithms.utils.graphutils;
2+
3+
import java.util.*;
4+
5+
public class GraphGenerator {
6+
7+
public static class DagGenerator {
8+
double edgeProbability;
9+
int minLevels, maxLevels, minNodesPerLevel, maxNodesPerLevel;
10+
11+
// Generates a DAg gives several parameters. Make sure the edge probability
12+
// is high enough to make a mostly connected graph.
13+
public DagGenerator(
14+
int minLevels,
15+
int maxLevels,
16+
int minNodesPerLevel,
17+
int maxNodesPerLevel,
18+
double edgeProbability) {
19+
this.minLevels = minLevels;
20+
this.maxLevels = maxLevels;
21+
this.minNodesPerLevel = minNodesPerLevel;
22+
this.maxNodesPerLevel = maxNodesPerLevel;
23+
this.edgeProbability = edgeProbability;
24+
}
25+
26+
/**
27+
* @param min - The minimum.
28+
* @param max - The maximum.
29+
* @return A random double between these numbers (inclusive the minimum and maximum).
30+
*/
31+
private static int rand(int min, int max) {
32+
return min + (int) (Math.random() * ((max - min) + 1));
33+
}
34+
35+
public List<List<Integer>> createDag() {
36+
int levels = rand(minLevels, maxLevels);
37+
int[] nodesPerLevel = new int[levels];
38+
39+
int n = 0;
40+
for (int l = 0; l < levels; l++) {
41+
nodesPerLevel[l] = rand(minNodesPerLevel, maxNodesPerLevel);
42+
n += nodesPerLevel[l];
43+
}
44+
List<List<Integer>> g = Utils.createEmptyAdjacencyList(n);
45+
int levelIndex = 0;
46+
for (int l = 0; l < levels - 1; l++) { // For each level
47+
for (int i = 0; i < nodesPerLevel[l]; i++) { // for each node on each level
48+
for (int j = 0; j < nodesPerLevel[l + 1]; j++) { // for each possible edge link
49+
if (Math.random() <= edgeProbability) {
50+
Utils.addDirectedEdge(g, levelIndex + i, levelIndex + nodesPerLevel[l] + j);
51+
}
52+
}
53+
}
54+
levelIndex += nodesPerLevel[l];
55+
}
56+
return g;
57+
}
58+
}
59+
60+
public static void main(String[] args) {
61+
DagGenerator gen = new DagGenerator(10, 10, 5, 5, 0.9);
62+
gen.createDag();
63+
}
64+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.williamfiset.algorithms.graphtheory;
2+
3+
import static com.google.common.truth.Truth.assertThat;
4+
5+
import com.williamfiset.algorithms.utils.graphutils.GraphGenerator;
6+
import com.williamfiset.algorithms.utils.graphutils.Utils;
7+
import java.util.*;
8+
import org.junit.*;
9+
10+
public class KahnsTest {
11+
12+
private static boolean find(List<List<Integer>> g, boolean[] vis, int at, int target) {
13+
List<Integer> edges = g.get(at);
14+
if (edges.size() == 0 || vis[at]) {
15+
return false;
16+
}
17+
if (at == target) {
18+
return true;
19+
}
20+
vis[at] = true;
21+
for (int next : edges) {
22+
if (find(g, vis, next, target)) {
23+
return true;
24+
}
25+
}
26+
return false;
27+
}
28+
29+
// Verifies that the topological ordering is not violated, O(n^2)
30+
private static boolean isTopsortOrdering(List<List<Integer>> g, int[] order) {
31+
int n = g.size();
32+
for (int i = 0; i < n; i++) {
33+
for (int j = i + 1; j < n; j++) {
34+
// jAppearsBeforeNodeI
35+
if (find(g, new boolean[n], order[j], order[i])) {
36+
return false;
37+
}
38+
}
39+
}
40+
return true;
41+
}
42+
43+
@Test
44+
public void verifyIsTopsortOrdering() {
45+
List<List<Integer>> g = Utils.createEmptyAdjacencyList(3);
46+
Utils.addDirectedEdge(g, 0, 1);
47+
Utils.addDirectedEdge(g, 1, 2);
48+
int[] order = {2, 1, 0};
49+
assertThat(isTopsortOrdering(g, order)).isEqualTo(false);
50+
}
51+
52+
@Test
53+
public void randomTest() {
54+
GraphGenerator.DagGenerator dagGen = new GraphGenerator.DagGenerator(10, 10, 5, 5, 0.86);
55+
List<List<Integer>> g = dagGen.createDag();
56+
Kahns solver = new Kahns();
57+
int[] order = solver.kahns(g);
58+
assertThat(isTopsortOrdering(g, order)).isEqualTo(true);
59+
}
60+
61+
@Test
62+
public void randomTests() {
63+
for (double p = 0.7; p <= 1.0; p += 0.02) {
64+
GraphGenerator.DagGenerator dagGen = new GraphGenerator.DagGenerator(2, 20, 4, 15, p);
65+
List<List<Integer>> g = dagGen.createDag();
66+
Kahns solver = new Kahns();
67+
int[] order = solver.kahns(g);
68+
assertThat(isTopsortOrdering(g, order)).isEqualTo(true);
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)