Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions util/src/main/java/net/automatalib/util/automaton/Automata.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,28 @@ public static <S, I, T> Graph<S, TransitionEdge<I, T>> asGraph(Automaton<S, I, T
return output;
}

/**
* Minimize the given mutable DFA in-place.
*
* @param automaton
* mutable DFA
* @param inputs
* the input symbols
* @param <S>
* state type
* @param <I>
* input symbol type
* @param <T>
* transition type
* @param <SP>
* state property type
* @param <TP>
* transition property type
* @param <A>
* automaton type
*
* @return the same mutable DFA (for convenience)
*/
@SuppressWarnings("unchecked")
public static <S, I, T, SP, TP, A extends MutableDeterministic<S, I, T, SP, TP>> A invasiveMinimize(A automaton,
Collection<? extends I> inputs) {
Expand All @@ -116,6 +138,7 @@ public static <S, I, T, SP, TP, A extends MutableDeterministic<S, I, T, SP, TP>>

ResultStateRecord<SP, TP>[] records = new ResultStateRecord[mr.getNumBlocks()];

// Store minimized automaton data in the records array
for (Block<S, TransitionEdge.Property<I, TP>> blk : mr.getBlocks()) {
int id = blk.getId();
S state = mr.getRepresentative(blk);
Expand All @@ -138,6 +161,7 @@ public static <S, I, T, SP, TP, A extends MutableDeterministic<S, I, T, SP, TP>>

automaton.clear();

// Add states from records
@Nullable Object[] states = new Object[records.length];
for (int i = 0; i < records.length; i++) {
ResultStateRecord<SP, TP> rec = records[i];
Expand All @@ -151,6 +175,7 @@ public static <S, I, T, SP, TP, A extends MutableDeterministic<S, I, T, SP, TP>>
states[i] = state;
}

// Add transitions from records
for (int i = 0; i < records.length; i++) {
ResultStateRecord<SP, TP> rec = records[i];
S state = (S) states[i];
Expand Down
105 changes: 105 additions & 0 deletions util/src/main/java/net/automatalib/util/automaton/fsa/NFAs.java
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,38 @@ public static <I, S, A extends MutableNFA<S, I>> A impl(NFA<?, I> nfa1,
return combine(nfa1, nfa2, inputs, out, AcceptanceCombiner.IMPL);
}

/**
* Determinizes the given NFA, and returns the result as a new complete DFA.
*
* @param nfa
* the original NFA
* @param inputAlphabet
* the input alphabet
* @param <I>
* input symbol type
*
* @return the determinized NFA
*/
public static <I> CompactDFA<I> determinize(NFA<?, I> nfa, Alphabet<I> inputAlphabet) {
return determinize(nfa, inputAlphabet, false, true);
}

/**
* Determinizes the given NFA, and returns the result as a new DFA.
*
* @param nfa
* the original NFA
* @param inputAlphabet
* the input alphabet
* @param partial
* allows the new DFA to be partial
* @param minimize
* whether to minimize the DFA
* @param <I>
* input symbol type
*
* @return the determinized NFA
*/
public static <I> CompactDFA<I> determinize(NFA<?, I> nfa,
Alphabet<I> inputAlphabet,
boolean partial,
Expand All @@ -301,6 +329,22 @@ public static <I> CompactDFA<I> determinize(NFA<?, I> nfa,
return result;
}

/**
* Determinizes the given NFA, and stores the result in a given mutable DFA.
*
* @param nfa
* the original NFA
* @param inputs
* the input symbols to consider
* @param out
* a mutable DFA for storing the result
* @param partial
* allows the new DFA to be partial
* @param minimize
* whether to minimize the DFA
* @param <I>
* input symbol type
*/
public static <I> void determinize(NFA<?, I> nfa,
Collection<? extends I> inputs,
MutableDFA<?, I> out,
Expand All @@ -312,20 +356,78 @@ public static <I> void determinize(NFA<?, I> nfa,
}
}

/**
* Determinizes the given NFA, and returns the result as a new DFA.
*
* @param nfa
* the original NFA
* @param <I>
* input symbol type
* @param <A>
* automaton type
*
* @return the determinized NFA
*/
public static <I, A extends NFA<?, I> & InputAlphabetHolder<I>> CompactDFA<I> determinize(A nfa) {
return determinize(nfa, false, true);
}

/**
* Determinizes the given NFA, and returns the result as a new DFA.
*
* @param nfa
* the original NFA
* @param partial
* allows the new DFA to be partial
* @param minimize
* whether to minimize the DFA
* @param <I>
* input symbol type
* @param <A>
* automaton type
*
* @return the determinized NFA
*/
public static <I, A extends NFA<?, I> & InputAlphabetHolder<I>> CompactDFA<I> determinize(A nfa,
boolean partial,
boolean minimize) {
return determinize(nfa, nfa.getInputAlphabet(), partial, minimize);
}

/**
* Determinizes the given NFA, and stores the result in a given mutable DFA.
*
* @param nfa
* the original NFA
* @param inputs
* the input symbols to consider
* @param out
* a mutable DFA for storing the result
* @param <I>
* input symbol type
*/
public static <I> void determinize(NFA<?, I> nfa, Collection<? extends I> inputs, MutableDFA<?, I> out) {
determinize(nfa, inputs, out, false, true);
}

/**
* Determinize the given NFA via the Subset (also called Powerset) Construction.
*
* @param nfa
* the original NFA
* @param inputs
* the input symbols to consider
* @param out
* a mutable DFA for storing the result
* @param partial
* allows the new DFA to be partial
* @param <I>
* input symbol type
* @param <SI>
* state type of the input automaton
* @param <SO>
* state type of the output automaton
*/
private static <I, SI, SO> void doDeterminize(NFA<SI, I> nfa,
Collection<? extends I> inputs,
MutableDFA<SO, I> out,
Expand All @@ -336,6 +438,7 @@ private static <I, SI, SO> void doDeterminize(NFA<SI, I> nfa,

Deque<DeterminizeRecord<SI, SO>> stack = new ArrayDeque<>();

// Add union of initial states to DFA and to stack
List<SI> initList = new ArrayList<>(nfa.getInitialStates());
BitSet initBs = new BitSet();
for (SI init : initList) {
Expand All @@ -359,6 +462,7 @@ private static <I, SI, SO> void doDeterminize(NFA<SI, I> nfa,
BitSet succBs = new BitSet();
List<SI> succList = new ArrayList<>();

// Determine the union of the successors of the given state and symbol
for (SI inState : inStates) {
for (SI succState : nfa.getSuccessors(inState, sym)) {
int succId = stateIds.getStateId(succState);
Expand All @@ -372,6 +476,7 @@ private static <I, SI, SO> void doDeterminize(NFA<SI, I> nfa,
if (!partial || !succList.isEmpty()) {
SO outSucc = outStateMap.get(succBs);
if (outSucc == null) {
// add new state to DFA and to stack
outSucc = out.addState(nfa.isAccepting(succList));
outStateMap.put(succBs, outSucc);
stack.push(new DeterminizeRecord<>(succList, outSucc));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import net.automatalib.automaton.fsa.DFA;
import net.automatalib.automaton.fsa.impl.CompactDFA;
import net.automatalib.util.automaton.Automata;
import net.automatalib.util.ts.acceptor.AcceptanceCombiner;
import org.testng.Assert;
import org.testng.annotations.Test;

Expand Down Expand Up @@ -67,6 +68,14 @@ private CompactDFA<Integer> forVector(boolean... boolVec) {
return result;
}

@Test
public void testCombine() {
DFA<?, Integer> expected = forVector(AND_RESULT);
DFA<?, Integer> actual = DFAs.combine(testDfa1, testDfa2, testAlphabet, AcceptanceCombiner.AND);

Assert.assertTrue(Automata.testEquivalence(actual, expected, testAlphabet));
}

@Test
public void testAnd() {
DFA<?, Integer> expected = forVector(AND_RESULT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import net.automatalib.automaton.fsa.impl.CompactDFA;
import net.automatalib.automaton.fsa.impl.CompactNFA;
import net.automatalib.util.automaton.Automata;
import net.automatalib.util.ts.acceptor.AcceptanceCombiner;
import net.automatalib.word.Word;
import org.testng.Assert;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -67,6 +68,13 @@ private CompactNFA<Integer> forVector(boolean... boolVec) {
return result;
}

@Test
public void testCombine() {
NFA<?, Integer> expected = forVector(AND_RESULT);
NFA<?, Integer> actual = NFAs.combine(testNfa1, testNfa2, testAlphabet, AcceptanceCombiner.AND);
assertEquivalence(actual, expected, testAlphabet);
}

@Test
public void testAnd() {
NFA<?, Integer> expected = forVector(AND_RESULT);
Expand Down Expand Up @@ -126,6 +134,8 @@ public void testDeterminize() {
CompactDFA<Integer> dfa = NFAs.determinize(nfa);

Assert.assertEquals(dfa.size(), 2);
Assert.assertTrue(dfa.accepts(Word.fromSymbols(0, 1, 0, 1)));
Assert.assertFalse(dfa.accepts(Word.fromSymbols(0, 1, 0, 1, 0)));
}

private <I> void assertEquivalence(NFA<?, I> nfa1, NFA<?, I> nfa2, Alphabet<I> inputs) {
Expand Down