Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port TopologicalSort to Java #4110

Merged
merged 1 commit into from Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 8 additions & 7 deletions kore/src/main/java/org/kframework/POSet.java
Expand Up @@ -6,13 +6,11 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.commons.lang3.tuple.Pair;
import org.kframework.utils.Lazy;
import org.kframework.utils.errorsystem.KEMException;
Expand Down Expand Up @@ -108,14 +106,17 @@ public Set<T> elements() {
return elementsLazy.get();
}

private List<T> computeSortedElements() {
return StreamSupport.stream(TopologicalSort.tsort(directRelations).spliterator(), false)
.toList();
private java.util.List<T> computeSortedElements() {
Optional<Stream<T>> topological = TopologicalSort.tsort(directRelations);
// We already checked for cycles during construction, so the sort should succeed
assert topological.isPresent();
return topological.get().toList();
}

private final Lazy<List<T>> sortedElementsLazy = new Lazy<>(this::computeSortedElements);
private final Lazy<java.util.List<T>> sortedElementsLazy =
new Lazy<>(this::computeSortedElements);

public List<T> sortedElements() {
public java.util.List<T> sortedElements() {
return sortedElementsLazy.get();
}

Expand Down
50 changes: 50 additions & 0 deletions kore/src/main/java/org/kframework/TopologicalSort.java
@@ -0,0 +1,50 @@
// Copyright (c) Runtime Verification, Inc. All Rights Reserved.
package org.kframework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.tuple.Pair;

public class TopologicalSort {
/** Topologically sort based on the provided edges, unless a cycle is present. */
public static <T> Optional<Stream<T>> tsort(Iterable<Pair<T, T>> edges) {
Map<T, Set<T>> toPred = new HashMap<>();
for (Pair<T, T> edge : edges) {
if (!toPred.containsKey(edge.getLeft())) {
toPred.put(edge.getLeft(), new HashSet<>());
}
if (!toPred.containsKey(edge.getRight())) {
toPred.put(edge.getRight(), new HashSet<>());
}
toPred.get(edge.getRight()).add(edge.getLeft());
}
return tsortInternal(toPred, Stream.empty());
}

private static <T> Optional<Stream<T>> tsortInternal(Map<T, Set<T>> toPreds, Stream<T> done) {
Map<Boolean, List<Map.Entry<T, Set<T>>>> partition =
toPreds.entrySet().stream()
.collect(Collectors.partitioningBy((e) -> e.getValue().isEmpty()));
List<Map.Entry<T, Set<T>>> noPreds = partition.get(true);
Map<T, Set<T>> hasPreds =
partition.get(false).stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
if (noPreds.isEmpty()) {
if (hasPreds.isEmpty()) {
return Optional.of(done);
}
return Optional.empty();
}
Set<T> found = noPreds.stream().map(Map.Entry::getKey).collect(Collectors.toSet());
for (Map.Entry<T, Set<T>> entry : hasPreds.entrySet()) {
entry.getValue().removeAll(found);
}
return tsortInternal(hasPreds, Stream.concat(done, found.stream()));
}
}
32 changes: 0 additions & 32 deletions kore/src/main/scala/org/kframework/TopologicalSort.scala

This file was deleted.

1 change: 0 additions & 1 deletion kore/src/main/scala/org/kframework/collections.scala
Expand Up @@ -19,7 +19,6 @@ object Collections {
def immutable[T](s: java.util.Set[T]): Set[T] = s.asScala.toSet
def immutable[T](s: java.util.List[T]): Seq[T] = s.asScala
def immutable[K, V](s: java.util.Map[K, V]): Map[K, V] = s.asScala
def immutable[T](s: Array[T]): Seq[T] = s
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this because it overlaps with the immutable[T](s: java.util.List[T]): Seq[T] overload, making the latter unusable (and it's dead code anyways).


def mutable[T](s: scala.List[T]): java.util.List[T] = s.asJava
def mutable[T](s: Seq[T]): java.util.List[T] = s.asJava
Expand Down
@@ -1,7 +1,6 @@
// Copyright (c) Runtime Verification, Inc. All Rights Reserved.
package org.kframework.compile

import collection._
import java.util
import org.kframework.attributes.Att
import org.kframework.builtin.Sorts
Expand All @@ -14,8 +13,10 @@ import org.kframework.kore._
import org.kframework.kore.KORE.KApply
import org.kframework.kore.KORE.KLabel
import org.kframework.utils.errorsystem.KEMException
import org.kframework.Collections
import org.kframework.POSet
import org.kframework.TopologicalSort._
import scala.collection._
import scala.collection.JavaConverters._

object ConfigurationInfoFromModule
Expand Down Expand Up @@ -96,7 +97,7 @@ class ConfigurationInfoFromModule(val m: Module) extends ConfigurationInfo {

private lazy val topCells = cellSorts.diff(edges.map(_._2))

private val sortedSorts: Seq[Sort] = tsort(edges).toSeq
private val sortedSorts: Seq[Sort] = Collections.immutable(edgesPoset.sortedElements())
private val sortedEdges: Seq[(Sort, Sort)] =
edges.toList.sortWith((l, r) => sortedSorts.indexOf(l._1) < sortedSorts.indexOf(r._1))
val levels: Map[Sort, Int] = sortedEdges.foldLeft(topCells.map((_, 0)).toMap) {
Expand Down