Skip to content

Commit 3b61aee

Browse files
committed
simplify procedural implementations
since the output semantics now better handle partial systems, get rid of explicit sink management
1 parent a7065b9 commit 3b61aee

File tree

8 files changed

+76
-76
lines changed

8 files changed

+76
-76
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
3434

3535
* `IOUtil#copy(Reader, Writer)` has been removed. Use `Reader#transferTo(Writer)` instead.
3636
* `JVMUtil` has been removed. Use `Runtime.version().feature()` for its previously (only) provided method.
37+
* `StackState#SINK` has been removed as procedural systems now better handle undefined transitions.
3738

3839
### Fixed
3940

core/src/main/java/net/automatalib/automaton/procedural/impl/EmptySPMM.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
import net.automatalib.alphabet.ProceduralInputAlphabet;
2222
import net.automatalib.automaton.procedural.SPMM;
2323
import net.automatalib.automaton.transducer.MealyMachine;
24-
import net.automatalib.common.util.collection.IterableUtil;
25-
import net.automatalib.word.Word;
2624
import org.checkerframework.checker.nullness.qual.Nullable;
2725

2826
/**
@@ -64,12 +62,6 @@ public O getErrorOutput() {
6462
return Collections.emptyMap();
6563
}
6664

67-
@Override
68-
public Word<O> computeSuffixOutput(Iterable<? extends I> prefix, Iterable<? extends I> suffix) {
69-
final int length = IterableUtil.size(suffix);
70-
return Word.fromList(Collections.nCopies(length, errorOutput));
71-
}
72-
7365
@Override
7466
public Void getTransition(Void state, I input) {
7567
return null;

core/src/main/java/net/automatalib/automaton/procedural/impl/StackSBA.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,38 +50,38 @@ public StackSBA(ProceduralInputAlphabet<I> alphabet,
5050
}
5151

5252
@Override
53-
public StackState<S, I, DFA<S, I>> getTransition(StackState<S, I, DFA<S, I>> state, I input) {
54-
if (state.isSink() || state.isTerm()) {
55-
return StackState.sink();
53+
public @Nullable StackState<S, I, DFA<S, I>> getTransition(StackState<S, I, DFA<S, I>> state, I input) {
54+
if (state.isTerm()) {
55+
return null;
5656
} else if (alphabet.isInternalSymbol(input)) {
5757
if (state.isInit()) {
58-
return StackState.sink();
58+
return null;
5959
}
6060

6161
final DFA<S, I> model = state.getProcedure();
6262
final S next = model.getTransition(state.getCurrentState(), input);
6363

6464
// undefined internal transition
6565
if (next == null || !model.isAccepting(next)) {
66-
return StackState.sink();
66+
return null;
6767
}
6868

6969
return state.updateState(next);
7070
} else if (alphabet.isCallSymbol(input)) {
7171
if (state.isInit() && !Objects.equals(this.initialCall, input)) {
72-
return StackState.sink();
72+
return null;
7373
}
7474

7575
final DFA<S, I> model = this.procedures.get(input);
7676

7777
if (model == null) {
78-
return StackState.sink();
78+
return null;
7979
}
8080

8181
final S next = model.getInitialState();
8282

8383
if (next == null) {
84-
return StackState.sink();
84+
return null;
8585
}
8686

8787
// store the procedural successor in the stack so that we don't need to look it up on return symbols
@@ -92,15 +92,15 @@ public StackState<S, I, DFA<S, I>> getTransition(StackState<S, I, DFA<S, I>> sta
9292
final DFA<S, I> p = state.getProcedure();
9393
final S succ = p.getSuccessor(state.getCurrentState(), input);
9494
if (succ == null || !p.isAccepting(succ)) {
95-
return StackState.sink();
95+
return null;
9696
}
9797
returnState = state.updateState(succ);
9898
}
9999

100100
return returnState.push(model, next);
101101
} else if (alphabet.isReturnSymbol(input)) {
102102
if (state.isInit()) {
103-
return StackState.sink();
103+
return null;
104104
}
105105

106106
// if we returned the state before, we checked that a procedure is available
@@ -109,19 +109,18 @@ public StackState<S, I, DFA<S, I>> getTransition(StackState<S, I, DFA<S, I>> sta
109109

110110
// cannot return, reject word
111111
if (succ == null || !model.isAccepting(succ)) {
112-
return StackState.sink();
112+
return null;
113113
}
114114

115115
return state.pop();
116116
} else {
117-
return StackState.sink();
117+
return null;
118118
}
119119
}
120120

121121
@Override
122122
public boolean isAccepting(StackState<S, I, DFA<S, I>> state) {
123-
return !state.isSink() &&
124-
(state.isInit() || state.isTerm() || state.getProcedure().isAccepting(state.getCurrentState()));
123+
return state.isInit() || state.isTerm() || state.getProcedure().isAccepting(state.getCurrentState());
125124
}
126125

127126
@Override

core/src/main/java/net/automatalib/automaton/procedural/impl/StackSPA.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,37 +51,37 @@ public StackSPA(ProceduralInputAlphabet<I> alphabet,
5151

5252
@Override
5353
public StackState<S, I, DFA<S, I>> getTransition(StackState<S, I, DFA<S, I>> state, I input) {
54-
if (state.isSink() || state.isTerm()) {
55-
return StackState.sink();
54+
if (state.isTerm()) {
55+
return null;
5656
} else if (alphabet.isInternalSymbol(input)) {
5757
if (state.isInit()) {
58-
return StackState.sink();
58+
return null;
5959
}
6060

6161
final DFA<S, I> model = state.getProcedure();
6262
final S next = model.getTransition(state.getCurrentState(), input);
6363

6464
// undefined internal transition
6565
if (next == null) {
66-
return StackState.sink();
66+
return null;
6767
}
6868

6969
return state.updateState(next);
7070
} else if (alphabet.isCallSymbol(input)) {
7171
if (state.isInit() && !Objects.equals(this.initialCall, input)) {
72-
return StackState.sink();
72+
return null;
7373
}
7474

7575
final DFA<S, I> model = this.procedures.get(input);
7676

7777
if (model == null) {
78-
return StackState.sink();
78+
return null;
7979
}
8080

8181
final S next = model.getInitialState();
8282

8383
if (next == null) {
84-
return StackState.sink();
84+
return null;
8585
}
8686

8787
// store the procedural successor in the stack so that we don't need to look it up on return symbols
@@ -91,28 +91,28 @@ public StackState<S, I, DFA<S, I>> getTransition(StackState<S, I, DFA<S, I>> sta
9191
} else {
9292
final S succ = state.getProcedure().getSuccessor(state.getCurrentState(), input);
9393
if (succ == null) {
94-
return StackState.sink();
94+
return null;
9595
}
9696
returnState = state.updateState(succ);
9797
}
9898

9999
return returnState.push(model, next);
100100
} else if (alphabet.isReturnSymbol(input)) {
101101
if (state.isInit()) {
102-
return StackState.sink();
102+
return null;
103103
}
104104

105105
// if we returned the state before, we checked that a procedure is available
106106
final DFA<S, I> model = state.getProcedure();
107107

108108
// cannot return, reject word
109109
if (!model.isAccepting(state.getCurrentState())) {
110-
return StackState.sink();
110+
return null;
111111
}
112112

113113
return state.pop();
114114
} else {
115-
return StackState.sink();
115+
return null;
116116
}
117117
}
118118

core/src/main/java/net/automatalib/automaton/procedural/impl/StackSPMM.java

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,39 +61,39 @@ public StackSPMM(ProceduralInputAlphabet<I> alphabet,
6161
}
6262

6363
@Override
64-
public MealyTransition<StackState<S, I, MealyMachine<S, I, T, O>>, O> getTransition(StackState<S, I, MealyMachine<S, I, T, O>> state,
65-
I input) {
66-
if (state.isSink() || state.isTerm()) {
67-
return sink();
64+
public @Nullable MealyTransition<StackState<S, I, MealyMachine<S, I, T, O>>, O> getTransition(StackState<S, I, MealyMachine<S, I, T, O>> state,
65+
I input) {
66+
if (state.isTerm()) {
67+
return null;
6868
} else if (alphabet.isInternalSymbol(input)) {
6969
if (state.isInit()) {
70-
return sink();
70+
return null;
7171
}
7272

7373
final MealyMachine<S, I, T, O> model = state.getProcedure();
7474
final T t = model.getTransition(state.getCurrentState(), input);
7575

7676
// undefined internal transition
7777
if (t == null || isErrorOutput(model.getTransitionOutput(t))) {
78-
return sink();
78+
return null;
7979
}
8080

8181
return new MealyTransition<>(state.updateState(model.getSuccessor(t)), model.getTransitionOutput(t));
8282
} else if (alphabet.isCallSymbol(input)) {
8383
if (state.isInit() && !Objects.equals(this.initialCall, input)) {
84-
return sink();
84+
return null;
8585
}
8686

8787
final MealyMachine<S, I, T, O> model = this.procedures.get(input);
8888

8989
if (model == null) {
90-
return sink();
90+
return null;
9191
}
9292

9393
final S next = model.getInitialState();
9494

9595
if (next == null) {
96-
return sink();
96+
return null;
9797
}
9898

9999
// store the procedural successor in the stack so that we don't need to look it up on return symbols
@@ -107,7 +107,7 @@ public MealyTransition<StackState<S, I, MealyMachine<S, I, T, O>>, O> getTransit
107107
final T t = p.getTransition(state.getCurrentState(), input);
108108

109109
if (t == null || isErrorOutput(p.getTransitionOutput(t))) {
110-
return sink();
110+
return null;
111111
}
112112
returnState = state.updateState(p.getSuccessor(t));
113113
output = p.getTransitionOutput(t);
@@ -116,20 +116,20 @@ public MealyTransition<StackState<S, I, MealyMachine<S, I, T, O>>, O> getTransit
116116
return new MealyTransition<>(returnState.push(model, next), output);
117117
} else if (alphabet.isReturnSymbol(input)) {
118118
if (state.isInit()) {
119-
return sink();
119+
return null;
120120
}
121121

122122
// if we returned the state before, we checked that a procedure is available
123123
final MealyMachine<S, I, T, O> model = state.getProcedure();
124124
final T t = model.getTransition(state.getCurrentState(), input);
125125

126126
if (t == null || isErrorOutput(model.getTransitionOutput(t))) {
127-
return sink();
127+
return null;
128128
}
129129

130130
return new MealyTransition<>(state.pop(), model.getTransitionOutput(t));
131131
} else {
132-
return sink();
132+
return null;
133133
}
134134
}
135135

@@ -168,8 +168,4 @@ public StackState<S, I, MealyMachine<S, I, T, O>> getSuccessor(MealyTransition<S
168168
return transition.getSuccessor();
169169
}
170170

171-
private MealyTransition<StackState<S, I, MealyMachine<S, I, T, O>>, O> sink() {
172-
return new MealyTransition<>(StackState.sink(), errorOutput);
173-
}
174-
175171
}

core/src/main/java/net/automatalib/automaton/procedural/impl/StackState.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
public final class StackState<S, I, P> {
3333

3434
private static final StackState<?, ?, ?> INIT = new StackState<>();
35-
private static final StackState<?, ?, ?> SINK = new StackState<>();
3635
private static final StackState<?, ?, ?> TERM = new StackState<>();
3736

3837
private final @Nullable StackState<S, I, P> prev;
@@ -75,15 +74,6 @@ S getCurrentState() {
7574
return procedureState;
7675
}
7776

78-
@SuppressWarnings("unchecked")
79-
static <I, S, P> StackState<S, I, P> sink() {
80-
return (StackState<S, I, P>) SINK;
81-
}
82-
83-
boolean isSink() {
84-
return this == SINK;
85-
}
86-
8777
@SuppressWarnings("unchecked")
8878
static <I, S, P> StackState<S, I, P> init() {
8979
return (StackState<S, I, P>) INIT;
@@ -106,7 +96,7 @@ boolean isTerm() {
10696
@SuppressWarnings("contracts.conditional.postcondition")
10797
@EnsuresNonNullIf(expression = {"this.prev", "this.procedure", "this.procedureState"}, result = false)
10898
private boolean isStatic() {
109-
return isInit() || isTerm() || isSink();
99+
return isInit() || isTerm();
110100
}
111101

112102
}

0 commit comments

Comments
 (0)