diff --git a/api/kotlin-graphs.api b/api/kotlin-graphs.api index c8504c3..4441d40 100644 --- a/api/kotlin-graphs.api +++ b/api/kotlin-graphs.api @@ -21,28 +21,31 @@ public final class io/github/alexandrepiveteau/graphs/ArcKt { public static final fun arcTo-cK2_UGU (II)J } -public abstract interface class io/github/alexandrepiveteau/graphs/DirectedGraph : io/github/alexandrepiveteau/graphs/Graph { - public static final field Companion Lio/github/alexandrepiveteau/graphs/DirectedGraph$Companion; +public abstract interface class io/github/alexandrepiveteau/graphs/Directed { public abstract fun contains--OaZVeM (J)Z } +public abstract interface class io/github/alexandrepiveteau/graphs/DirectedGraph : io/github/alexandrepiveteau/graphs/Directed, io/github/alexandrepiveteau/graphs/Graph { + public static final field Companion Lio/github/alexandrepiveteau/graphs/DirectedGraph$Companion; +} + public final class io/github/alexandrepiveteau/graphs/DirectedGraph$Companion { } public final class io/github/alexandrepiveteau/graphs/DirectedGraph$DefaultImpls { public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/DirectedGraph;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/DirectedGraph;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/DirectedGraph;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/DirectedGraph;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/DirectedGraph;I)I } public final class io/github/alexandrepiveteau/graphs/DirectedGraphKt { - public static final fun toUndirectedGraph (Lio/github/alexandrepiveteau/graphs/DirectedGraph;)Lio/github/alexandrepiveteau/graphs/UndirectedGraph; - public static final fun transposed (Lio/github/alexandrepiveteau/graphs/DirectedGraph;)Lio/github/alexandrepiveteau/graphs/DirectedGraph; + public static final fun toUndirectedGraph (Lio/github/alexandrepiveteau/graphs/Directed;)Lio/github/alexandrepiveteau/graphs/UndirectedGraph; + public static final fun transposed (Lio/github/alexandrepiveteau/graphs/Directed;)Lio/github/alexandrepiveteau/graphs/DirectedGraph; } public abstract interface class io/github/alexandrepiveteau/graphs/DirectedNetwork : io/github/alexandrepiveteau/graphs/DirectedGraph, io/github/alexandrepiveteau/graphs/Network { public static final field Companion Lio/github/alexandrepiveteau/graphs/DirectedNetwork$Companion; - public abstract fun weight--OaZVeM (J)I } public final class io/github/alexandrepiveteau/graphs/DirectedNetwork$Companion { @@ -50,11 +53,15 @@ public final class io/github/alexandrepiveteau/graphs/DirectedNetwork$Companion public final class io/github/alexandrepiveteau/graphs/DirectedNetwork$DefaultImpls { public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;II)I + public static fun successorWeight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;II)I + public static fun successorWeight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;I)I - public static fun weight--OaZVeM (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;J)I - public static fun weight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;II)I - public static fun weight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;II)I +} + +public final class io/github/alexandrepiveteau/graphs/DirectedNetworkKt { + public static final fun successorWeight-hOs2cps (Lio/github/alexandrepiveteau/graphs/Directed;J)I } public final class io/github/alexandrepiveteau/graphs/Edge { @@ -79,20 +86,13 @@ public final class io/github/alexandrepiveteau/graphs/EdgeKt { public static final fun edgeTo-cK2_UGU (II)J } -public abstract interface class io/github/alexandrepiveteau/graphs/Graph { - public abstract fun contains-dT2TSiQ (I)Z - public abstract fun getSize ()I - public abstract fun index-dT2TSiQ (I)I - public abstract fun successor-_QOBl-4 (II)I - public abstract fun successor-vAesux8 (II)I - public abstract fun successorsSize (I)I - public abstract fun successorsSize-dT2TSiQ (I)I - public abstract fun vertex-1Pv3iCI (I)I +public abstract interface class io/github/alexandrepiveteau/graphs/Graph : io/github/alexandrepiveteau/graphs/Successors, io/github/alexandrepiveteau/graphs/VertexSet { } public final class io/github/alexandrepiveteau/graphs/Graph$DefaultImpls { public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/Graph;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/Graph;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/Graph;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/Graph;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/Graph;I)I } @@ -102,7 +102,8 @@ public abstract interface class io/github/alexandrepiveteau/graphs/MutableDirect public final class io/github/alexandrepiveteau/graphs/MutableDirectedGraph$DefaultImpls { public static fun addVertices (Lio/github/alexandrepiveteau/graphs/MutableDirectedGraph;)Lio/github/alexandrepiveteau/graphs/Vertices; public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableDirectedGraph;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableDirectedGraph;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableDirectedGraph;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableDirectedGraph;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableDirectedGraph;I)I } @@ -121,11 +122,11 @@ public final class io/github/alexandrepiveteau/graphs/MutableDirectedNetwork$Def public static fun addArc--OaZVeM (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;J)V public static fun addVertices (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;)Lio/github/alexandrepiveteau/graphs/Vertices; public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;II)I + public static fun successorWeight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;II)I + public static fun successorWeight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;I)I - public static fun weight--OaZVeM (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;J)I - public static fun weight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;II)I - public static fun weight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableDirectedNetwork;II)I } public abstract interface class io/github/alexandrepiveteau/graphs/MutableDirectedNetworkScope : io/github/alexandrepiveteau/graphs/MutableDirectedGraphScope, io/github/alexandrepiveteau/graphs/MutableNetworkScope { @@ -145,7 +146,8 @@ public abstract interface class io/github/alexandrepiveteau/graphs/MutableGraph public final class io/github/alexandrepiveteau/graphs/MutableGraph$DefaultImpls { public static fun addVertices (Lio/github/alexandrepiveteau/graphs/MutableGraph;)Lio/github/alexandrepiveteau/graphs/Vertices; public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableGraph;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableGraph;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableGraph;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableGraph;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableGraph;I)I } @@ -164,10 +166,11 @@ public abstract interface class io/github/alexandrepiveteau/graphs/MutableNetwor public final class io/github/alexandrepiveteau/graphs/MutableNetwork$DefaultImpls { public static fun addVertices (Lio/github/alexandrepiveteau/graphs/MutableNetwork;)Lio/github/alexandrepiveteau/graphs/Vertices; public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableNetwork;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableNetwork;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableNetwork;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableNetwork;II)I + public static fun successorWeight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/MutableNetwork;II)I + public static fun successorWeight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableNetwork;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableNetwork;I)I - public static fun weight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/MutableNetwork;II)I - public static fun weight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableNetwork;II)I } public abstract interface class io/github/alexandrepiveteau/graphs/MutableNetworkScope : io/github/alexandrepiveteau/graphs/MutableGraphScope { @@ -183,7 +186,8 @@ public abstract interface class io/github/alexandrepiveteau/graphs/MutableUndire public final class io/github/alexandrepiveteau/graphs/MutableUndirectedGraph$DefaultImpls { public static fun addVertices (Lio/github/alexandrepiveteau/graphs/MutableUndirectedGraph;)Lio/github/alexandrepiveteau/graphs/Vertices; public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableUndirectedGraph;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableUndirectedGraph;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableUndirectedGraph;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableUndirectedGraph;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableUndirectedGraph;I)I } @@ -202,10 +206,11 @@ public final class io/github/alexandrepiveteau/graphs/MutableUndirectedNetwork$D public static fun addEdge-zEWoN30 (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;J)V public static fun addVertices (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;)Lio/github/alexandrepiveteau/graphs/Vertices; public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;II)I + public static fun successorWeight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;II)I + public static fun successorWeight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;I)I - public static fun weight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;II)I - public static fun weight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;II)I public static fun weight-zEWoN30 (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetwork;J)I } @@ -220,19 +225,16 @@ public final class io/github/alexandrepiveteau/graphs/MutableUndirectedNetworkSc public static fun addVertices (Lio/github/alexandrepiveteau/graphs/MutableUndirectedNetworkScope;)Lio/github/alexandrepiveteau/graphs/Vertices; } -public abstract interface class io/github/alexandrepiveteau/graphs/Network : io/github/alexandrepiveteau/graphs/Graph { - public abstract fun weight (II)I - public abstract fun weight-9scIZJg (II)I - public abstract fun weight-cK2_UGU (II)I - public abstract fun weight-iNgu2Tg (II)I +public abstract interface class io/github/alexandrepiveteau/graphs/Network : io/github/alexandrepiveteau/graphs/Graph, io/github/alexandrepiveteau/graphs/SuccessorsWeight { } public final class io/github/alexandrepiveteau/graphs/Network$DefaultImpls { public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/Network;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/Network;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/Network;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/Network;II)I + public static fun successorWeight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/Network;II)I + public static fun successorWeight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/Network;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/Network;I)I - public static fun weight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/Network;II)I - public static fun weight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/Network;II)I } public final class io/github/alexandrepiveteau/graphs/NoSuchArcException : java/util/NoSuchElementException { @@ -247,17 +249,66 @@ public final class io/github/alexandrepiveteau/graphs/NoSuchVertexException : ja public fun ()V } -public abstract interface class io/github/alexandrepiveteau/graphs/UndirectedGraph : io/github/alexandrepiveteau/graphs/Graph { - public static final field Companion Lio/github/alexandrepiveteau/graphs/UndirectedGraph$Companion; +public abstract interface class io/github/alexandrepiveteau/graphs/Predecessors : io/github/alexandrepiveteau/graphs/VertexSet { + public abstract fun predecessor-_QOBl-4 (II)I + public abstract fun predecessor-vAesux8 (II)I + public abstract fun predecessorsSize (I)I + public abstract fun predecessorsSize-dT2TSiQ (I)I +} + +public final class io/github/alexandrepiveteau/graphs/Predecessors$DefaultImpls { + public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/Predecessors;I)Z + public static fun predecessor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/Predecessors;II)I + public static fun predecessorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/Predecessors;I)I +} + +public abstract interface class io/github/alexandrepiveteau/graphs/Successors : io/github/alexandrepiveteau/graphs/VertexSet { + public abstract fun successorIndex (II)I + public abstract fun successorIndex-iNgu2Tg (II)I + public abstract fun successorVertex-_QOBl-4 (II)I + public abstract fun successorVertex-vAesux8 (II)I + public abstract fun successorsSize (I)I + public abstract fun successorsSize-dT2TSiQ (I)I +} + +public final class io/github/alexandrepiveteau/graphs/Successors$DefaultImpls { + public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/Successors;I)Z + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/Successors;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/Successors;II)I + public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/Successors;I)I +} + +public abstract interface class io/github/alexandrepiveteau/graphs/SuccessorsWeight : io/github/alexandrepiveteau/graphs/Successors { + public abstract fun successorWeight (II)I + public abstract fun successorWeight-9scIZJg (II)I + public abstract fun successorWeight-cK2_UGU (II)I + public abstract fun successorWeight-iNgu2Tg (II)I +} + +public final class io/github/alexandrepiveteau/graphs/SuccessorsWeight$DefaultImpls { + public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;I)Z + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;II)I + public static fun successorWeight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;II)I + public static fun successorWeight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;II)I + public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;I)I +} + +public abstract interface class io/github/alexandrepiveteau/graphs/Undirected { public abstract fun contains-zEWoN30 (J)Z } +public abstract interface class io/github/alexandrepiveteau/graphs/UndirectedGraph : io/github/alexandrepiveteau/graphs/Graph, io/github/alexandrepiveteau/graphs/Undirected { + public static final field Companion Lio/github/alexandrepiveteau/graphs/UndirectedGraph$Companion; +} + public final class io/github/alexandrepiveteau/graphs/UndirectedGraph$Companion { } public final class io/github/alexandrepiveteau/graphs/UndirectedGraph$DefaultImpls { public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/UndirectedGraph;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/UndirectedGraph;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/UndirectedGraph;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/UndirectedGraph;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/UndirectedGraph;I)I } @@ -282,10 +333,11 @@ public final class io/github/alexandrepiveteau/graphs/UndirectedNetwork$Companio public final class io/github/alexandrepiveteau/graphs/UndirectedNetwork$DefaultImpls { public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;I)Z - public static fun successor-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;II)I + public static fun successorIndex-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;II)I + public static fun successorVertex-_QOBl-4 (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;II)I + public static fun successorWeight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;II)I + public static fun successorWeight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;II)I public static fun successorsSize-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;I)I - public static fun weight-cK2_UGU (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;II)I - public static fun weight-iNgu2Tg (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;II)I public static fun weight-zEWoN30 (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;J)I } @@ -372,6 +424,17 @@ public final class io/github/alexandrepiveteau/graphs/VertexMapKt { public static final fun forEach-TXWKjJg ([ILkotlin/jvm/functions/Function2;)V } +public abstract interface class io/github/alexandrepiveteau/graphs/VertexSet { + public abstract fun contains-dT2TSiQ (I)Z + public abstract fun getSize ()I + public abstract fun index-dT2TSiQ (I)I + public abstract fun vertex-1Pv3iCI (I)I +} + +public final class io/github/alexandrepiveteau/graphs/VertexSet$DefaultImpls { + public static fun contains-dT2TSiQ (Lio/github/alexandrepiveteau/graphs/VertexSet;I)Z +} + public abstract interface class io/github/alexandrepiveteau/graphs/Vertices { public abstract fun component1-IrpSQec ()I public abstract fun component2-IrpSQec ()I @@ -398,33 +461,40 @@ public final class io/github/alexandrepiveteau/graphs/Vertices$DefaultImpls { } public final class io/github/alexandrepiveteau/graphs/algorithms/Algorithms { - public static final fun connectedComponents (Lio/github/alexandrepiveteau/graphs/UndirectedGraph;)Lkotlin/Pair; - public static final fun maxFlowEdmondsKarp-SPb1_vQ (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;II)Lio/github/alexandrepiveteau/graphs/DirectedNetwork; - public static final fun minimumSpanningForest (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;)Lio/github/alexandrepiveteau/graphs/UndirectedNetwork; - public static final fun shortestPathDijkstra-9scIZJg (Lio/github/alexandrepiveteau/graphs/Network;I)Lio/github/alexandrepiveteau/graphs/DirectedNetwork; - public static final fun shortestPathDijkstra-SPb1_vQ (Lio/github/alexandrepiveteau/graphs/Network;II)[I - public static final fun shortestPathFasterAlgorithm-9scIZJg (Lio/github/alexandrepiveteau/graphs/Network;I)Lio/github/alexandrepiveteau/graphs/DirectedNetwork; - public static final fun shortestPathFasterAlgorithm-SPb1_vQ (Lio/github/alexandrepiveteau/graphs/Network;II)[I - public static final fun stronglyConnectedComponentsKosaraju (Lio/github/alexandrepiveteau/graphs/DirectedGraph;)Lkotlin/Pair; - public static final fun topologicalSort (Lio/github/alexandrepiveteau/graphs/DirectedGraph;)[I + public static final fun connectedComponents (Lio/github/alexandrepiveteau/graphs/Undirected;)Lkotlin/Pair; + public static final fun maxFlowEdmondsKarp-SPb1_vQ (Lio/github/alexandrepiveteau/graphs/Directed;II)Lio/github/alexandrepiveteau/graphs/DirectedNetwork; + public static final fun minimumSpanningForest (Lio/github/alexandrepiveteau/graphs/Undirected;)Lio/github/alexandrepiveteau/graphs/UndirectedNetwork; + public static final fun shortestPathDijkstra-9scIZJg (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;I)Lio/github/alexandrepiveteau/graphs/DirectedNetwork; + public static final fun shortestPathDijkstra-SPb1_vQ (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;II)[I + public static final fun shortestPathFasterAlgorithm-9scIZJg (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;I)Lio/github/alexandrepiveteau/graphs/DirectedNetwork; + public static final fun shortestPathFasterAlgorithm-SPb1_vQ (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;II)[I + public static final fun stronglyConnectedComponentsKosaraju (Lio/github/alexandrepiveteau/graphs/Directed;)Lkotlin/Pair; + public static final fun topologicalSort (Lio/github/alexandrepiveteau/graphs/Directed;)[I +} + +public final class io/github/alexandrepiveteau/graphs/algorithms/RandomWalkKt { + public static final fun randomWalk-YQfbarM (Lio/github/alexandrepiveteau/graphs/Successors;ILkotlin/random/Random;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun randomWalk-YQfbarM$default (Lio/github/alexandrepiveteau/graphs/Successors;ILkotlin/random/Random;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public static final fun randomWalkWeighted-YQfbarM (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;ILkotlin/random/Random;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun randomWalkWeighted-YQfbarM$default (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;ILkotlin/random/Random;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V } public final class io/github/alexandrepiveteau/graphs/algorithms/Traversals { - public static final fun forEachArc (Lio/github/alexandrepiveteau/graphs/DirectedGraph;Lkotlin/jvm/functions/Function1;)V - public static final fun forEachArc (Lio/github/alexandrepiveteau/graphs/DirectedNetwork;Lkotlin/jvm/functions/Function2;)V - public static final fun forEachEdge (Lio/github/alexandrepiveteau/graphs/UndirectedGraph;Lkotlin/jvm/functions/Function1;)V - public static final fun forEachEdge (Lio/github/alexandrepiveteau/graphs/UndirectedNetwork;Lkotlin/jvm/functions/Function2;)V - public static final fun forEachNeighbor-zrzjTAw (Lio/github/alexandrepiveteau/graphs/Graph;ILkotlin/jvm/functions/Function1;)V - public static final fun forEachNeighbor-zrzjTAw (Lio/github/alexandrepiveteau/graphs/Network;ILkotlin/jvm/functions/Function2;)V - public static final fun forEachVertex (Lio/github/alexandrepiveteau/graphs/Graph;Lkotlin/jvm/functions/Function1;)V - public static final fun forEachVertexBreadthFirst-zrzjTAw (Lio/github/alexandrepiveteau/graphs/Graph;ILkotlin/jvm/functions/Function1;)V - public static final fun forEachVertexDepthFirst-YQfbarM (Lio/github/alexandrepiveteau/graphs/Graph;I[ZLkotlin/jvm/functions/Function1;)V - public static synthetic fun forEachVertexDepthFirst-YQfbarM$default (Lio/github/alexandrepiveteau/graphs/Graph;I[ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V - public static final fun forEachVertexDepthFirstHelper-wZYKThQ (Lio/github/alexandrepiveteau/graphs/Graph;I[ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V - public static synthetic fun forEachVertexDepthFirstHelper-wZYKThQ$default (Lio/github/alexandrepiveteau/graphs/Graph;I[ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V - public static final fun forEachVertexDepthFirstPostOrder-YQfbarM (Lio/github/alexandrepiveteau/graphs/Graph;I[ZLkotlin/jvm/functions/Function1;)V - public static synthetic fun forEachVertexDepthFirstPostOrder-YQfbarM$default (Lio/github/alexandrepiveteau/graphs/Graph;I[ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V - public static final fun shortestPathBreadthFirst-SPb1_vQ (Lio/github/alexandrepiveteau/graphs/Graph;II)[I + public static final fun forEachArc (Lio/github/alexandrepiveteau/graphs/Directed;Lkotlin/jvm/functions/Function1;)V + public static final fun forEachArc (Lio/github/alexandrepiveteau/graphs/Directed;Lkotlin/jvm/functions/Function2;)V + public static final fun forEachEdge (Lio/github/alexandrepiveteau/graphs/Undirected;Lkotlin/jvm/functions/Function1;)V + public static final fun forEachEdge (Lio/github/alexandrepiveteau/graphs/Undirected;Lkotlin/jvm/functions/Function2;)V + public static final fun forEachSuccessor-zrzjTAw (Lio/github/alexandrepiveteau/graphs/Successors;ILkotlin/jvm/functions/Function1;)V + public static final fun forEachSuccessor-zrzjTAw (Lio/github/alexandrepiveteau/graphs/SuccessorsWeight;ILkotlin/jvm/functions/Function2;)V + public static final fun forEachVertex (Lio/github/alexandrepiveteau/graphs/VertexSet;Lkotlin/jvm/functions/Function1;)V + public static final fun forEachVertexBreadthFirst-zrzjTAw (Lio/github/alexandrepiveteau/graphs/Successors;ILkotlin/jvm/functions/Function1;)V + public static final fun forEachVertexDepthFirst-YQfbarM (Lio/github/alexandrepiveteau/graphs/Successors;I[ZLkotlin/jvm/functions/Function1;)V + public static synthetic fun forEachVertexDepthFirst-YQfbarM$default (Lio/github/alexandrepiveteau/graphs/Successors;I[ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public static final fun forEachVertexDepthFirstHelper-wZYKThQ (Lio/github/alexandrepiveteau/graphs/Successors;I[ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun forEachVertexDepthFirstHelper-wZYKThQ$default (Lio/github/alexandrepiveteau/graphs/Successors;I[ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public static final fun forEachVertexDepthFirstPostOrder-YQfbarM (Lio/github/alexandrepiveteau/graphs/Successors;I[ZLkotlin/jvm/functions/Function1;)V + public static synthetic fun forEachVertexDepthFirstPostOrder-YQfbarM$default (Lio/github/alexandrepiveteau/graphs/Successors;I[ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public static final fun shortestPathBreadthFirst-SPb1_vQ (Lio/github/alexandrepiveteau/graphs/Successors;II)[I } public abstract interface class io/github/alexandrepiveteau/graphs/builder/DirectedGraphBuilder : io/github/alexandrepiveteau/graphs/MutableDirectedGraphScope, io/github/alexandrepiveteau/graphs/builder/GraphBuilder { @@ -502,11 +572,13 @@ public final class io/github/alexandrepiveteau/graphs/internal/collections/IntDe public final class io/github/alexandrepiveteau/graphs/internal/collections/IntVector { public fun ()V + public final fun clear ()V public final fun get (I)I public final fun getSize ()I public final fun plusAssign (I)V public final fun removeLast ()V public final fun set (II)V + public final fun sum ()I public final fun toIntArray ()[I } diff --git a/build.gradle.kts b/build.gradle.kts index f14c616..1f42567 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,9 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { - kotlin("multiplatform") version "1.8.20" - id("org.jetbrains.kotlinx.binary-compatibility-validator") version "0.13.0" - id("org.jetbrains.dokka") version "1.8.10" + kotlin("multiplatform") version "1.9.21" + id("org.jetbrains.kotlinx.binary-compatibility-validator") version "0.13.2" + id("org.jetbrains.dokka") version "1.9.10" id("com.vanniktech.maven.publish") version "0.25.2" } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Directed.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Directed.kt new file mode 100644 index 0000000..c50da2c --- /dev/null +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Directed.kt @@ -0,0 +1,8 @@ +package io.github.alexandrepiveteau.graphs + +/** A marker interface for [Graph]s that are directed. */ +public interface Directed { + + /** Returns true if the given [arc] is contained in this [Directed] graph, and false otherwise. */ + public operator fun contains(arc: Arc): Boolean +} diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/DirectedGraph.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/DirectedGraph.kt index 0a29e6c..6e55197 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/DirectedGraph.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/DirectedGraph.kt @@ -6,10 +6,7 @@ import io.github.alexandrepiveteau.graphs.builder.buildDirectedGraph import io.github.alexandrepiveteau.graphs.builder.buildUndirectedGraph /** A [DirectedGraph] is a [Graph] where [Vertex]s are linked using [Arc]s. */ -public interface DirectedGraph : Graph { - - /** Returns true if the given [arc] is contained in this [DirectedGraph], and false otherwise. */ - public operator fun contains(arc: Arc): Boolean +public interface DirectedGraph : Graph, Directed { /** * An object which serves as the companion of [DirectedGraph], and which provides a number of @@ -22,13 +19,15 @@ public interface DirectedGraph : Graph { * Transforms the [DirectedGraph] into an [UndirectedGraph], by adding an edge between each pair of * vertices that are connected by an arc. */ -public fun DirectedGraph.toUndirectedGraph(): UndirectedGraph = buildUndirectedGraph { - forEachVertex { addVertex() } - forEachArc { (u, v) -> addEdge(u edgeTo v) } -} +public fun G.toUndirectedGraph(): UndirectedGraph where G : Directed, G : Successors = + buildUndirectedGraph { + forEachVertex { addVertex() } + forEachArc { (u, v) -> addEdge(u edgeTo v) } + } /** Returns the transposed [DirectedGraph], where the direction of arcs has been reversed. */ -public fun DirectedGraph.transposed(): DirectedGraph = buildDirectedGraph { - forEachVertex { addVertex() } - forEachArc { addArc(it.reversed()) } -} +public fun G.transposed(): DirectedGraph where G : Directed, G : Successors = + buildDirectedGraph { + forEachVertex { addVertex() } + forEachArc { addArc(it.reversed()) } + } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/DirectedNetwork.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/DirectedNetwork.kt index 8d8ed52..9e1f0f3 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/DirectedNetwork.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/DirectedNetwork.kt @@ -3,17 +3,19 @@ package io.github.alexandrepiveteau.graphs /** A [DirectedNetwork] is a [Network] and a [DirectedGraph]. */ public interface DirectedNetwork : Network, DirectedGraph { - /** - * Returns the weight of the [Arc]. - * - * @throws NoSuchVertexException if [arc] is not a valid arc for this [UndirectedNetwork]. - * @throws NoSuchEdgeException if there is no arc between the two vertices. - */ - public fun weight(arc: Arc): Int = weight(arc.from, arc.to) - /** * An object which serves as the companion of the [DirectedNetwork], and which provides a number * of methods to create [DirectedNetwork]s. */ public companion object } + +/** + * Returns the weight of the [Arc]. + * + * @throws NoSuchVertexException if [arc] is not a valid arc for this [UndirectedNetwork]. + * @throws NoSuchEdgeException if there is no arc between the two vertices. + */ +public fun N.successorWeight( + arc: Arc, +): Int where N : Directed, N : SuccessorsWeight = successorWeight(arc.from, arc.to) diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Graph.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Graph.kt index dd1f1d9..8198c7e 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Graph.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Graph.kt @@ -8,53 +8,4 @@ package io.github.alexandrepiveteau.graphs * links by their index. This is useful for algorithms which need to iterate over the vertices and * links of the graph without having to create an explicit iterator. */ -public interface Graph { - - /** The number of vertices in this [Graph]. */ - public val size: Int - - /** Returns true if the given [vertex] is contained in this [Graph], and false otherwise. */ - public operator fun contains(vertex: Vertex): Boolean = index(vertex) in 0 until size - - /** - * Returns the index of the given [vertex] in this [Graph]. If the vertex is not contained in this - * [Graph], a [NoSuchVertexException] is thrown. - */ - public fun index(vertex: Vertex): Int - - /** - * Returns the [Vertex] at the given [index] in this [Graph]. If the index is not contained in - * this [Graph], an [IndexOutOfBoundsException] is thrown. - */ - public fun vertex(index: Int): Vertex - - /** - * Returns the number of edges leaving the [Vertex] at the given index in this [Graph]. If the - * vertex is not contained in this [Graph], an [IndexOutOfBoundsException] is thrown. - */ - public fun successorsSize(index: Int): Int - - /** - * Returns the number of edges leaving the given [vertex] in this [Graph]. If the vertex is not - * contained in this [Graph], a [NoSuchVertexException] is thrown. - */ - public fun successorsSize(vertex: Vertex): Int = successorsSize(index(vertex)) - - /** - * Returns the [Vertex] at the given [neighborIndex] index in the list of neighbors of the - * [Vertex] at the given [index] in this [Graph]. If the vertex is not contained in this [Graph], - * an [IndexOutOfBoundsException] is thrown. - */ - public fun successor(index: Int, neighborIndex: Int): Vertex - - /** - * Returns the [Vertex] at the given [neighborIndex] index in the list of neighbors of the given - * [vertex] in this [Graph]. If the vertex is not contained in this [Graph], a - * [NoSuchVertexException], and if the neighbor index is not contained in the list of neighbors of - * the vertex, an [IndexOutOfBoundsException] is thrown. - */ - public fun successor( - vertex: Vertex, - neighborIndex: Int, - ): Vertex = successor(index(vertex), neighborIndex) -} +public interface Graph : VertexSet, Successors diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Network.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Network.kt index ed59fb6..c5cc12f 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Network.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Network.kt @@ -4,37 +4,4 @@ package io.github.alexandrepiveteau.graphs * A [Network] is a [Graph] with some weights associated to each link. The weights are represented * as [Int] values. */ -public interface Network : Graph { - - /** - * Returns the weight of the edge between the [Vertex] at [index] and the [Vertex] at - * [neighborIndex]. - * - * @throws IndexOutOfBoundsException if [index] or [neighborIndex] are not valid indices. - */ - public fun weight(index: Int, neighborIndex: Int): Int - - /** - * Returns the weight of the edge between the [Vertex] at [index] and its [neighbor]. - * - * @throws IndexOutOfBoundsException if [index] is not a valid index. - * @throws NoSuchVertexException if [neighbor] is not a valid vertex. - */ - public fun weight(index: Int, neighbor: Vertex): Int - - /** - * Returns the weight of the edge between the [vertex] and its [neighbor]. - * - * @throws NoSuchVertexException if [vertex] or [neighbor] are not valid vertices. - * @throws NoSuchEdgeException if there is no edge between [vertex] and [neighbor]. - */ - public fun weight(vertex: Vertex, neighbor: Vertex): Int = weight(index(vertex), neighbor) - - /** - * Returns the weight of the edge between the [vertex] and the [Vertex] at [neighborIndex]. - * - * @throws NoSuchVertexException if [vertex] is not a valid vertex. - * @throws IndexOutOfBoundsException if [neighborIndex] is not a valid index. - */ - public fun weight(vertex: Vertex, neighborIndex: Int): Int = weight(index(vertex), neighborIndex) -} +public interface Network : Graph, SuccessorsWeight diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Predecessors.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Predecessors.kt new file mode 100644 index 0000000..082c0fc --- /dev/null +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Predecessors.kt @@ -0,0 +1,38 @@ +package io.github.alexandrepiveteau.graphs + +/** + * [Predecessors] are a [VertexSet] where each [Vertex] has a list of neighbors, which can be + * accessed by their index. + */ +public interface Predecessors : VertexSet { + + /** + * Returns the number of edges entering the [Vertex] at the given index in this [Predecessors]. If + * the vertex is not contained in this [Predecessors], an [IndexOutOfBoundsException] is thrown. + */ + public fun predecessorsSize(index: Int): Int + + /** + * Returns the number of edges entering the given [vertex] in this [Predecessors]. If the vertex + * is not contained in this [Predecessors], a [NoSuchVertexException] is thrown. + */ + public fun predecessorsSize(vertex: Vertex): Int = predecessorsSize(index(vertex)) + + /** + * Returns the [Vertex] at the given [neighborIndex] index in the list of neighbors of the + * [Vertex] at the given [index] in this [Predecessors]. If the vertex is not contained in this + * [Predecessors], an [IndexOutOfBoundsException] is thrown. + */ + public fun predecessor(index: Int, neighborIndex: Int): Vertex + + /** + * Returns the [Vertex] at the given [neighborIndex] index in the list of neighbors of the given + * [vertex] in this [Predecessors]. If the vertex is not contained in this [Predecessors], a + * [NoSuchVertexException], and if the neighbor index is not contained in the list of neighbors of + * the vertex, an [IndexOutOfBoundsException] is thrown. + */ + public fun predecessor( + vertex: Vertex, + neighborIndex: Int, + ): Vertex = predecessor(index(vertex), neighborIndex) +} diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Successors.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Successors.kt new file mode 100644 index 0000000..8bdaec1 --- /dev/null +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Successors.kt @@ -0,0 +1,56 @@ +package io.github.alexandrepiveteau.graphs + +/** + * [Successors] are a [VertexSet] where each [Vertex] has a list of neighbors, which can be accessed + * by their index. + */ +public interface Successors : VertexSet { + + /** + * Returns the number of edges leaving the [Vertex] at the given index in this [Successors]. If + * the vertex is not contained in this [Successors], an [IndexOutOfBoundsException] is thrown. + */ + public fun successorsSize(index: Int): Int + + /** + * Returns the number of edges leaving the given [vertex] in this [Successors]. If the vertex is + * not contained in this [Successors], a [NoSuchVertexException] is thrown. + */ + public fun successorsSize(vertex: Vertex): Int = successorsSize(index(vertex)) + + /** + * Returns the index of the vertex at the given [neighborIndex] index in the list of neighbors of + * the [Vertex] in this [Successors]. If the vertex is not contained in this [Successors], an + * [IndexOutOfBoundsException] is thrown. + */ + public fun successorIndex(index: Int, neighborIndex: Int): Int + + /** + * Returns the index of the vertex at the given [neighborIndex] index in the list of neighbors of + * the [Vertex] in this [Successors]. If the vertex is not contained in this [Successors], a + * [NoSuchVertexException], and if the neighbor index is not contained in the list of neighbors of + * the vertex, an [IndexOutOfBoundsException] is thrown. + */ + public fun successorIndex( + vertex: Vertex, + neighborIndex: Int, + ): Int = successorIndex(index(vertex), neighborIndex) + + /** + * Returns the [Vertex] at the given [neighborIndex] index in the list of neighbors of the + * [Vertex] at the given [index] in this [Successors]. If the vertex is not contained in this + * [Successors], an [IndexOutOfBoundsException] is thrown. + */ + public fun successorVertex(index: Int, neighborIndex: Int): Vertex + + /** + * Returns the [Vertex] at the given [neighborIndex] index in the list of neighbors of the given + * [vertex] in this [Successors]. If the vertex is not contained in this [Successors], a + * [NoSuchVertexException], and if the neighbor index is not contained in the list of neighbors of + * the vertex, an [IndexOutOfBoundsException] is thrown. + */ + public fun successorVertex( + vertex: Vertex, + neighborIndex: Int, + ): Vertex = successorVertex(index(vertex), neighborIndex) +} diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/SuccessorsWeight.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/SuccessorsWeight.kt new file mode 100644 index 0000000..07ef077 --- /dev/null +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/SuccessorsWeight.kt @@ -0,0 +1,42 @@ +package io.github.alexandrepiveteau.graphs + +/** + * [SuccessorsWeight] are a [Successors] where each link has a weight, which can be accessed by + * their index. + */ +public interface SuccessorsWeight : Successors { + + /** + * Returns the weight of the edge between the [Vertex] at [index] and the [Vertex] at + * [neighborIndex]. + * + * @throws IndexOutOfBoundsException if [index] or [neighborIndex] are not valid indices. + */ + public fun successorWeight(index: Int, neighborIndex: Int): Int + + /** + * Returns the weight of the edge between the [Vertex] at [index] and its [neighbor]. + * + * @throws IndexOutOfBoundsException if [index] is not a valid index. + * @throws NoSuchVertexException if [neighbor] is not a valid vertex. + */ + public fun successorWeight(index: Int, neighbor: Vertex): Int + + /** + * Returns the weight of the edge between the [vertex] and its [neighbor]. + * + * @throws NoSuchVertexException if [vertex] or [neighbor] are not valid vertices. + * @throws NoSuchEdgeException if there is no edge between [vertex] and [neighbor]. + */ + public fun successorWeight(vertex: Vertex, neighbor: Vertex): Int = + successorWeight(index(vertex), neighbor) + + /** + * Returns the weight of the edge between the [vertex] and the [Vertex] at [neighborIndex]. + * + * @throws NoSuchVertexException if [vertex] is not a valid vertex. + * @throws IndexOutOfBoundsException if [neighborIndex] is not a valid index. + */ + public fun successorWeight(vertex: Vertex, neighborIndex: Int): Int = + successorWeight(index(vertex), neighborIndex) +} diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Undirected.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Undirected.kt new file mode 100644 index 0000000..b67f43a --- /dev/null +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/Undirected.kt @@ -0,0 +1,8 @@ +package io.github.alexandrepiveteau.graphs + +/** A marker interface for [Graph]s that are undirected. */ +public interface Undirected { + + /** Returns true if the given [edge] is contained in this [Undirected] graph, and false otherwise. */ + public operator fun contains(edge: Edge): Boolean +} diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.complete.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.complete.kt index b7e1cd3..82bf5fe 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.complete.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.complete.kt @@ -2,13 +2,22 @@ package io.github.alexandrepiveteau.graphs /** An implementation of [UndirectedGraph] which is empty. */ private object EmptyUndirectedGraph : UndirectedGraph { + override val size = 0 + override fun contains(vertex: Vertex) = false + override fun contains(edge: Edge) = false + override fun index(vertex: Vertex) = throw NoSuchVertexException() + override fun vertex(index: Int) = throw IndexOutOfBoundsException() + override fun successorsSize(index: Int) = throw IndexOutOfBoundsException() - override fun successor(index: Int, neighborIndex: Int) = throw IndexOutOfBoundsException() + + override fun successorIndex(index: Int, neighborIndex: Int) = throw IndexOutOfBoundsException() + + override fun successorVertex(index: Int, neighborIndex: Int) = throw IndexOutOfBoundsException() } /** Returns an empty [UndirectedGraph], which is a graph with no vertices and no edges. */ @@ -16,8 +25,10 @@ public fun UndirectedGraph.Companion.empty(): UndirectedGraph = EmptyUndirectedG /** An implementation of [UndirectedNetwork] which is empty. */ private object EmptyUndirectedNetwork : UndirectedNetwork, UndirectedGraph by EmptyUndirectedGraph { - override fun weight(index: Int, neighborIndex: Int) = throw IndexOutOfBoundsException() - override fun weight(index: Int, neighbor: Vertex) = throw IndexOutOfBoundsException() + + override fun successorWeight(index: Int, neighborIndex: Int) = throw IndexOutOfBoundsException() + + override fun successorWeight(index: Int, neighbor: Vertex) = throw IndexOutOfBoundsException() } /** Returns an empty [UndirectedNetwork], which is a network with no vertices and no edges. */ @@ -25,28 +36,37 @@ public fun UndirectedNetwork.Companion.empty(): UndirectedNetwork = EmptyUndirec /** An implementation of a [UndirectedGraph] which is complete. */ private open class CompleteUndirectedGraph(override val size: Int) : UndirectedGraph { + override fun contains(edge: Edge): Boolean { val (u, v) = edge return u != v && u in this && v in this } + override fun index(vertex: Vertex): Int { if (vertex.index < 0 || vertex.index >= size) throw NoSuchVertexException() return vertex.index } + override fun vertex(index: Int): Vertex { if (index < 0 || index >= size) throw IndexOutOfBoundsException() return Vertex(index) } + override fun successorsSize(index: Int): Int { if (index < 0 || index >= size) throw IndexOutOfBoundsException() return size - 1 } - override fun successor(index: Int, neighborIndex: Int): Vertex { + + override fun successorIndex(index: Int, neighborIndex: Int): Int { if (index < 0 || index >= size) throw IndexOutOfBoundsException() if (neighborIndex < 0 || neighborIndex >= size - 1) throw IndexOutOfBoundsException() var vertex = neighborIndex if (vertex >= index) vertex++ - return Vertex(vertex) + return vertex + } + + override fun successorVertex(index: Int, neighborIndex: Int): Vertex { + return vertex(successorIndex(index, neighborIndex)) } } @@ -68,13 +88,13 @@ public fun UndirectedGraph.Companion.complete(size: Int): UndirectedGraph { private class CompleteUndirectedNetwork(size: Int, private val weight: Int) : CompleteUndirectedGraph(size), UndirectedNetwork { - override fun weight(index: Int, neighborIndex: Int): Int { + override fun successorWeight(index: Int, neighborIndex: Int): Int { if (index < 0 || index >= size) throw IndexOutOfBoundsException() if (neighborIndex < 0 || neighborIndex >= size - 1) throw IndexOutOfBoundsException() return weight } - override fun weight(index: Int, neighbor: Vertex): Int { + override fun successorWeight(index: Int, neighbor: Vertex): Int { if (index < 0 || index >= size) throw IndexOutOfBoundsException() if (neighbor.index < 0 || neighbor.index >= size) throw NoSuchVertexException() if (index == neighbor.index) throw NoSuchEdgeException() diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.kt index 36a890c..e6ed6f5 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.kt @@ -5,12 +5,7 @@ import io.github.alexandrepiveteau.graphs.algorithms.forEachVertex import io.github.alexandrepiveteau.graphs.builder.buildDirectedGraph /** A [UndirectedGraph] is a [Graph] where [Vertex]s are linked using [Edge]s. */ -public interface UndirectedGraph : Graph { - - /** - * Returns true if the given [edge] is contained in this [UndirectedGraph], and false otherwise. - */ - public operator fun contains(edge: Edge): Boolean +public interface UndirectedGraph : Graph, Undirected { /** * An object which serves as the companion of [UndirectedGraph], and which provides a number of diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedNetwork.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedNetwork.kt index b754b65..d57d766 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedNetwork.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/UndirectedNetwork.kt @@ -9,7 +9,7 @@ public interface UndirectedNetwork : Network, UndirectedGraph { * @throws NoSuchVertexException if [edge] is not a valid edge for this [UndirectedNetwork]. * @throws NoSuchEdgeException if there is no edge between the two vertices. */ - public fun weight(edge: Edge): Int = weight(edge.component1(), edge.component2()) + public fun weight(edge: Edge): Int = successorWeight(edge.component1(), edge.component2()) /** * An object which serves as the companion of the [UndirectedNetwork], and which provides a number diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/VertexMap.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/VertexMap.kt index 3bf26e5..1cfef3e 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/VertexMap.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/VertexMap.kt @@ -15,7 +15,7 @@ public inline fun VertexMap( init: (index: Vertex) -> Vertex, ): VertexMap { return VertexMap(size).apply { - for (index in 0 until size) { + for (index in 0 ..< size) { this[Vertex(index)] = init(Vertex(index)) } } @@ -77,7 +77,7 @@ public value class VertexMap private constructor(private val array: VertexArray) * @receiver the [VertexMap] to iterate over. */ public inline fun VertexMap.forEach(action: (Vertex, Vertex) -> Unit) { - for (index in 0 until size) { + for (index in 0 ..< size) { val v = Vertex(index) action(v, this[v]) } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/VertexSet.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/VertexSet.kt new file mode 100644 index 0000000..e2da819 --- /dev/null +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/VertexSet.kt @@ -0,0 +1,23 @@ +package io.github.alexandrepiveteau.graphs + +/** A set of vertices. Vertices can be iterated over, and their [size] can be queried. */ +public interface VertexSet { + + /** The number of vertices in this [VertexSet]. */ + public val size: Int + + /** Returns true if the given [vertex] is contained in this [VertexSet], and false otherwise. */ + public operator fun contains(vertex: Vertex): Boolean = index(vertex) in 0 ..< size + + /** + * Returns the index of the given [vertex] in this [VertexSet]. If the vertex is not contained in + * this [VertexSet], a [NoSuchVertexException] is thrown. + */ + public fun index(vertex: Vertex): Int + + /** + * Returns the [Vertex] at the given [index] in this [VertexSet]. If the index is not contained in + * this [VertexSet], an [IndexOutOfBoundsException] is thrown. + */ + public fun vertex(index: Int): Vertex +} diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/BasicTraversal.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/BasicTraversal.kt index abd594e..3cdd10e 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/BasicTraversal.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/BasicTraversal.kt @@ -15,9 +15,11 @@ import kotlin.jvm.JvmName * - **Time complexity**: O(|N|), where |N| is the number of vertices in this graph. * - **Space complexity**: O(1). */ -public inline fun Graph.forEachVertex(action: (Vertex) -> Unit) { +public inline fun G.forEachVertex( + action: (Vertex) -> Unit, +) where G : VertexSet { contract { callsInPlace(action) } - for (i in 0 until size) action(vertex(i)) + for (i in 0 ..< size) action(vertex(i)) } /** @@ -27,10 +29,13 @@ public inline fun Graph.forEachVertex(action: (Vertex) -> Unit) { * - **Time complexity**: O(|N|), where |N| is the number of neighbors of the given [vertex]. * - **Space complexity**: O(1). */ -public inline fun Graph.forEachNeighbor(vertex: Vertex, action: (Vertex) -> Unit) { +public inline fun G.forEachSuccessor( + vertex: Vertex, + action: (Vertex) -> Unit, +) where G : Successors { contract { callsInPlace(action) } val index = index(vertex) - for (i in 0 until successorsSize(index)) action(successor(vertex, i)) + for (i in 0 ..< successorsSize(index)) action(successorVertex(vertex, i)) } /** @@ -40,10 +45,13 @@ public inline fun Graph.forEachNeighbor(vertex: Vertex, action: (Vertex) -> Unit * - **Time complexity**: O(|N|), where |N| is the number of neighbors of the given [vertex]. * - **Space complexity**: O(1). */ -public inline fun Network.forEachNeighbor(vertex: Vertex, action: (Vertex, Int) -> Unit) { +public inline fun N.forEachSuccessor( + vertex: Vertex, + action: (Vertex, Int) -> Unit, +) where N : SuccessorsWeight { contract { callsInPlace(action) } val index = index(vertex) - for (i in 0 until successorsSize(index)) action(successor(vertex, i), weight(vertex, i)) + for (i in 0 ..< successorsSize(index)) action(successorVertex(vertex, i), successorWeight(vertex, i)) } /** @@ -53,9 +61,11 @@ public inline fun Network.forEachNeighbor(vertex: Vertex, action: (Vertex, Int) * - **Time complexity**: O(|A|), where |A| is the number of arcs in this graph. * - **Space complexity**: O(1). */ -public inline fun DirectedGraph.forEachArc(action: (Arc) -> Unit) { +public inline fun G.forEachArc( + action: (Arc) -> Unit, +) where G : Directed, G : Successors { contract { callsInPlace(action) } - forEachVertex { u -> forEachNeighbor(u) { v -> action(u arcTo v) } } + forEachVertex { u -> forEachSuccessor(u) { v -> action(u arcTo v) } } } /** @@ -65,9 +75,11 @@ public inline fun DirectedGraph.forEachArc(action: (Arc) -> Unit) { * - **Time complexity**: O(|A|), where |A| is the number of arcs in this graph. * - **Space complexity**: O(1). */ -public inline fun DirectedNetwork.forEachArc(action: (Arc, Int) -> Unit) { +public inline fun N.forEachArc( + action: (Arc, Int) -> Unit, +) where N : Directed, N : SuccessorsWeight { contract { callsInPlace(action) } - forEachVertex { u -> forEachNeighbor(u) { v, w -> action(u arcTo v, w) } } + forEachVertex { u -> forEachSuccessor(u) { v, w -> action(u arcTo v, w) } } } /** @@ -77,9 +89,11 @@ public inline fun DirectedNetwork.forEachArc(action: (Arc, Int) -> Unit) { * - **Time complexity**: O(|E|), where |E| is the number of edges in this graph. * - **Space complexity**: O(1). */ -public inline fun UndirectedGraph.forEachEdge(action: (Edge) -> Unit) { +public inline fun G.forEachEdge( + action: (Edge) -> Unit, +) where G : Undirected, G : Successors { contract { callsInPlace(action) } - forEachVertex { u -> forEachNeighbor(u) { v -> if (index(u) <= index(v)) action(u edgeTo v) } } + forEachVertex { u -> forEachSuccessor(u) { v -> if (index(u) <= index(v)) action(u edgeTo v) } } } /** @@ -89,9 +103,11 @@ public inline fun UndirectedGraph.forEachEdge(action: (Edge) -> Unit) { * - **Time complexity**: O(|E|), where |E| is the number of edges in this graph. * - **Space complexity**: O(1). */ -public inline fun UndirectedNetwork.forEachEdge(action: (Edge, Int) -> Unit) { +public inline fun N.forEachEdge( + action: (Edge, Int) -> Unit, +) where N : Undirected, N : SuccessorsWeight { contract { callsInPlace(action) } forEachVertex { u -> - forEachNeighbor(u) { v, w -> if (index(u) <= index(v)) action(u edgeTo v, w) } + forEachSuccessor(u) { v, w -> if (index(u) <= index(v)) action(u edgeTo v, w) } } } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/BreadthFirstTraversal.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/BreadthFirstTraversal.kt index d99d54a..324deb6 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/BreadthFirstTraversal.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/BreadthFirstTraversal.kt @@ -21,14 +21,17 @@ import kotlin.jvm.JvmName * @param from the vertex from which to start the search. * @param action the action to execute on each vertex. */ -public inline fun Graph.forEachVertexBreadthFirst(from: Vertex, action: (Vertex) -> Unit) { +public inline fun G.forEachVertexBreadthFirst( + from: Vertex, + action: (Vertex) -> Unit, +) where G : Successors { contract { callsInPlace(action) } val queue = IntDequeue().apply { addLast(index(from)) } val visited = BooleanArray(size).apply { this[index(from)] = true } while (queue.size > 0) { val next = queue.removeFirst() action(vertex(next)) - forEachNeighbor(vertex(next)) { + forEachSuccessor(vertex(next)) { if (!visited[index(it)]) { queue.addLast(index(it)) visited[index(it)] = true @@ -51,14 +54,17 @@ public inline fun Graph.forEachVertexBreadthFirst(from: Vertex, action: (Vertex) * @return the [VertexArray] with the shortest path going from the [from] vertex to the [to] vertex, * or `null` if there is no path between the two vertices. */ -public fun Graph.shortestPathBreadthFirst(from: Vertex, to: Vertex): VertexArray? { +public fun G.shortestPathBreadthFirst( + from: Vertex, + to: Vertex, +): VertexArray? where G : Successors { if (from !in this) throw NoSuchVertexException() if (to !in this) throw NoSuchVertexException() val parents = VertexMap(size) { Vertex.Invalid } forEachVertexBreadthFirst(from) { u -> - forEachNeighbor(u) { v -> + forEachSuccessor(u) { v -> if (parents[v] == Vertex.Invalid) parents[v] = u if (v == to) return computePath(parents, from, to) } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/ConnectedComponents.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/ConnectedComponents.kt index a036e56..aa1fbf6 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/ConnectedComponents.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/ConnectedComponents.kt @@ -3,6 +3,8 @@ package io.github.alexandrepiveteau.graphs.algorithms +import io.github.alexandrepiveteau.graphs.Successors +import io.github.alexandrepiveteau.graphs.Undirected import io.github.alexandrepiveteau.graphs.UndirectedGraph import io.github.alexandrepiveteau.graphs.VertexMap import io.github.alexandrepiveteau.graphs.builder.buildUndirectedGraph @@ -19,7 +21,9 @@ import kotlin.jvm.JvmName * of edges in this graph. * - **Space complexity**: `O(|N|)`, where |N| is the number of vertices in this graph. */ -public fun UndirectedGraph.connectedComponents(): Pair { +public fun G.connectedComponents(): Pair where +G : Undirected, +G : Successors { val map = VertexMap(size) val visited = BooleanArray(size) // TODO : We could use a specific implementation of Graph which has no edges between vertices. diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/DepthFirstTraversal.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/DepthFirstTraversal.kt index 424f24e..81cdad9 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/DepthFirstTraversal.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/DepthFirstTraversal.kt @@ -3,7 +3,7 @@ package io.github.alexandrepiveteau.graphs.algorithms -import io.github.alexandrepiveteau.graphs.Graph +import io.github.alexandrepiveteau.graphs.Successors import io.github.alexandrepiveteau.graphs.Vertex import io.github.alexandrepiveteau.graphs.internal.collections.IntDequeue import kotlin.contracts.contract @@ -23,11 +23,11 @@ import kotlin.jvm.JvmName * @param visited the vertices that have already been visited, which will be updated by the search. * @param action the action to execute on each vertex. */ -public inline fun Graph.forEachVertexDepthFirst( +public inline fun G.forEachVertexDepthFirst( from: Vertex, visited: BooleanArray = BooleanArray(size), action: (Vertex) -> Unit, -) { +) where G : Successors { contract { callsInPlace(action) } forEachVertexDepthFirstHelper(from, visited, action) {} } @@ -45,11 +45,11 @@ public inline fun Graph.forEachVertexDepthFirst( * @param visited the vertices that have already been visited, which will be updated by the search. * @param action the action to execute on each vertex. */ -public inline fun Graph.forEachVertexDepthFirstPostOrder( +public inline fun G.forEachVertexDepthFirstPostOrder( from: Vertex, visited: BooleanArray = BooleanArray(size), action: (Vertex) -> Unit, -) { +) where G : Successors { contract { callsInPlace(action) } forEachVertexDepthFirstHelper(from, visited, {}, action) } @@ -70,12 +70,12 @@ public inline fun Graph.forEachVertexDepthFirstPostOrder( * @param postOrderAction the action to execute on each vertex post order. */ @PublishedApi -internal inline fun Graph.forEachVertexDepthFirstHelper( +internal inline fun G.forEachVertexDepthFirstHelper( from: Vertex, visited: BooleanArray = BooleanArray(size), inOrderAction: (Vertex) -> Unit, postOrderAction: (Vertex) -> Unit, -) { +) where G : Successors { contract { callsInPlace(inOrderAction) callsInPlace(postOrderAction) @@ -90,7 +90,7 @@ internal inline fun Graph.forEachVertexDepthFirstHelper( } var found = false while (counts[next] < successorsSize(next)) { - val neighbor = successor(next, counts[next]++) + val neighbor = successorVertex(next, counts[next]++) if (!visited[index(neighbor)]) { found = true path.addLast(index(neighbor)) diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Dijkstra.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Dijkstra.kt index 92a9eeb..07f4d50 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Dijkstra.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Dijkstra.kt @@ -14,7 +14,9 @@ import kotlin.jvm.JvmName * @param from the [Vertex] to start the search from. * @return the map of parents for each vertex in the shortest path tree from the [from] vertex. */ -private fun Network.shortestPathDijkstraParents(from: Vertex): VertexMap { +private fun N.shortestPathDijkstraParents( + from: Vertex, +): VertexMap where N : SuccessorsWeight { val parents = VertexMap(size) { Vertex.Invalid } val queue = IntMinPriorityQueue(size) val distances = IntArray(size) { Int.MAX_VALUE } @@ -26,7 +28,7 @@ private fun Network.shortestPathDijkstraParents(from: Vertex): VertexMap { while (queue.size > 0) { val v1 = vertex(queue.remove()) visited[index(v1)] = true - forEachNeighbor(v1) { v2, weight -> + forEachSuccessor(v1) { v2, weight -> if (!visited[index(v2)]) { // Note : we only throw on negative weights if they are visited, so a graph with negative // weights in a component disconnected from the source will not throw. @@ -61,7 +63,9 @@ private fun Network.shortestPathDijkstraParents(from: Vertex): VertexMap { * @throws NoSuchVertexException if the [from] vertex is not in this network. * @throws IllegalArgumentException if the network contains negative weights. */ -public fun Network.shortestPathDijkstra(from: Vertex): DirectedNetwork { +public fun N.shortestPathDijkstra( + from: Vertex, +): DirectedNetwork where N : SuccessorsWeight { if (from !in this) throw NoSuchVertexException() return computeNetwork(shortestPathDijkstraParents(from)) } @@ -82,7 +86,10 @@ public fun Network.shortestPathDijkstra(from: Vertex): DirectedNetwork { * @throws NoSuchVertexException if the [from] or [to] vertices are not in this graph. * @throws IllegalArgumentException if the network contains negative weights. */ -public fun Network.shortestPathDijkstra(from: Vertex, to: Vertex): VertexArray? { +public fun N.shortestPathDijkstra( + from: Vertex, + to: Vertex, +): VertexArray? where N : SuccessorsWeight { if (from !in this) throw NoSuchVertexException() if (to !in this) throw NoSuchVertexException() return computePath(shortestPathDijkstraParents(from), from, to) diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/EdmondsKarp.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/EdmondsKarp.kt index 93a7e9b..15cd657 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/EdmondsKarp.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/EdmondsKarp.kt @@ -10,13 +10,15 @@ import kotlin.jvm.JvmName import kotlin.math.min /** Returns the residual network of this [DirectedNetwork], given the current [flow]. */ -private fun DirectedNetwork.residual(flow: DirectedNetwork): DirectedNetwork { +private fun N.residual( + flow: DirectedNetwork, +): DirectedNetwork where N : Directed, N : SuccessorsWeight { return buildDirectedNetwork { forEachVertex { addVertex() } forEachArc { arc -> - val forwardCapacity = weight(arc) - flow.weight(arc) + val forwardCapacity = successorWeight(arc) - flow.successorWeight(arc) if (forwardCapacity > 0) addArc(arc, forwardCapacity) - val backwardCapacity = flow.weight(arc) + val backwardCapacity = flow.successorWeight(arc) if (backwardCapacity > 0) addArc(arc.reversed(), backwardCapacity) } } @@ -24,26 +26,34 @@ private fun DirectedNetwork.residual(flow: DirectedNetwork): DirectedNetwork { /** Iterates over all the arcs in the path, and calls the [action] for each of them. */ private inline fun VertexArray.forEachArc(action: (Arc) -> Unit) { - for (u in 0 until size - 1) { + for (u in 0 ..< size - 1) { action(this[u] arcTo this[u + 1]) } } /** Returns the remaining capacity of the [flow] in the [path]. */ -private fun DirectedNetwork.remainingCapacity(flow: DirectedNetwork, path: VertexArray): Int { +private fun N.remainingCapacity( + flow: DirectedNetwork, + path: VertexArray, +): Int where N : Directed, N : SuccessorsWeight { var capacity = Int.MAX_VALUE path.forEachArc { arc -> - val local = if (arc in this) weight(arc) - flow.weight(arc) else flow.weight(arc.reversed()) + val local = + if (arc in this) successorWeight(arc) - flow.successorWeight(arc) + else flow.successorWeight(arc.reversed()) capacity = min(capacity, local) } return capacity } /** Augments the [flow] with the given [path] and [flow], and returns the new flow. */ -private fun DirectedNetwork.augment(path: VertexArray, flow: Int): DirectedNetwork { +private fun N.augment( + path: VertexArray, + flow: Int, +): DirectedNetwork where N : Directed, N : SuccessorsWeight { return buildDirectedNetwork { forEachVertex { addVertex() } - forEachArc { (u, v) -> addArc(u arcTo v, weight(u arcTo v)) } + forEachVertex { u -> forEachSuccessor(u) { v, w -> addArc(u arcTo v, w) } } path.forEachArc { arc -> if (arc in this@augment) addArc(arc, flow) else addArc(arc.reversed(), -flow) } @@ -60,7 +70,10 @@ private fun DirectedNetwork.augment(path: VertexArray, flow: Int): DirectedNetwo * constrained by the capacities of the arcs. * @receiver the [Network] on which to compute the maximum flow. */ -public fun DirectedNetwork.maxFlowEdmondsKarp(from: Vertex, to: Vertex): DirectedNetwork { +public fun N.maxFlowEdmondsKarp( + from: Vertex, + to: Vertex, +): DirectedNetwork where N : Directed, N : SuccessorsWeight { // TODO : Use some MutableDirectedNetworks once they're implemented. var maxFlow = buildDirectedNetwork { forEachVertex { addVertex() } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Kosaraju.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Kosaraju.kt index 5190180..b03996b 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Kosaraju.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Kosaraju.kt @@ -16,7 +16,9 @@ import kotlin.jvm.JvmName * connected component. * @receiver the [DirectedGraph] to transform. */ -public fun DirectedGraph.stronglyConnectedComponentsKosaraju(): Pair { +public fun G.stronglyConnectedComponentsKosaraju(): Pair where +G : Directed, +G : Successors { // 1. Traverse all vertices in post-order fashion, and prepend them to the queue. val visited = BooleanArray(size) val queue = IntDequeue() @@ -32,7 +34,7 @@ public fun DirectedGraph.stronglyConnectedComponentsKosaraju(): Pair G.computePath( + parents: VertexMap, + from: Vertex, + to: Vertex, +): VertexArray? where G : VertexSet { if (from == Vertex.Invalid) throw IllegalArgumentException() if (to == Vertex.Invalid) throw IllegalArgumentException() val path = IntDequeue() @@ -36,12 +40,14 @@ internal fun Graph.computePath(parents: VertexMap, from: Vertex, to: Vertex): Ve * @return the [DirectedNetwork] for the subgraph of this [Network] defined by the [parents] map. * @receiver the [Network] to transform. */ -internal fun Network.computeNetwork(parents: VertexMap): DirectedNetwork { +internal fun N.computeNetwork( + parents: VertexMap, +): DirectedNetwork where N : SuccessorsWeight { return buildDirectedNetwork { forEachVertex { addVertex() } parents.forEach { vertex, parent -> if (parent != Vertex.Invalid) { - addArc(parent arcTo vertex, weight(parent, vertex)) + addArc(parent arcTo vertex, successorWeight(parent, vertex)) } } } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Prim.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Prim.kt index 9d5cc8a..c6a857c 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Prim.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/Prim.kt @@ -3,11 +3,8 @@ package io.github.alexandrepiveteau.graphs.algorithms -import io.github.alexandrepiveteau.graphs.UndirectedNetwork -import io.github.alexandrepiveteau.graphs.Vertex -import io.github.alexandrepiveteau.graphs.VertexMap +import io.github.alexandrepiveteau.graphs.* import io.github.alexandrepiveteau.graphs.builder.buildUndirectedNetwork -import io.github.alexandrepiveteau.graphs.edgeTo import io.github.alexandrepiveteau.graphs.internal.collections.IntMinPriorityQueue import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName @@ -19,33 +16,37 @@ import kotlin.jvm.JvmName * @return an [UndirectedNetwork] corresponding to the minimum spanning forest of the current * @receiver the [UndirectedNetwork] to compute the minimum spanning forest from. */ -public fun UndirectedNetwork.minimumSpanningForest(): UndirectedNetwork = buildUndirectedNetwork { - // Create all vertices in the resulting forest. - repeat(size) { addVertex() } +public fun N.minimumSpanningForest(): UndirectedNetwork where +N : Undirected, +N : SuccessorsWeight { + return buildUndirectedNetwork { + // Create all vertices in the resulting forest. + repeat(size) { addVertex() } - // Create the state for the Prim algorithm. - val parents = VertexMap(size) { Vertex.Invalid } - val weights = IntArray(size) { Int.MAX_VALUE } - val queue = IntMinPriorityQueue(size) - val visited = BooleanArray(size) { false } + // Create the state for the Prim algorithm. + val parents = VertexMap(size) { Vertex.Invalid } + val weights = IntArray(size) { Int.MAX_VALUE } + val queue = IntMinPriorityQueue(size) + val visited = BooleanArray(size) { false } - // Iterate over each tree in the forest. - forEachVertex { start -> - if (!visited[index(start)]) { - queue[index(start)] = 0 - while (queue.size > 0) { - val v1 = vertex(queue.remove()) - visited[index(v1)] = true - if (parents[v1] != Vertex.Invalid) { - addEdge(v1 edgeTo parents[v1], weights[index(v1)]) - } - forEachNeighbor(v1) { v2, weight -> - if (!visited[index(v2)]) { - val d = if (queue.contains(index(v2))) queue[index(v2)] else Int.MAX_VALUE - if (weight < d) { - parents[v2] = v1 - weights[index(v2)] = weight - queue[index(v2)] = weight + // Iterate over each tree in the forest. + forEachVertex { start -> + if (!visited[index(start)]) { + queue[index(start)] = 0 + while (queue.size > 0) { + val v1 = vertex(queue.remove()) + visited[index(v1)] = true + if (parents[v1] != Vertex.Invalid) { + addEdge(v1 edgeTo parents[v1], weights[index(v1)]) + } + forEachSuccessor(v1) { v2, weight -> + if (!visited[index(v2)]) { + val d = if (queue.contains(index(v2))) queue[index(v2)] else Int.MAX_VALUE + if (weight < d) { + parents[v2] = v1 + weights[index(v2)] = weight + queue[index(v2)] = weight + } } } } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/RandomWalk.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/RandomWalk.kt new file mode 100644 index 0000000..b756f36 --- /dev/null +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/RandomWalk.kt @@ -0,0 +1,91 @@ +package io.github.alexandrepiveteau.graphs.algorithms + +import io.github.alexandrepiveteau.graphs.Successors +import io.github.alexandrepiveteau.graphs.SuccessorsWeight +import io.github.alexandrepiveteau.graphs.Vertex +import io.github.alexandrepiveteau.graphs.internal.collections.IntVector +import kotlin.contracts.contract +import kotlin.random.Random + +/** + * Performs a random walk on the graph, starting from the given [from] vertex, and performs the + * given [action] on each vertex. The walk may be infinite if the graph contains cycles, and the + * walk will stop if the vertex has no successors. + * + * This method is inline, so it can be used to traverse the graph with suspending functions. + * + * ## Asymptotic complexity + * - **Time complexity**: Depends on the graph. + * - **Space complexity**: O(1). + */ +public inline fun G.randomWalk( + from: Vertex, + random: Random = Random, + action: (Vertex) -> Unit, +) where G : Successors { + contract { callsInPlace(action) } + + var current = index(from) + + while (true) { + action(vertex(current)) + val size = successorsSize(current) + if (size == 0) return + + current = index(successorVertex(current, random.nextInt(size))) + } +} + +/** + * Performs a random walk on the graph, starting from the given [from] vertex, and performs the + * given [action] on each vertex. The walk may be infinite if the graph contains cycles, and the + * walk will stop if the vertex has no successors. The walk will be weighted, and the probability of + * choosing a successor is proportional to the weight of the link. Negative weights are not + * supported, and will be ignored and treated as if they were 0. + * + * This method is inline, so it can be used to traverse the graph with suspending functions. + * + * ## Asymptotic complexity + * - **Time complexity**: Depends on the graph. + * - **Space complexity**: O(|D|), where |D| is the number of distinct successors for any given + * vertex. + */ +public inline fun G.randomWalkWeighted( + from: Vertex, + random: Random = Random, + action: (Vertex) -> Unit, +) where G : SuccessorsWeight { + contract { callsInPlace(action) } + + var current = index(from) + val vertices = IntVector() + val weights = IntVector() + + while (true) { + action(vertex(current)) + val size = successorsSize(current) + if (size == 0) return + + vertices.clear() + weights.clear() + + for (i in 0 ..< size) { + val weight = successorWeight(current, i) + if (weight <= 0) continue + vertices += index(successorVertex(current, i)) + weights += weight + } + + val total = weights.sum() + if (total <= 0) return // No reachable successors. + val value = random.nextInt(total) + var sum = 0 + for (i in 0 ..< weights.size) { + sum += weights[i] + if (sum > value) { + current = vertices[i] + break + } + } + } +} diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/ShortestPathFasterAlgorithm.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/ShortestPathFasterAlgorithm.kt index 8d24556..986d3ac 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/ShortestPathFasterAlgorithm.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/ShortestPathFasterAlgorithm.kt @@ -14,7 +14,9 @@ import kotlin.jvm.JvmName * @param from the [Vertex] to start the search from. * @return the map of parents for each vertex in the shortest path tree from the [from] vertex. */ -private fun Network.shortestPathFasterAlgorithmParents(from: Vertex): VertexMap { +private fun N.shortestPathFasterAlgorithmParents( + from: Vertex, +): VertexMap where N : SuccessorsWeight { val enqueued = BooleanArray(size) val distances = IntArray(size) { Int.MAX_VALUE } val queue = IntDequeue() @@ -29,7 +31,7 @@ private fun Network.shortestPathFasterAlgorithmParents(from: Vertex): VertexMap while (queue.size > 0) { val v1 = vertex(queue.removeFirst()) enqueued[index(v1)] = false - forEachNeighbor(v1) { v2, weight -> + forEachSuccessor(v1) { v2, weight -> val d1 = distances[index(v1)] val d2 = distances[index(v2)] if (d1 != Int.MAX_VALUE && (d2 == Int.MAX_VALUE || d1 + weight < d2)) { @@ -62,7 +64,9 @@ private fun Network.shortestPathFasterAlgorithmParents(from: Vertex): VertexMap * vertices in the network. * @throws NoSuchVertexException if the given [from] vertex is not in this graph. */ -public fun Network.shortestPathFasterAlgorithm(from: Vertex): DirectedNetwork { +public fun N.shortestPathFasterAlgorithm( + from: Vertex, +): DirectedNetwork where N : SuccessorsWeight { if (from !in this) throw NoSuchVertexException() return computeNetwork(shortestPathFasterAlgorithmParents(from)) } @@ -84,7 +88,10 @@ public fun Network.shortestPathFasterAlgorithm(from: Vertex): DirectedNetwork { * or `null` if no such path exists. * @throws NoSuchVertexException if the given [from] vertex or [to] vertex is not in this graph. */ -public fun Network.shortestPathFasterAlgorithm(from: Vertex, to: Vertex): VertexArray? { +public fun N.shortestPathFasterAlgorithm( + from: Vertex, + to: Vertex, +): VertexArray? where N : SuccessorsWeight { if (from !in this) throw NoSuchVertexException() if (to !in this) throw NoSuchVertexException() return computePath(shortestPathFasterAlgorithmParents(from), from, to) diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/TopologicalSort.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/TopologicalSort.kt index 3a45a0c..eea6242 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/TopologicalSort.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/algorithms/TopologicalSort.kt @@ -3,9 +3,7 @@ package io.github.alexandrepiveteau.graphs.algorithms -import io.github.alexandrepiveteau.graphs.DirectedGraph -import io.github.alexandrepiveteau.graphs.VertexArray -import io.github.alexandrepiveteau.graphs.asVertexArray +import io.github.alexandrepiveteau.graphs.* import io.github.alexandrepiveteau.graphs.internal.collections.IntDequeue import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName @@ -23,7 +21,7 @@ import kotlin.jvm.JvmName * @receiver the [DirectedGraph] to sort topologically. * @throws IllegalArgumentException if the graph contains a cycle. */ -public fun DirectedGraph.topologicalSort(): VertexArray { +public fun G.topologicalSort(): VertexArray where G : Directed, G : Successors { // 0. Set up a queue of vertices to add to the topological sort, and a boolean array to keep track // of the vertices that have already been sorted. @@ -50,7 +48,7 @@ public fun DirectedGraph.topologicalSort(): VertexArray { val vertex = queue.removeFirst() result.addLast(vertex) - forEachNeighbor(vertex(vertex)) { + forEachSuccessor(vertex(vertex)) { val to = index(it) edges[to]-- if (edges[to] == 0 && !sorted[to]) { diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/collections/IntVector.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/collections/IntVector.kt index 902bfc0..a21190d 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/collections/IntVector.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/collections/IntVector.kt @@ -39,6 +39,18 @@ internal class IntVector { size-- } + /** Clears the vector. */ + fun clear() { + size = 0 + } + + /** Returns the sum of all the elements in the vector. */ + fun sum(): Int { + var sum = 0 + for (i in 0 until size) sum += buffer[i] + return sum + } + /** Returns a copy of the vector as an [IntArray]. */ fun toIntArray(): IntArray = buffer.copyOf(size) } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyListGraph.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyListGraph.kt index 1a019b6..739c852 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyListGraph.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyListGraph.kt @@ -27,11 +27,15 @@ internal class AdjacencyListGraph(private val neighbors: Array) : G return neighbors[index].size } - override fun successor(index: Int, neighborIndex: Int): Vertex { + override fun successorIndex(index: Int, neighborIndex: Int): Int { if (index < 0 || index >= size) throw IndexOutOfBoundsException() val neighbors = neighbors[index] if (neighborIndex < 0 || neighborIndex >= neighbors.size) throw IndexOutOfBoundsException() - return neighbors[neighborIndex] + return neighbors[neighborIndex].index + } + + override fun successorVertex(index: Int, neighborIndex: Int): Vertex { + return vertex(successorIndex(index, neighborIndex)) } } diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyListNetwork.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyListNetwork.kt index bec4aa3..7c8510e 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyListNetwork.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyListNetwork.kt @@ -13,14 +13,14 @@ internal class AdjacencyListNetwork( private val weights: Array, ) : Network, Graph by AdjacencyListGraph(neighbors) { - override fun weight(index: Int, neighborIndex: Int): Int { + override fun successorWeight(index: Int, neighborIndex: Int): Int { if (index < 0 || index >= size) throw IndexOutOfBoundsException() val weights = weights[index] if (neighborIndex < 0 || neighborIndex >= weights.size) throw IndexOutOfBoundsException() return weights[neighborIndex] } - override fun weight(index: Int, neighbor: Vertex): Int { + override fun successorWeight(index: Int, neighbor: Vertex): Int { if (index < 0 || index >= size) throw IndexOutOfBoundsException() val neighbors = neighbors[index] val neighborIndex = neighbors.binarySearch(neighbor) diff --git a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyMatrixGraph.kt b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyMatrixGraph.kt index c51c8aa..71ffaaa 100644 --- a/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyMatrixGraph.kt +++ b/src/commonMain/kotlin/io/github/alexandrepiveteau/graphs/internal/graphs/AdjacencyMatrixGraph.kt @@ -29,17 +29,21 @@ internal abstract class AdjacencyMatrixGraph(private val present: Array= size) throw IndexOutOfBoundsException() val neighbors = present[index] var remaining = neighborIndex for (i in neighbors.indices) { if (neighbors[i]) { - if (remaining == 0) return Vertex(i) else remaining-- + if (remaining == 0) return i else remaining-- } } throw IndexOutOfBoundsException() } + + override fun successorVertex(index: Int, neighborIndex: Int): Vertex { + return vertex(successorIndex(index, neighborIndex)) + } } /** An implementation of [DirectedGraph] which uses an adjacency matrix to store the edges. */ diff --git a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.complete.kt b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.complete.kt index 9dd3c1a..db34502 100644 --- a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.complete.kt +++ b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/UndirectedGraph.complete.kt @@ -18,7 +18,7 @@ class UndirectedEmptyGraphTests { assertFailsWith { graph.vertex(0) } assertFailsWith { graph.index(Vertex(0)) } assertFailsWith { graph.successorsSize(0) } - assertFailsWith { graph.successor(0, 0) } + assertFailsWith { graph.successorVertex(0, 0) } } } diff --git a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/algorithms/DijkstraTests.kt b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/algorithms/DijkstraTests.kt index 29d758f..fa1cd30 100644 --- a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/algorithms/DijkstraTests.kt +++ b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/algorithms/DijkstraTests.kt @@ -19,9 +19,10 @@ class DijkstraTests { @Test fun singletonNetworkReturnsItself() { - val network = buildUndirectedNetwork { addVertex() } + var node: Vertex + val network = buildUndirectedNetwork { node = addVertex() } val expected = buildUndirectedNetwork { addVertex() } - val dijkstra = network.shortestPathDijkstra(network.vertex(0)) + val dijkstra = network.shortestPathDijkstra(node) assertEquals(expected, dijkstra) } diff --git a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/builder/UndirectedNetworkBuilderTests.kt b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/builder/UndirectedNetworkBuilderTests.kt index 6f3bcb6..c0e442c 100644 --- a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/builder/UndirectedNetworkBuilderTests.kt +++ b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/builder/UndirectedNetworkBuilderTests.kt @@ -31,7 +31,7 @@ class UndirectedNetworkBuilderTests { addEdge(a edgeTo b, 2) } - assertEquals(3, network.weight(a, b)) + assertEquals(3, network.successorWeight(a, b)) } @Test @@ -45,6 +45,6 @@ class UndirectedNetworkBuilderTests { addEdge(a edgeTo b, 1) addEdge(a edgeTo b, -2) } - assertEquals(-1, network.weight(a, b)) + assertEquals(-1, network.successorWeight(a, b)) } } diff --git a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/util/Assertions.kt b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/util/Assertions.kt index 203b2bc..7119d06 100644 --- a/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/util/Assertions.kt +++ b/src/commonTest/kotlin/io/github/alexandrepiveteau/graphs/util/Assertions.kt @@ -22,8 +22,8 @@ fun assertEquals(expected: Graph, actual: Graph) { ) for (j in 0 until expected.successorsSize(i)) { assertEquals( - expected.successor(i, j), - actual.successor(i, j), + expected.successorVertex(i, j), + actual.successorVertex(i, j), "neighbor different: $i, $j", ) } @@ -41,7 +41,7 @@ fun assertEquals(expected: Network, actual: Network) { assertEqualsGraph(expected as Graph, actual as Graph) for (i in 0 until expected.size) { for (j in 0 until expected.successorsSize(i)) { - assertEquals(expected.weight(i, j), actual.weight(i, j)) + assertEquals(expected.successorWeight(i, j), actual.successorWeight(i, j)) } } } @@ -66,8 +66,8 @@ fun assertFlowValid( val outgoing = IntArray(flow.size) { 0 } val incoming = IntArray(flow.size) { 0 } flow.forEachArc { (u, v) -> - val capacity = capacities.weight(u, v) - val weight = flow.weight(u, v) + val capacity = capacities.successorWeight(u, v) + val weight = flow.successorWeight(u, v) assertEquals(true, weight in 0..capacity) outgoing[u.index] += weight incoming[v.index] += weight