diff --git a/util/src/main/java/net/automatalib/util/automaton/Automata.java b/util/src/main/java/net/automatalib/util/automaton/Automata.java index fd2ffe35b3..0d95d8bb6b 100644 --- a/util/src/main/java/net/automatalib/util/automaton/Automata.java +++ b/util/src/main/java/net/automatalib/util/automaton/Automata.java @@ -97,6 +97,28 @@ public static Graph> asGraph(Automaton + * state type + * @param + * input symbol type + * @param + * transition type + * @param + * state property type + * @param + * transition property type + * @param + * automaton type + * + * @return the same mutable DFA (for convenience) + */ @SuppressWarnings("unchecked") public static > A invasiveMinimize(A automaton, Collection inputs) { @@ -116,6 +138,7 @@ public static > ResultStateRecord[] records = new ResultStateRecord[mr.getNumBlocks()]; + // Store minimized automaton data in the records array for (Block> blk : mr.getBlocks()) { int id = blk.getId(); S state = mr.getRepresentative(blk); @@ -138,6 +161,7 @@ public static > automaton.clear(); + // Add states from records @Nullable Object[] states = new Object[records.length]; for (int i = 0; i < records.length; i++) { ResultStateRecord rec = records[i]; @@ -151,6 +175,7 @@ public static > states[i] = state; } + // Add transitions from records for (int i = 0; i < records.length; i++) { ResultStateRecord rec = records[i]; S state = (S) states[i]; diff --git a/util/src/main/java/net/automatalib/util/automaton/fsa/NFAs.java b/util/src/main/java/net/automatalib/util/automaton/fsa/NFAs.java index 63cbd16383..ae3ee432f5 100644 --- a/util/src/main/java/net/automatalib/util/automaton/fsa/NFAs.java +++ b/util/src/main/java/net/automatalib/util/automaton/fsa/NFAs.java @@ -288,10 +288,38 @@ public static > A impl(NFA 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 + * input symbol type + * + * @return the determinized NFA + */ public static CompactDFA determinize(NFA nfa, Alphabet 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 + * input symbol type + * + * @return the determinized NFA + */ public static CompactDFA determinize(NFA nfa, Alphabet inputAlphabet, boolean partial, @@ -301,6 +329,22 @@ public static CompactDFA determinize(NFA 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 + * input symbol type + */ public static void determinize(NFA nfa, Collection inputs, MutableDFA out, @@ -312,20 +356,78 @@ public static void determinize(NFA nfa, } } + /** + * Determinizes the given NFA, and returns the result as a new DFA. + * + * @param nfa + * the original NFA + * @param + * input symbol type + * @param + * automaton type + * + * @return the determinized NFA + */ public static & InputAlphabetHolder> CompactDFA 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 + * input symbol type + * @param + * automaton type + * + * @return the determinized NFA + */ public static & InputAlphabetHolder> CompactDFA 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 + * input symbol type + */ public static void determinize(NFA nfa, Collection inputs, MutableDFA 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 + * input symbol type + * @param + * state type of the input automaton + * @param + * state type of the output automaton + */ private static void doDeterminize(NFA nfa, Collection inputs, MutableDFA out, @@ -336,6 +438,7 @@ private static void doDeterminize(NFA nfa, Deque> stack = new ArrayDeque<>(); + // Add union of initial states to DFA and to stack List initList = new ArrayList<>(nfa.getInitialStates()); BitSet initBs = new BitSet(); for (SI init : initList) { @@ -359,6 +462,7 @@ private static void doDeterminize(NFA nfa, BitSet succBs = new BitSet(); List 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); @@ -372,6 +476,7 @@ private static void doDeterminize(NFA 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)); diff --git a/util/src/test/java/net/automatalib/util/automaton/fsa/DFAsTest.java b/util/src/test/java/net/automatalib/util/automaton/fsa/DFAsTest.java index 877d2e0d25..96297593d3 100644 --- a/util/src/test/java/net/automatalib/util/automaton/fsa/DFAsTest.java +++ b/util/src/test/java/net/automatalib/util/automaton/fsa/DFAsTest.java @@ -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; @@ -67,6 +68,14 @@ private CompactDFA forVector(boolean... boolVec) { return result; } + @Test + public void testCombine() { + DFA expected = forVector(AND_RESULT); + DFA actual = DFAs.combine(testDfa1, testDfa2, testAlphabet, AcceptanceCombiner.AND); + + Assert.assertTrue(Automata.testEquivalence(actual, expected, testAlphabet)); + } + @Test public void testAnd() { DFA expected = forVector(AND_RESULT); diff --git a/util/src/test/java/net/automatalib/util/automaton/fsa/NFAsTest.java b/util/src/test/java/net/automatalib/util/automaton/fsa/NFAsTest.java index a554456a64..3b16e43431 100644 --- a/util/src/test/java/net/automatalib/util/automaton/fsa/NFAsTest.java +++ b/util/src/test/java/net/automatalib/util/automaton/fsa/NFAsTest.java @@ -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; @@ -67,6 +68,13 @@ private CompactNFA forVector(boolean... boolVec) { return result; } + @Test + public void testCombine() { + NFA expected = forVector(AND_RESULT); + NFA actual = NFAs.combine(testNfa1, testNfa2, testAlphabet, AcceptanceCombiner.AND); + assertEquivalence(actual, expected, testAlphabet); + } + @Test public void testAnd() { NFA expected = forVector(AND_RESULT); @@ -126,6 +134,8 @@ public void testDeterminize() { CompactDFA 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 void assertEquivalence(NFA nfa1, NFA nfa2, Alphabet inputs) {