Skip to content

Commit

Permalink
Overhaul minimization code (#83)
Browse files Browse the repository at this point in the history
* add valmaris algorithm

* initial PT refactoring

* implement bisimulation via valmari

* add documentation

* cleanups

* add invasive hopcroft methods

* some more universal tests

* performance tweaks

* move OneSEVPAMinimizer

* improve documentation

* cleanup

* wording

* fix javadoc errors
  • Loading branch information
mtf90 authored Dec 12, 2024
1 parent f4b6a5b commit b4ae7ac
Show file tree
Hide file tree
Showing 47 changed files with 2,958 additions and 1,189 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

* AutomataLib now supports JPMS modules. Many of the artifacts now provide a `module-info` descriptor with the exception of `automata-brics` and `automata-jung-visualizer` which do not have modular dependencies and only provide an `Automatic-Module-Name` in their respective `MANIFEST.MF`s. As a consequence of this, the distribution artifacts (for Maven-less environments) also only provide an `Automatic-Module-Name`. Note that while this is a Java 9+ feature, AutomataLib still supports Java 8 byte code for the remaining class files.
* Added `TabakovVardiRandomAutomata` that allows for creating Tabakov-Vardi random automata, in particular, NFAs (thanks to [John Nicol](https://github.com/jn1z)).
* Added Valmari's algorithm for solving the coarsest relational partition problem in O(m + log n). This includes utility classes such as `ValmariInitializers` and `ValmariExtractors` for, e.g., convenient quotienting of NFAs via bi-similarity.

### Changed

Expand All @@ -25,9 +26,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* `CollectionsUtil` has been renamed to `CollectionUtil`.
* The `net:automatalib.tooling:automata-build-tools` module has been renamed to `net.automatalib:automata-build-config`.
* The `Alphabets#toGrowingAlphabetOrThrowException` method has been moved to `Alphabet#asGrowingAlphabetOrThrowException` so that one does not require an `automata-core` dependency for a simple cast.
* `OneSEVPAMinimizer` has been moved from `net.automatalib.util.minimizer` to `net.automatalib.util.automaton.minimizer`.
* The `Visualization` factory has been moved from the `automata-core` artifact to the `automata-api` artifact. Furthermore, the previous `DummyVP` has been replaced with a `NoopVP` that does not show a swing window anymore when no proper VisualizationProvider is configured but instead logs an error message. This allows us to drop the `java.desktop` (module) dependency for headless setups and only require it in actual visualizers (DOT, JUNG, etc.).
* The `DirectPowersetDTS` class has been renamed to `PowersetView`.
* The `FormatException` is now a checked exception because we can [reasonably expect clients to recover from this error](https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html). Furthermore, all parsing-related code has been aligned to use the `FormatException` instead of leaking implementation details (such as the `ParseException`s generated by JavaCC).
* The `PaigeTarjanMinimization` class (including all supporting classes such as `PaigeTarjanInitializers`) has been removed because, despite its name, the class never implemented Paige-Tarjan's algorithm for solving the *relational* coarsest partition problem but the functional one instead. Most of the previous functionality has been migrated to the (now correctly named) `HopcroftMinimizer` class.
* The serializers have been overhauled to allow for better integration of custom automaton types (especially when parsing). Some of the changes introduce new factory methods which may require some refactoring but the previous functionality is still available. As a part of this streamlining, many parsers no longer automatically un-compress or buffer the input streams to reduce overhead. The need for this can be determined best where the streams are created (in user-land).

### Removed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,64 @@ public static int computeNewCapacity(int length, int requiredCapacity, int nextC
public static <E> Iterator<E> iterator(E[] array) {
return new ArrayIterator<>(array);
}

/**
* Computes for the given array its prefix sum and directly stores the result in the given array.
*
* @param array
* the elements of the sum
* @param startInclusive
* the start index from which to begin the computation (inclusive)
* @param endExclusive
* the end index at which to stop the computation (exclusive)
*/
public static void prefixSum(int[] array, int startInclusive, int endExclusive) {
for (int i = startInclusive + 1; i < endExclusive; i++) {
array[i] += array[i - 1];
}
}

/**
* Sorts the given array according to the given keys using the heapsort sorting algorithm.
*
* @param arr
* the array to sort
* @param keys
* the array of keys, i.e. element i will be sorted according to {@code keys[i]}.
*/
public static void heapsort(int[] arr, int[] keys) {

int start = arr.length / 2;
int end = arr.length;

while (end > 1) {
if (start > 0) {
start--;
} else {
end--;
swap(arr, end, 0);
}

int root = start;
while (2 * root + 1 < end) {
int child = 2 * root + 1;
if (child + 1 < end && keys[arr[child]] < keys[arr[child + 1]]) {
child++;
}

if (keys[arr[root]] < keys[arr[child]]) {
swap(arr, root, child);
root = child;
} else {
break;
}
}
}
}

private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public static List<String> charStringRange(char start, char end) {
return new CharStringRange(start, end);
}

public static <T> List<? extends T> randomAccessList(Collection<? extends T> coll) {
public static <T> List<T> randomAccessList(Collection<T> coll) {
if (coll instanceof List && coll instanceof RandomAccess) {
return (List<? extends T>) coll;
return (List<T>) coll;
}
return new ArrayList<>(coll);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ public Integer createTransition(int successor, Void property) {
return toState(getIntSuccessor(getIntInitialState(), input));
}

@Override
// Overridden for performance reasons (to prevent autoboxing of default implementation)
public int getSuccessor(int state, int input) {
return transitions[toMemoryIndex(state, input)];
}

@Override
// Overridden for performance reasons (to prevent autoboxing of default implementation)
public @Nullable Integer getSuccessor(Integer state, Iterable<? extends I> input) {
Expand All @@ -75,6 +81,17 @@ protected void updateTransitionStorage(Payload payload) {
this.transitions = updateTransitionStorage(this.transitions, AbstractCompact.INVALID_STATE, payload);
}

@Override
// Overridden for performance reasons (to prevent autoboxing of default implementation)
public Void getTransitionProperty(int state, int input) {
return null;
}

@Override
public Void getTransitionProperty(Integer transition) {
return null;
}

@Override
public void setTransitionProperty(Integer transition, Void property) {}

Expand All @@ -99,11 +116,6 @@ public void setTransition(int state, int inputIdx, int succ) {
transitions[toMemoryIndex(state, inputIdx)] = succ;
}

@Override
public Void getTransitionProperty(Integer transition) {
return null;
}

@Override
public void clear() {
Arrays.fill(transitions, 0, size() * numInputs(), AbstractCompact.INVALID_STATE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Arrays;

import net.automatalib.alphabet.Alphabet;
import net.automatalib.automaton.AutomatonCreator;
import net.automatalib.automaton.base.AbstractCompact;
import net.automatalib.automaton.base.AbstractCompactDeterministic;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand All @@ -43,6 +44,10 @@ public UniversalCompactDet(Alphabet<I> alphabet) {
this(alphabet, DEFAULT_INIT_CAPACITY, DEFAULT_RESIZE_FACTOR);
}

public UniversalCompactDet(Alphabet<I> alphabet, int stateCapacity) {
this(alphabet, stateCapacity, DEFAULT_RESIZE_FACTOR);
}

public UniversalCompactDet(Alphabet<I> alphabet, int stateCapacity, float resizeFactor) {
super(alphabet, stateCapacity, resizeFactor);

Expand Down Expand Up @@ -158,4 +163,17 @@ protected void updateTransitionStorage(Payload payload) {
this.transitions = updateTransitionStorage(this.transitions, AbstractCompact.INVALID_STATE, payload);
this.transitionProperties = updateTransitionStorage(this.transitionProperties, null, payload);
}

public static final class Creator<I, SP, TP> implements AutomatonCreator<UniversalCompactDet<I, SP, TP>, I> {

@Override
public UniversalCompactDet<I, SP, TP> createAutomaton(Alphabet<I> alphabet, int numStates) {
return new UniversalCompactDet<>(alphabet, numStates);
}

@Override
public UniversalCompactDet<I, SP, TP> createAutomaton(Alphabet<I> alphabet) {
return new UniversalCompactDet<>(alphabet);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ public O getTransitionProperty(CompactTransition<O> transition) {
return transition.getProperty();
}

@Override
@SuppressWarnings("unchecked")
// Overridden for performance reasons (to prevent object instantiation of default implementation)
public O getTransitionProperty(int state, int input) {
return (O) outputs[toMemoryIndex(state, input)];
}

@Override
public void setTransitionProperty(CompactTransition<O> transition, O property) {
transition.setProperty(property);
Expand All @@ -109,6 +116,12 @@ public void removeAllTransitions(Integer state) {
Arrays.fill(outputs, lower, upper, null);
}

@Override
// Overridden for performance reasons (to prevent object instantiation of default implementation)
public int getSuccessor(int state, int input) {
return transitions[toMemoryIndex(state, input)];
}

@Override
public int getIntSuccessor(CompactTransition<O> transition) {
return transition.getSuccId();
Expand Down
Loading

0 comments on commit b4ae7ac

Please sign in to comment.