first commit

This commit is contained in:
Walcher 2024-01-02 15:25:05 +01:00
parent 5d48bb53e7
commit b418c37417
36 changed files with 5575 additions and 0 deletions

View file

@ -0,0 +1,4 @@
package ab1;
public class FinalizedStateException extends RuntimeException {
}

117
src/main/java/ab1/NFA.java Normal file
View file

@ -0,0 +1,117 @@
package ab1;
import java.util.Collection;
/**
* The {@code NFA} interface represents a Non-deterministic Finite Automaton (NFA) and provides methods to manipulate
* NFAs as well as run words against the NFA to check if they are in the language or not. The NFA has two states:
* edit and accept. While in edit-state, new transitions and accepting states can be added until
* {@link #finalizeAutomaton()} is called. If a method is called in the wrong state, a {@link FinalizedStateException}
* should be thrown.
*/
public interface NFA {
/**
* @return all states present in the automaton
*/
Collection<String> getStates();
/**
* @return all transitions currently configured in the automaton
*/
Collection<Transition> getTransitions();
/**
* @return all states present in the automata, marked as accepting state
*/
Collection<String> getAcceptingStates();
/**
* @return initial state of the automata. This cannot change over the lifetime of the object
*/
String getInitialState();
/**
* Add a new transition to the automata.
*
* @param transition information about the new transition. If the automaton already has a transition for the
* given fromState and readSymbol, it should be added nonetheless.
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was already called
*/
void addTransition(Transition transition) throws FinalizedStateException;
/**
* Flag a state to be an accepting state. If the state was accepting before, nothing changes.
*
* @param state - label of the new accepting state
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was already called
*/
void addAcceptingState(String state) throws FinalizedStateException;
/**
* @param other any NFA
* @return a new NFA instance that accepts the language L(return) = L(this) L(other).
* other. Both, other and this NFA must not change during this operation.
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was not already called
*/
NFA union(NFA other) throws FinalizedStateException;
/**
* @param other - any NFA
* @return a new NFA instance that accepts the language L(return) = L(this) L(other).
* Both, other and this NFA must not change during this operation.
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was not already called
*/
NFA intersection(NFA other) throws FinalizedStateException;
/**
* @param other - any NFA
* @return a new NFA instance that accepts the language L(return) = L(this) + L(other).
* Both, other and this NFA must not change during this operation.
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was not already called
*/
NFA concatenation(NFA other) throws FinalizedStateException;
/**
* @return a new NFA instance that accepts the language L(this)*.
* This NFA must not change during the operation.
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was not already called
*/
NFA kleeneStar() throws FinalizedStateException;
/**
* @return a new NFA instance that accepts the language L(this).
* This NFA must not change during the operation.
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was not already called
*/
NFA plusOperator() throws FinalizedStateException;
/**
* @return a new NFA instance that accepts the complement of L(this).
* This NFA must not change during the operation.
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was not already called
*/
NFA complement() throws FinalizedStateException;
/**
* @return if the automaton is editable or not
*/
boolean isFinalized();
/**
* Marks the automaton as finalized. Only now words can be tested.
*/
void finalizeAutomaton();
/**
* @return whether the language of this automaton is finite or infinite.
*/
boolean isFinite();
/**
* @param word - word to check, can be empty
* @return true, iff the word lies in the language of the automaton
* @throws FinalizedStateException if {@link #finalizeAutomaton()} was not already called
*/
boolean acceptsWord(String word) throws FinalizedStateException;
}

View file

@ -0,0 +1,5 @@
package ab1;
public interface NFAFactory {
NFA buildNFA(String startState);
}

View file

@ -0,0 +1,14 @@
package ab1;
import lombok.Builder;
/**
* Describes a transition of one character
*
* @param fromState - state, the automata must have for the transition to take effect
* @param readSymbol - next symbol in the word. Can be null for ε.
* @param toState - state, the automata has after the transition
*/
@Builder
public record Transition(String fromState, Character readSymbol, String toState) {
}

View file

@ -0,0 +1,11 @@
package ab1.impl.GRUPPE;
import ab1.NFA;
import ab1.NFAFactory;
public class NFAFactoryImpl implements NFAFactory {
@Override
public NFA buildNFA(String startState) {
return new NFAImpl();
}
}

View file

@ -0,0 +1,90 @@
package ab1.impl.GRUPPE;
import ab1.FinalizedStateException;
import ab1.NFA;
import ab1.Transition;
import java.util.Collection;
import java.util.Set;
public class NFAImpl implements NFA {
@Override
public Set<String> getStates() {
return null;
}
@Override
public Collection<Transition> getTransitions() {
return null;
}
@Override
public Set<String> getAcceptingStates() {
return null;
}
@Override
public String getInitialState() {
return null;
}
@Override
public void addTransition(Transition transition) throws FinalizedStateException {
}
@Override
public void addAcceptingState(String state) throws FinalizedStateException {
}
@Override
public NFA union(NFA other) throws FinalizedStateException {
return null;
}
@Override
public NFA intersection(NFA other) throws FinalizedStateException {
return null;
}
@Override
public NFA concatenation(NFA other) throws FinalizedStateException {
return null;
}
@Override
public NFA kleeneStar() throws FinalizedStateException {
return null;
}
@Override
public NFA plusOperator() throws FinalizedStateException {
return null;
}
@Override
public NFA complement() throws FinalizedStateException {
return null;
}
@Override
public boolean isFinalized() {
return false;
}
@Override
public void finalizeAutomaton() {
}
@Override
public boolean isFinite() {
return false;
}
@Override
public boolean acceptsWord(String word) {
return false;
}
}

View file

@ -0,0 +1,9 @@
package ab1;
import ab1.impl.GRUPPE.NFAFactoryImpl;
public class NFAProvider {
public static NFAFactory provideFactory() {
return new NFAFactoryImpl();
}
}

View file

@ -0,0 +1,176 @@
package ab1.tests;
import ab1.NFA;
import ab1.NFAFactory;
import ab1.NFAProvider;
import ab1.Transition;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ComplexTests {
private final NFAFactory factory = NFAProvider.provideFactory();
@Test
public void concat1Test() {
var nfaA = buildCharLanguage('a');
var testInstance = nfaA.concatenation(nfaA);
assertFalse(testInstance.acceptsWord("a"));
assertTrue(testInstance.acceptsWord("aa"));
assertFalse(testInstance.acceptsWord("aaa"));
}
@Test
public void union1Test() {
var nfaA = buildCharLanguage('a');
var nfaB = buildCharLanguage('b');
var testInstance = nfaA.union(nfaB);
assertTrue(testInstance.acceptsWord("a"));
assertTrue(testInstance.acceptsWord("b"));
assertFalse(testInstance.acceptsWord("ab"));
assertFalse(testInstance.acceptsWord("ba"));
}
@Test
public void intersection1Test() {
var nfaA = buildCharLanguage('a');
var nfaB = buildCharLanguage('b');
var testInstance = nfaA.intersection(nfaB);
assertFalse(testInstance.acceptsWord("a"));
assertFalse(testInstance.acceptsWord("b"));
assertFalse(testInstance.acceptsWord("ab"));
assertFalse(testInstance.acceptsWord("ba"));
}
@Test
public void intersection2Test() {
var nfaA = buildCharLanguage('a');
var nfaB = buildCharStarLanguage('a');
var testInstance = nfaA.intersection(nfaB);
assertTrue(testInstance.acceptsWord("a"));
assertFalse(testInstance.acceptsWord("aa"));
assertFalse(testInstance.acceptsWord("aaaa"));
assertFalse(testInstance.acceptsWord("aaaaaaaaaaa"));
assertFalse(testInstance.acceptsWord("b"));
assertFalse(testInstance.acceptsWord("ab"));
assertFalse(testInstance.acceptsWord("ba"));
}
@Test
public void star1Test() {
var nfaA = buildCharLanguage('a');
var testInstance = nfaA.kleeneStar();
assertTrue(testInstance.acceptsWord(""));
assertTrue(testInstance.acceptsWord("a"));
assertTrue(testInstance.acceptsWord("aa"));
assertTrue(testInstance.acceptsWord("aaaa"));
assertTrue(testInstance.acceptsWord("aaaaaaaaaaa"));
assertFalse(testInstance.acceptsWord("b"));
assertFalse(testInstance.acceptsWord("ab"));
assertFalse(testInstance.acceptsWord("ba"));
}
@Test
public void plus1Test() {
var nfaA = buildCharLanguage('a');
var testInstance = nfaA.plusOperator();
assertTrue(testInstance.acceptsWord("a"));
assertTrue(testInstance.acceptsWord("aa"));
assertTrue(testInstance.acceptsWord("aaaa"));
assertTrue(testInstance.acceptsWord("aaaaaaaaaaa"));
assertFalse(testInstance.acceptsWord(""));
assertFalse(testInstance.acceptsWord("b"));
assertFalse(testInstance.acceptsWord("ab"));
assertFalse(testInstance.acceptsWord("ba"));
}
@Test
public void plus2Test() {
var nfaA = buildCharLanguage('a');
var testInstance = nfaA.plusOperator();
assertTrue(testInstance.acceptsWord("a"));
assertTrue(testInstance.acceptsWord("aa"));
assertTrue(testInstance.acceptsWord("aaaa"));
assertTrue(testInstance.acceptsWord("aaaaaaaaaaa"));
assertFalse(testInstance.acceptsWord(""));
assertFalse(testInstance.acceptsWord("b"));
assertFalse(testInstance.acceptsWord("ab"));
assertFalse(testInstance.acceptsWord("ba"));
}
@Test
public void complement1Test() {
var nfaA = buildCharLanguage('a');
var testInstance = nfaA.complement();
assertFalse(testInstance.acceptsWord("a"));
assertTrue(testInstance.acceptsWord("aa"));
assertTrue(testInstance.acceptsWord("aaaa"));
assertTrue(testInstance.acceptsWord("aaaaaaaaaaa"));
assertTrue(testInstance.acceptsWord(""));
assertTrue(testInstance.acceptsWord("b"));
assertTrue(testInstance.acceptsWord("ab"));
assertTrue(testInstance.acceptsWord("ba"));
}
@Test
public void finite1Test() {
var nfaA = buildCharLanguage('a');
assertTrue(nfaA.isFinite());
}
@Test
public void finite2Test() {
var nfaA = buildCharLanguage('a');
assertFalse(nfaA.complement().isFinite());
}
private NFA buildCharStarLanguage(char c) {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.fromState("START")
.readSymbol(c)
.toState("START")
.build()
);
instance.addAcceptingState("START");
instance.finalizeAutomaton();
return instance;
}
private NFA buildCharLanguage(char c) {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.fromState("START")
.readSymbol(c)
.toState("ACCEPT")
.build()
);
instance.addAcceptingState("ACCEPT");
instance.finalizeAutomaton();
assertTrue(instance.acceptsWord(String.valueOf(c)));
return instance;
}
}

View file

@ -0,0 +1,119 @@
package ab1.tests;
import ab1.FinalizedStateException;
import ab1.NFAFactory;
import ab1.NFAProvider;
import ab1.Transition;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class FinalizeTests {
private final NFAFactory factory = NFAProvider.provideFactory();
@Test
public void finalize1Test() {
var instance = factory.buildNFA("START");
assertFalse(instance.isFinalized());
instance.finalizeAutomaton();
assertTrue(instance.isFinalized());
}
@Test
public void finalize2Test() {
var instance = factory.buildNFA("START");
instance.finalizeAutomaton();
assertThrows(
FinalizedStateException.class,
() -> instance.addTransition(
Transition.builder()
.fromState("START")
.toState("ACCEPT")
.readSymbol('a')
.build()
)
);
}
@Test
public void finalize3Test() {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.fromState("START")
.toState("ACCEPT")
.readSymbol('a')
.build()
);
instance.finalizeAutomaton();
}
@Test
public void finalize4Test() {
var instance = factory.buildNFA("START");
assertThrows(
FinalizedStateException.class,
instance::kleeneStar
);
}
@Test
public void finalize5Test() {
var instance = factory.buildNFA("START");
assertThrows(
FinalizedStateException.class,
instance::plusOperator
);
}
@Test
public void finalize6Test() {
var instance = factory.buildNFA("START");
assertThrows(
FinalizedStateException.class,
() -> instance.concatenation(instance)
);
}
@Test
public void finalize7Test() {
var instance = factory.buildNFA("START");
assertThrows(
FinalizedStateException.class,
() -> instance.intersection(instance)
);
}
@Test
public void finalize8Test() {
var instance = factory.buildNFA("START");
assertThrows(
FinalizedStateException.class,
instance::complement
);
}
@Test
public void finalize9Test() {
var instance = factory.buildNFA("START");
assertThrows(
FinalizedStateException.class,
() -> instance.union(instance)
);
}
}

View file

@ -0,0 +1,135 @@
package ab1.tests;
import ab1.NFAFactory;
import ab1.NFAProvider;
import ab1.Transition;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class LogicTests {
private final NFAFactory factory = NFAProvider.provideFactory();
@Test
public void language1Test() {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.fromState("START")
.readSymbol('a')
.toState("ACCEPT")
.build()
);
instance.addAcceptingState("ACCEPT");
instance.finalizeAutomaton();
assertTrue(instance.acceptsWord("a"));
assertFalse(instance.acceptsWord("aa"));
assertFalse(instance.acceptsWord("ba"));
assertFalse(instance.acceptsWord("xyaz"));
assertFalse(instance.acceptsWord("ETI is fun!"));
}
@Test
public void language2Test() {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.fromState("START")
.readSymbol('a')
.toState("ACCEPT")
.build()
);
instance.addTransition(
Transition.builder()
.fromState("ACCEPT")
.readSymbol('a')
.toState("ACCEPT")
.build()
);
instance.addAcceptingState("ACCEPT");
instance.finalizeAutomaton();
assertTrue(instance.acceptsWord("a"));
assertTrue(instance.acceptsWord("aa"));
assertTrue(instance.acceptsWord("aaa"));
assertTrue(instance.acceptsWord("aaaa"));
assertTrue(instance.acceptsWord("aaaaaaaaaaaaaaaaaaaaaa"));
assertFalse(instance.acceptsWord("ba"));
assertFalse(instance.acceptsWord("xyaz"));
assertFalse(instance.acceptsWord("ETI is fun!"));
}
@Test
public void language3Test() {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.fromState("START")
.readSymbol(null)
.toState("S1")
.build()
);
instance.addTransition(
Transition.builder()
.fromState("START")
.readSymbol(null)
.toState("S2")
.build()
);
instance.addTransition(
Transition.builder()
.fromState("S1")
.readSymbol('a')
.toState("ACCEPT")
.build()
);
instance.addTransition(
Transition.builder()
.fromState("S2")
.readSymbol('b')
.toState("ACCEPT")
.build()
);
instance.addAcceptingState("ACCEPT");
instance.finalizeAutomaton();
assertTrue(instance.acceptsWord("a"));
assertTrue(instance.acceptsWord("b"));
assertFalse(instance.acceptsWord("ba"));
assertFalse(instance.acceptsWord("xyaz"));
assertFalse(instance.acceptsWord("ETI is fun!"));
}
@Test
public void language4Test() {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.fromState("START")
.readSymbol('a')
.toState("ACCEPT")
.build()
);
instance.addTransition(
Transition.builder()
.fromState("ACCEPT")
.readSymbol(null)
.toState("START")
.build()
);
instance.addAcceptingState("ACCEPT");
instance.finalizeAutomaton();
assertTrue(instance.acceptsWord("a"));
assertTrue(instance.acceptsWord("aa"));
assertTrue(instance.acceptsWord("aaa"));
assertTrue(instance.acceptsWord("aaaa"));
assertTrue(instance.acceptsWord("aaaaaaaaaaaaaaaaaaaaaa"));
assertFalse(instance.acceptsWord("ba"));
assertFalse(instance.acceptsWord("xyaz"));
assertFalse(instance.acceptsWord("ETI is fun!"));
}
}

View file

@ -0,0 +1,84 @@
package ab1.tests;
import ab1.NFAFactory;
import ab1.NFAProvider;
import ab1.Transition;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class SimpleTests {
private final NFAFactory factory = NFAProvider.provideFactory();
@Test
public void acceptingStates1Test() {
var instance = factory.buildNFA("START");
instance.addAcceptingState("ACCEPT");
assertEquals(1, instance.getAcceptingStates().size());
assertTrue(instance.getAcceptingStates().contains("ACCEPT"));
}
@Test
public void acceptingStates2Test() {
var instance = factory.buildNFA("START");
instance.addAcceptingState("ACCEPT");
instance.addAcceptingState("ACCEPT");
instance.addAcceptingState("ACCEPT");
assertEquals(1, instance.getAcceptingStates().size());
assertTrue(instance.getAcceptingStates().contains("ACCEPT"));
}
@Test
public void acceptingStates3Test() {
var instance = factory.buildNFA("START");
instance.addAcceptingState("ACCEPT");
instance.addAcceptingState("OTHER_ACCEPT");
assertEquals(2, instance.getAcceptingStates().size());
assertTrue(instance.getAcceptingStates().contains("ACCEPT"));
assertTrue(instance.getAcceptingStates().contains("OTHER_ACCEPT"));
}
@Test
public void acceptingStates4Test() {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.readSymbol('a')
.fromState("START")
.toState("ACCEPT")
.build()
);
instance.addAcceptingState("ACCEPT");
assertEquals(1, instance.getAcceptingStates().size());
assertTrue(instance.getAcceptingStates().contains("ACCEPT"));
}
@Test
public void transitions1Test() {
var instance = factory.buildNFA("START");
instance.addTransition(
Transition.builder()
.readSymbol('a')
.fromState("START")
.toState("ACCEPT")
.build()
);
assertEquals(2, instance.getStates().size());
}
@Test
public void initialStateTest() {
var instance = factory.buildNFA("START");
assertEquals("START", instance.getInitialState());
}
}