> newStateNodes = new UnorderedCollection<>();
do {
- while ((next = openTransitions.poll()) != null) {
- DTNode newStateNode = closeTransition(next, false);
- if (newStateNode != null) {
- newStateNodes.add(newStateNode);
- }
- }
+ newStateNodes.addAll(closeTransitions(openTransitions, false));
if (!newStateNodes.isEmpty()) {
addNewStates(newStateNodes);
}
@@ -145,22 +144,45 @@ protected void closeTransitions() {
}
/**
- * Ensures that the specified transition points to a leaf-node. If the transition is a tree transition, this method
+ * Ensures that the specified transitions point to a leaf-node. If a transition is a tree transition, this method
* has no effect.
+ *
+ * The provided transList is consumed in this process.
+ *
+ * If a transition needs sifting, the reached leaf node will be collected in the returned collection.
*
- * @param trans
- * the transition
+ * @param transList
+ * the list of transitions
+ *
+ * @return a collection containing the reached leaves of transitions that needed sifting
*/
- private DTNode closeTransition(AbstractHypTrans trans, boolean hard) {
- if (trans.isTree()) {
- return null;
+ private List> closeTransitions(TransList transList, boolean hard) {
+
+ final List> transToSift = new ArrayList<>(transList.size());
+
+ AbstractHypTrans t;
+ while ((t = transList.poll()) != null) {
+ if (!t.isTree()) {
+ transToSift.add(t);
+ }
}
- DTNode node = updateDTTarget(trans, hard);
- if (node.isLeaf() && node.getData() == null && trans.getNextElement() == null) {
- return node;
+ if (transToSift.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ final Iterator> leavesIter = updateDTTargets(transToSift, hard).iterator();
+ final List> result = new ArrayList<>(transToSift.size());
+
+ for (final AbstractHypTrans transition : transToSift) {
+ final DTNode node = leavesIter.next();
+ if (node.isLeaf() && node.getData() == null && transition.getNextElement() == null) {
+ result.add(node);
+ }
}
- return null;
+
+ assert !leavesIter.hasNext();
+ return result;
}
private void addNewStates(UnorderedCollection> newStateNodes) {
@@ -190,20 +212,40 @@ private void addNewStates(UnorderedCollection> newStateNodes) {
initializeLocation(newLoc);
}
- protected DTNode updateDTTarget(AbstractHypTrans trans, boolean hard) {
- if (trans.isTree()) {
- return trans.getTargetNode();
+ protected List> updateDTTargets(List> trans, boolean hard) {
+
+ final List> nodes = new ArrayList<>(trans.size());
+ final List> prefixes = new ArrayList<>(trans.size());
+
+ for (final AbstractHypTrans t : trans) {
+ if (!t.isTree()) {
+ DTNode start = t.getNonTreeTarget();
+
+ if (start == null) {
+ t.setNonTreeTarget(dtree.getRoot());
+ start = dtree.getRoot();
+ }
+
+ nodes.add(start);
+ prefixes.add(t.getAccessSequence());
+ }
}
- DTNode start = trans.getNonTreeTarget();
- if (start == null) {
- trans.setNonTreeTarget(dtree.getRoot());
- start = dtree.getRoot();
+ final Iterator> leavesIter = dtree.sift(nodes, prefixes, hard).iterator();
+ final List> result = new ArrayList<>(trans.size());
+
+ for (final AbstractHypTrans t : trans) {
+ if (t.isTree()) {
+ result.add(t.getTargetNode());
+ } else {
+ final DTNode leaf = leavesIter.next();
+ t.setNonTreeTarget(leaf);
+ leaf.addIncoming(t);
+ result.add(leaf);
+ }
}
- DTNode result = dtree.sift(start, trans, hard);
- trans.setNonTreeTarget(result);
- result.addIncoming(trans);
+ assert !leavesIter.hasNext();
return result;
}
diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/DTLearnerVPDA.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/DTLearnerVPDA.java
index 89d8d85249..b8254c1ed3 100644
--- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/DTLearnerVPDA.java
+++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/DTLearnerVPDA.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2018 TU Dortmund
+/* Copyright (C) 2013-2019 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/algorithms/active/discrimination-tree-vpda/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java b/algorithms/active/discrimination-tree-vpda/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java
index aa66e43a55..d5dc388f62 100644
--- a/algorithms/active/discrimination-tree-vpda/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java
+++ b/algorithms/active/discrimination-tree-vpda/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2018 TU Dortmund
+/* Copyright (C) 2013-2019 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/algorithms/active/discrimination-tree/pom.xml b/algorithms/active/discrimination-tree/pom.xml
index 874407f2d5..1ea731b0c8 100644
--- a/algorithms/active/discrimination-tree/pom.xml
+++ b/algorithms/active/discrimination-tree/pom.xml
@@ -1,6 +1,6 @@
-
4.0.0
- learnlib-algorithms-active-parent
de.learnlib
- 0.13.1
+ learnlib-algorithms-active-parent
+ 0.14.0
../pom.xml
learnlib-discrimination-tree
+
LearnLib :: Algorithms :: Discrimination Tree
A learning algorithm, which distinguishes hypothesis states using a discrimination tree.
@@ -58,7 +58,7 @@ limitations under the License.
net.automatalib
- automata-commons-util
+ automata-commons-smartcollections
@@ -71,12 +71,10 @@ limitations under the License.
org.testng
testng
- test
de.learnlib.testsupport
learnlib-learner-it-support
- test
de.learnlib
diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java
index 3a37bc0ceb..e59e5c018b 100644
--- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java
+++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2018 TU Dortmund
+/* Copyright (C) 2013-2019 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,9 +23,8 @@
import de.learnlib.algorithms.discriminationtree.hypothesis.DTLearnerHypothesis;
import de.learnlib.algorithms.discriminationtree.hypothesis.HState;
import de.learnlib.algorithms.discriminationtree.hypothesis.HTransition;
+import de.learnlib.api.Resumable;
import de.learnlib.api.algorithm.LearningAlgorithm;
-import de.learnlib.api.algorithm.feature.ResumableLearner;
-import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet;
import de.learnlib.api.oracle.MembershipOracle;
import de.learnlib.api.query.DefaultQuery;
import de.learnlib.api.query.Query;
@@ -34,17 +33,17 @@
import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode;
import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree;
import de.learnlib.util.MQUtil;
+import net.automatalib.SupportsGrowingAlphabet;
import net.automatalib.automata.concepts.SuffixOutput;
+import net.automatalib.exception.GrowingAlphabetNotSupportedException;
import net.automatalib.words.Alphabet;
import net.automatalib.words.Word;
import net.automatalib.words.impl.Alphabets;
public abstract class AbstractDTLearner, I, D, SP, TP>
- implements LearningAlgorithm,
- SupportsGrowingAlphabet,
- ResumableLearner> {
+ implements LearningAlgorithm, SupportsGrowingAlphabet, Resumable> {
- protected Alphabet alphabet;
+ protected final Alphabet alphabet;
private final MembershipOracle oracle;
private final LocalSuffixFinder super I, ? super D> suffixFinder;
private final boolean repeatedCounterexampleEvaluation;
@@ -69,7 +68,7 @@ protected AbstractDTLearner(Alphabet alphabet,
@Override
public void startLearning() {
- HState init = hypothesis.getInitialState();
+ HState init = hypothesis.createInitialState();
AbstractWordBasedDTNode> initDt = dtree.sift(init.getAccessSequence());
if (initDt.getData() != null) {
throw new IllegalStateException("Decision tree already contains data");
@@ -149,9 +148,8 @@ protected void initializeState(HState newState) {
}
protected void updateHypothesis() {
- HTransition current;
- while ((current = openTransitions.poll()) != null) {
- updateTransition(current);
+ while (!openTransitions.isEmpty()) {
+ updateTransitions();
}
List> queries = new ArrayList<>();
@@ -174,22 +172,37 @@ protected void updateHypothesis() {
oracle.processQueries(queries);
}
- protected void updateTransition(HTransition trans) {
- if (trans.isTree()) {
- return;
+ protected void updateTransitions() {
+ final List> transitionsToSift = new ArrayList<>(openTransitions.size());
+ final List>> nodes = new ArrayList<>(openTransitions.size());
+ final List> prefixes = new ArrayList<>(openTransitions.size());
+
+ for (HTransition t : openTransitions) {
+ if (!t.isTree()) {
+ transitionsToSift.add(t);
+ nodes.add(t.getDT());
+ prefixes.add(t.getAccessSequence());
+ }
}
- AbstractWordBasedDTNode> currDt = trans.getDT();
- currDt = dtree.sift(currDt, trans.getAccessSequence());
- trans.setDT(currDt);
-
- HState state = currDt.getData();
- if (state == null) {
- state = createState(trans);
- currDt.setData(state);
- state.setDTLeaf(currDt);
- } else {
- state.addNonTreeIncoming(trans);
+ openTransitions.clear();
+
+ final List>> results = dtree.sift(nodes, prefixes);
+
+ for (int i = 0; i < transitionsToSift.size(); i++) {
+ final HTransition trans = transitionsToSift.get(i);
+ final AbstractWordBasedDTNode> currDt = results.get(i);
+
+ trans.setDT(currDt);
+
+ HState state = currDt.getData();
+ if (state == null) {
+ state = createState(trans);
+ currDt.setData(state);
+ state.setDTLeaf(currDt);
+ } else {
+ state.addNonTreeIncoming(trans);
+ }
}
}
@@ -214,30 +227,29 @@ public DTLearnerHypothesis getHypothesisDS() {
}
@Override
- public void addAlphabetSymbol(I symbol) {
+ public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException {
- if (this.alphabet.containsSymbol(symbol)) {
- return;
+ if (!this.alphabet.containsSymbol(symbol)) {
+ Alphabets.toGrowingAlphabetOrThrowException(this.alphabet).addSymbol(symbol);
}
- final int newSymbolIdx = this.alphabet.size();
-
this.hypothesis.addAlphabetSymbol(symbol);
- // since we share the alphabet instance with our hypothesis, our alphabet might have already been updated (if it
- // was already a GrowableAlphabet)
- if (!this.alphabet.containsSymbol(symbol)) {
- this.alphabet = Alphabets.withNewSymbol(this.alphabet, symbol);
- }
+ // check if we already have information about the symbol (then the transition is defined) so we don't post
+ // redundant queries
+ if (this.hypothesis.getInitialState() != null &&
+ this.hypothesis.getSuccessor(this.hypothesis.getInitialState(), symbol) == null) {
+ final int newSymbolIdx = this.alphabet.getSymbolIndex(symbol);
+
+ for (final HState s : this.hypothesis.getStates()) {
+ final HTransition newTrans = new HTransition<>(s, symbol, dtree.getRoot());
+ s.setTransition(newSymbolIdx, newTrans);
+ newTransitions.add(newTrans);
+ openTransitions.add(newTrans);
+ }
- for (final HState s : this.hypothesis.getStates()) {
- final HTransition newTrans = new HTransition<>(s, symbol, dtree.getRoot());
- s.setTransition(newSymbolIdx, newTrans);
- newTransitions.add(newTrans);
- openTransitions.add(newTrans);
+ this.updateHypothesis();
}
-
- this.updateHypothesis();
}
@Override
@@ -252,7 +264,11 @@ public void resume(DTLearnerState state) {
this.dtree.setOracle(oracle);
}
- public static class BuilderDefaults {
+ public static final class BuilderDefaults {
+
+ private BuilderDefaults() {
+ // prevent instantiation
+ }
public static LocalSuffixFinder super I, ? super O> suffixFinder() {
return LocalSuffixFinders.RIVEST_SCHAPIRE;
diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/DTLearnerState.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/DTLearnerState.java
index 707448b107..af05e84580 100644
--- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/DTLearnerState.java
+++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/DTLearnerState.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2018 TU Dortmund
+/* Copyright (C) 2013-2019 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/DTLearnerDFA.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/DTLearnerDFA.java
index 18175b75d6..7b1b74ae28 100644
--- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/DTLearnerDFA.java
+++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/DTLearnerDFA.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2018 TU Dortmund
+/* Copyright (C) 2013-2019 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -95,7 +95,11 @@ public void resume(DTLearnerState state) {
this.hypWrapper = new HypothesisWrapperDFA<>(this.hypothesis);
}
- public static class BuilderDefaults {
+ public static final class BuilderDefaults {
+
+ private BuilderDefaults() {
+ // prevent instantiation
+ }
public static boolean epsilonRoot() {
return true;
diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java
index 06602fd2f7..bfbd31c907 100644
--- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java
+++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2018 TU Dortmund
+/* Copyright (C) 2013-2019 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/DTLearnerHypothesis.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/DTLearnerHypothesis.java
index d43ece67ee..a7d2ebcedd 100644
--- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/DTLearnerHypothesis.java
+++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/DTLearnerHypothesis.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2018 TU Dortmund
+/* Copyright (C) 2013-2019 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@
import java.util.Map;
import de.learnlib.api.AccessSequenceTransformer;
-import net.automatalib.automata.GrowableAlphabetAutomaton;
+import net.automatalib.SupportsGrowingAlphabet;
import net.automatalib.automata.UniversalDeterministicAutomaton;
import net.automatalib.automata.concepts.StateIDs;
import net.automatalib.graphs.Graph;
@@ -52,21 +52,27 @@ public class DTLearnerHypothesis
implements UniversalDeterministicAutomaton, I, HTransition, SP, TP>,
AccessSequenceTransformer,
StateIDs>,
- GrowableAlphabetAutomaton,
+ SupportsGrowingAlphabet,
Serializable {
- private Alphabet alphabet;
- private final HState root;
+ private final Alphabet alphabet;
+ private int alphabetSize;
+ private HState root;
private final List> nodes = new ArrayList<>();
public DTLearnerHypothesis(Alphabet alphabet) {
this.alphabet = alphabet;
- this.root = new HState<>(alphabet.size());
+ this.alphabetSize = this.alphabet.size();
+ }
+
+ public HState createInitialState() {
+ this.root = new HState<>(alphabetSize);
this.nodes.add(root);
+ return this.root;
}
public HState createState(HTransition treeIncoming) {
- HState state = new HState<>(alphabet.size(), nodes.size(), treeIncoming);
+ HState state = new HState<>(alphabetSize, nodes.size(), treeIncoming);
nodes.add(state);
treeIncoming.makeTree(state);
return state;
@@ -131,15 +137,18 @@ public HState getSuccessor(HTransition trans) {
@Override
public void addAlphabetSymbol(I symbol) {
- if (this.alphabet.containsSymbol(symbol)) {
- return;
+ if (!this.alphabet.containsSymbol(symbol)) {
+ Alphabets.toGrowingAlphabetOrThrowException(this.alphabet).addSymbol(symbol);
}
- this.alphabet = Alphabets.withNewSymbol(this.alphabet, symbol);
- final int alphabetSize = this.alphabet.size();
+ final int newAlphabetSize = this.alphabet.size();
+
+ if (alphabetSize < newAlphabetSize) {
+ for (final HState s : this.getStates()) {
+ s.ensureInputCapacity(newAlphabetSize);
+ }
- for (final HState s : this.getStates()) {
- s.ensureInputCapacity(alphabetSize);
+ this.alphabetSize = newAlphabetSize;
}
}
diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HState.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HState.java
index 1b76e6491b..777c91f25a 100644
--- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HState.java
+++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HState.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2018 TU Dortmund
+/* Copyright (C) 2013-2019 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@
import java.util.List;
import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode;
-import net.automatalib.commons.util.array.ResizingObjectArray;
+import net.automatalib.commons.smartcollections.ResizingArrayStorage;
import net.automatalib.words.Word;
import net.automatalib.words.WordBuilder;
@@ -32,7 +32,7 @@ public class HState implements Serializable {
private final HTransition treeIncoming;
private final int id;
private final int depth;
- private final ResizingObjectArray transitions;
+ private final ResizingArrayStorage