From b6795d9d789d19470f074173a0edfdc04f27b451 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 8 Feb 2018 12:10:57 +0100 Subject: [PATCH 001/125] bump automatalib version to 0.8.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b4e2fc79d3..b0c791b4b6 100644 --- a/pom.xml +++ b/pom.xml @@ -187,7 +187,7 @@ limitations under the License. 1.1 - 0.7.0 + 0.8.0-SNAPSHOT 0.1 8.1 3.0.2 From 183f0a55bddaabd324781fbd5f1967272970fd91 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 13 Feb 2018 20:53:59 +0100 Subject: [PATCH 002/125] travis: add (experimental) configuration for continuous deployment --- .travis.yml | 48 +++++++++++++++++++++------------ build-tools/travis-settings.xml | 39 +++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 build-tools/travis-settings.xml diff --git a/.travis.yml b/.travis.yml index e27956f34e..e2204c15e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,30 +1,44 @@ language: java + sudo: false dist: trusty + jdk: - oraclejdk8 - openjdk8 -# disable caching for now, because it breaks reporting to coveralls -# see https://github.com/travis-ci/travis-ci/issues/8208#issuecomment-349240845 -#cache: -# directories: -# - $HOME/.m2 -#before_cache: -# # do not cache our local archives -# - rm -rf $HOME/.m2/repository/net/automatalib/ -# - rm -rf $HOME/.m2/repository/de/learnlib/ + +cache: + directories: + - $HOME/.m2 + +before_cache: + # do not cache our local archives + - rm -rf $HOME/.m2/repository/net/automatalib/ + - rm -rf $HOME/.m2/repository/de/learnlib/ + branches: only: - master - develop -before_install: - - git clone -b develop --single-branch https://github.com/LearnLib/automatalib.git /tmp/automatalib-develop - - pushd /tmp/automatalib-develop - # skip several aspects of the build process, because we are only interested in the compiled code - - mvn install -DskipTests -Dmaven.javadoc.skip=true - - popd + +pre_install: + - cp build-tools/travis-settings.xml $HOME/.m2/settings.xml + install: true # skip mvn install, because we essentially run the same command in the script routine + script: - mvn install -B -Pintegration-tests,code-analysis,code-coverage,bundles -after_success: - - mvn coveralls:report + - mvn coveralls:report + +jobs: + include: + - stage: deploy + jdk: openjdk8 # use openjdk build + install: true # skip the normal build + script: skip # skip the normal build + deploy: + # define deployment in deploy phase, which is skipped for pull-requests + provider: script + script: mvn -DskipTests=true deploy + on: + branch: develop # only auto deploy snapshots diff --git a/build-tools/travis-settings.xml b/build-tools/travis-settings.xml new file mode 100644 index 0000000000..8fc46b2ca8 --- /dev/null +++ b/build-tools/travis-settings.xml @@ -0,0 +1,39 @@ + + + false + + + + travis-automatalib-snapshot + + + sonatype-snapshots + Sonatype Snapshots + + https://oss.sonatype.org/content/repositories/snapshots + + + false + + + true + + + + + + + + travis-automatalib-snapshot + + + + + ossrh + ${env.OSSRH_TOKEN_USERNAME} + ${env.OSSRH_TOKEN_PASSWORD} + + + From 705b246935120aaf8243c1a8aab8ef705a2200c4 Mon Sep 17 00:00:00 2001 From: mtf90 Date: Tue, 13 Feb 2018 21:41:39 +0100 Subject: [PATCH 003/125] Update README.md add information about continuous deployment [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 66a7118146..9ba64f2238 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,8 @@ Note, that LearnLib requires Java 8. #### Building development versions -If you intend to use development versions of LearnLib, simply clone the development branch of the repository +If you intend to use development versions of LearnLib, you can either use the deployed SNAPSHOT artifacts from the continuous integration server (see [Using Development Versions](https://github.com/LearnLib/learnlib/wiki/Using-Development-Versions)), or build them yourself. +Simply clone the development branch of the repository ``` git clone -b develop --single-branch https://github.com/LearnLib/learnlib.git From b3c7d6bc6b3dbc79551843054d492190aaa70d01 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 13 Feb 2018 21:49:36 +0100 Subject: [PATCH 004/125] add artifact description to distribution module [skip ci] --- distribution/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/distribution/pom.xml b/distribution/pom.xml index 71406580ed..c6d5638dc8 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -29,6 +29,13 @@ limitations under the License. pom LearnLib :: Distribution + + An afrtifact that aggregates all other artifacts of LearnLib to produce an Uber-JAR that can be used in + non-maven environments. Likewise, this single artifact may be used in maven-aware environments to declare a + dependency on all LearnLib artifacts. + + + @@ -58,6 +62,10 @@ limitations under the License. net.automatalib automata-incremental + + net.automatalib + automata-util + @@ -76,7 +84,6 @@ limitations under the License. testng - de.learnlib.testsupport @@ -84,12 +91,12 @@ limitations under the License. de.learnlib - learnlib-membership-oracles + learnlib-statistics test de.learnlib - learnlib-statistics + learnlib-drivers-simulator test diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java index ad4ca1afaa..b205e4e6ea 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java @@ -52,26 +52,11 @@ public class DFACacheOracle implements DFALearningCacheOracle { private final Lock incDfaLock; private final MembershipOracle delegate; - /** - * Constructor. - * - * @param alphabet - * the alphabet of the cache - * @param delegate - * the delegate oracle - * - * @deprecated since 2014-01-24. Use {@link DFACaches#createCache(Alphabet, MembershipOracle)} - */ - @Deprecated - public DFACacheOracle(Alphabet alphabet, MembershipOracle delegate) { - this(new IncrementalDFADAGBuilder<>(alphabet), delegate); - } - - public DFACacheOracle(IncrementalDFABuilder incDfa, MembershipOracle delegate) { + DFACacheOracle(IncrementalDFABuilder incDfa, MembershipOracle delegate) { this(incDfa, new ReentrantLock(), delegate); } - private DFACacheOracle(IncrementalDFABuilder incDfa, Lock lock, MembershipOracle delegate) { + DFACacheOracle(IncrementalDFABuilder incDfa, Lock lock, MembershipOracle delegate) { this.incDfa = incDfa; this.incDfaLock = lock; this.delegate = delegate; diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java index ad791eadee..3f7fb8d4ab 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java @@ -65,52 +65,16 @@ public class MealyCacheOracle implements MealyLearningCacheOracle { private final Comparator> queryCmp; private final Mapping errorSyms; - /** - * Constructor. - * - * @param alphabet - * the input alphabet for the cache - * @param delegate - * the delegate Mealy oracle - * - * @deprecated since 2014-01-23. Use {@link #createDAGCacheOracle(Alphabet, MembershipOracle)} to reproduce old - * behavior. - */ - @Deprecated - public MealyCacheOracle(Alphabet alphabet, MembershipOracle> delegate) { - this(alphabet, null, delegate); - } - - /** - * Constructor. - * - * @param alphabet - * the input alphabet for the cache - * @param errorSyms - * the error symbol mapping (see class description) - * @param delegate - * the delegate Mealy oracle - * - * @deprecated since 2014-01-23. Use {@link #createDAGCacheOracle(Alphabet, Mapping, MembershipOracle)} to reproduce - * old behavior. - */ - @Deprecated - public MealyCacheOracle(Alphabet alphabet, - Mapping errorSyms, - MembershipOracle> delegate) { - this(new IncrementalMealyDAGBuilder<>(alphabet), errorSyms, delegate); - } - - public MealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, - Mapping errorSyms, - MembershipOracle> delegate) { + MealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, + Mapping errorSyms, + MembershipOracle> delegate) { this(incrementalBuilder, new ReentrantLock(), errorSyms, delegate); } - public MealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, - Lock lock, - Mapping errorSyms, - MembershipOracle> delegate) { + MealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, + Lock lock, + Mapping errorSyms, + MembershipOracle> delegate) { this.incMealy = incrementalBuilder; this.incMealyLock = lock; this.queryCmp = new ReverseLexCmp<>(incrementalBuilder.getInputAlphabet()); @@ -206,7 +170,7 @@ public void processQueries(Collection>> queries) { } private MasterQuery createMasterQuery(Word word) { - WordBuilder wb = new WordBuilder<>(); + WordBuilder wb = new WordBuilder<>(word.size()); if (incMealy.lookup(word, wb)) { return new MasterQuery<>(word, wb.toWord()); } diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/SymbolQueryCache.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/SymbolQueryCache.java index 21686f324d..a0d3f9be2f 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/SymbolQueryCache.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/SymbolQueryCache.java @@ -16,12 +16,19 @@ package de.learnlib.filter.cache.mealy; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.oracle.SymbolQueryOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; +import net.automatalib.automata.transout.MealyMachine; import net.automatalib.automata.transout.impl.FastMealy; import net.automatalib.automata.transout.impl.FastMealyState; +import net.automatalib.util.automata.equivalence.NearLinearEquivalenceTest; import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; /** * A cache for a {@link SymbolQueryOracle}. Upon construction, it is provided with a delegate oracle. Queries that can @@ -37,8 +44,7 @@ * * @author frohme */ -// TODO: integrate in existing LearningCache hierarchy -public class SymbolQueryCache implements SymbolQueryOracle { +public class SymbolQueryCache implements SymbolQueryOracle, MealyLearningCacheOracle { private final FastMealy cache; private final SymbolQueryOracle delegate; @@ -101,4 +107,24 @@ public void reset() { this.currentTrace.clear(); this.currentTraceValid = true; } + + @Override + public EquivalenceOracle, I, Word> createCacheConsistencyTest() { + return this::findCounterexample; + } + + private DefaultQuery> findCounterexample(MealyMachine hypothesis, + Collection alphabet) { + /* + TODO: potential optimization: If the hypothesis has undefined transitions, but the cache doesn't, it is a clear + counterexample! + */ + final Word sepWord = NearLinearEquivalenceTest.findSeparatingWord(cache, hypothesis, alphabet, true); + + if (sepWord != null) { + return new DefaultQuery<>(sepWord, cache.computeOutput(sepWord)); + } + + return null; + } } diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCache.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCache.java index f8197809c8..5ca8e52d68 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCache.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCache.java @@ -15,6 +15,7 @@ */ package de.learnlib.filter.cache.sul; +import java.util.Collection; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -23,13 +24,16 @@ import javax.annotation.ParametersAreNonnullByDefault; import de.learnlib.api.SUL; -import de.learnlib.filter.cache.LearningCache; +import de.learnlib.api.query.Query; +import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; import de.learnlib.filter.cache.mealy.MealyCacheConsistencyTest; +import de.learnlib.oracle.membership.SULOracle; import net.automatalib.incremental.mealy.IncrementalMealyBuilder; import net.automatalib.incremental.mealy.dag.IncrementalMealyDAGBuilder; import net.automatalib.incremental.mealy.tree.IncrementalMealyTreeBuilder; import net.automatalib.ts.transout.MealyTransitionSystem; import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; /** @@ -50,30 +54,15 @@ * @author Malte Isberner */ @ParametersAreNonnullByDefault -public class SULCache implements SUL, LearningCache.MealyLearningCache { +public class SULCache implements SUL, MealyLearningCacheOracle { private final SULCacheImpl impl; - /** - * Constructor. - * - * @param alphabet - * the input alphabet - * @param sul - * the system under learning - * - * @deprecated since 2014-01-24. Use {@link SULCaches#createCache(Alphabet, SUL)} - */ - @Deprecated - public SULCache(Alphabet alphabet, SUL sul) { - this(new IncrementalMealyDAGBuilder<>(alphabet), sul); - } - - public SULCache(IncrementalMealyBuilder incMealy, SUL sul) { + SULCache(IncrementalMealyBuilder incMealy, SUL sul) { this(incMealy, new ReentrantLock(), sul); } - public SULCache(IncrementalMealyBuilder incMealy, Lock lock, SUL sul) { + SULCache(IncrementalMealyBuilder incMealy, Lock lock, SUL sul) { this.impl = new SULCacheImpl<>(incMealy, lock, incMealy.asTransitionSystem(), sul); } @@ -105,6 +94,11 @@ public MealyCacheConsistencyTest createCacheConsistencyTest() { return impl.createCacheConsistencyTest(); } + @Override + public void processQueries(Collection>> queries) { + SULOracle.processQueries(impl, queries); + } + /** * Implementation class; we need this to bind the {@code T} and {@code S} type parameters of the transition system * returned by {@link IncrementalMealyBuilder#asTransitionSystem()}. @@ -121,7 +115,7 @@ public MealyCacheConsistencyTest createCacheConsistencyTest() { * @author Malte Isberner */ @ParametersAreNonnullByDefault - private static final class SULCacheImpl { + private static final class SULCacheImpl implements SUL, MealyLearningCache { private final IncrementalMealyBuilder incMealy; private final MealyTransitionSystem mealyTs; @@ -142,12 +136,14 @@ private static final class SULCacheImpl { this.incMealyLock = lock; } + @Override public void pre() { incMealyLock.lock(); this.current = mealyTs.getInitialState(); } @Nullable + @Override public O step(@Nullable I in) { O out = null; @@ -184,6 +180,7 @@ public O step(@Nullable I in) { // TODO: The SUL interface might need a cleanup() method which, by contract, // is to be called regardless of whether preceding step()s threw unrecoverable // errors! + @Override public void post() { try { if (outputWord != null) { @@ -207,6 +204,7 @@ public void post() { } @Nonnull + @Override public MealyCacheConsistencyTest createCacheConsistencyTest() { return new MealyCacheConsistencyTest<>(incMealy, incMealyLock); } diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SULOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SULOracle.java index 22929aafae..f989dc4063 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SULOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SULOracle.java @@ -65,7 +65,7 @@ public void processQueries(Collection>> queries) { } } - private static void processQueries(SUL sul, Collection>> queries) { + public static void processQueries(SUL sul, Collection>> queries) { for (Query> q : queries) { Word output = answerQuery(sul, q.getPrefix(), q.getSuffix()); q.answer(output); @@ -73,7 +73,7 @@ private static void processQueries(SUL sul, Collection Word answerQuery(SUL sul, Word prefix, Word suffix) throws SULException { + public static Word answerQuery(SUL sul, Word prefix, Word suffix) throws SULException { sul.pre(); try { // Prefix: Execute symbols, don't record output From 0f8c7e77cc6b1ef08fdd88e78b805a45aeeb0f28 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 23 Feb 2018 17:43:00 +0100 Subject: [PATCH 014/125] statistics: add counting wrapper for SymbolQueryOracles --- .../oracle/CounterSymbolQueryOracle.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterSymbolQueryOracle.java diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterSymbolQueryOracle.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterSymbolQueryOracle.java new file mode 100644 index 0000000000..45dbb50aa8 --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterSymbolQueryOracle.java @@ -0,0 +1,62 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.statistic.oracle; + +import java.util.concurrent.atomic.AtomicLong; + +import de.learnlib.api.oracle.SymbolQueryOracle; + +/** + * A simple wrapper for counting the number of {@link SymbolQueryOracle#reset() resets} and + * {@link SymbolQueryOracle#query(Object) symbol queries} of a {@link SymbolQueryOracle}. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +public class CounterSymbolQueryOracle implements SymbolQueryOracle { + + private final SymbolQueryOracle delegate; + private final AtomicLong resetCounter = new AtomicLong(); + private final AtomicLong symbolCounter = new AtomicLong(); + + public CounterSymbolQueryOracle(SymbolQueryOracle delegate) { + this.delegate = delegate; + } + + @Override + public O query(I i) { + symbolCounter.incrementAndGet(); + return delegate.query(i); + } + + @Override + public void reset() { + resetCounter.incrementAndGet(); + delegate.reset(); + } + + public long getResetCount() { + return resetCounter.get(); + } + + public long getSymbolCount() { + return symbolCounter.get(); + } +} From 2da89aebf31357cb23c2da2986f3ff59c43ac22c Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 23 Feb 2018 17:44:17 +0100 Subject: [PATCH 015/125] cache: add various unit tests for caches --- .../filter/cache/AbstractCacheTest.java | 153 ++++++++++++++++++ .../learnlib/filter/cache/CacheTestUtils.java | 57 +++++++ .../filter/cache/DFACacheOracleTest.java | 109 ------------- .../cache/dfa/AbstractDFACacheTest.java | 71 ++++++++ .../filter/cache/dfa/DFADAGCacheTest.java | 29 ++++ .../filter/cache/dfa/DFAHashCacheTest.java | 30 ++++ .../filter/cache/dfa/DFATreeCacheTest.java | 29 ++++ .../cache/mealy/AbstractMealyCacheTest.java | 83 ++++++++++ .../filter/cache/mealy/MealyDAGCacheTest.java | 29 ++++ .../cache/mealy/MealyDAGMapperCacheTest.java | 29 ++++ .../cache/mealy/MealyTreeCacheTest.java | 29 ++++ .../cache/mealy/MealyTreeMapperCacheTest.java | 29 ++++ .../cache/mealy/SymbolQueryCacheTest.java | 70 ++++++++ .../cache/sul/AbstractSULCacheTest.java | 72 +++++++++ .../filter/cache/sul/SULDAGCacheTest.java | 30 ++++ .../filter/cache/sul/SULTreeCacheTest.java | 30 ++++ 16 files changed, 770 insertions(+), 109 deletions(-) create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/AbstractCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/CacheTestUtils.java delete mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/DFACacheOracleTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/AbstractDFACacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFADAGCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFAHashCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFATreeCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/AbstractMealyCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGMapperCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeMapperCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/SymbolQueryCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/AbstractSULCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULDAGCacheTest.java create mode 100644 oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULTreeCacheTest.java diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/AbstractCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/AbstractCacheTest.java new file mode 100644 index 0000000000..486ea27bd8 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/AbstractCacheTest.java @@ -0,0 +1,153 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.Query; +import net.automatalib.automata.concepts.Output; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * A simple test against various cache implementations. + * + * @author Oliver Bauer + * @author frohme + */ +public abstract class AbstractCacheTest, I, D> { + + private static final int LENGTH = 5; + private Random random = new Random(42); + private Alphabet alphabet; + private LearningCacheOracle oracle; + private List> queries; + + @BeforeClass + public void setup() { + alphabet = getAlphabet(); + oracle = getCachedOracle(); + queries = new ArrayList<>(); + } + + @Test + public void testNoQueriesReceived() { + Assert.assertEquals(queries.size(), 0); + oracle.processQueries(queries); + Assert.assertEquals(getNumberOfPosedQueries(), 0); + } + + @Test(dependsOnMethods = {"testNoQueriesReceived"}) + public void testFirstQuery() { + queries.add(new DefaultQuery<>(generateWord())); + + Assert.assertEquals(queries.size(), 1); + oracle.processQueries(queries); + Assert.assertEquals(getNumberOfPosedQueries(), 1); + } + + @Test(dependsOnMethods = {"testFirstQuery"}) + public void testFirstDuplicate() { + Assert.assertEquals(queries.size(), 1); + oracle.processQueries(queries); + Assert.assertEquals(getNumberOfPosedQueries(), 1); + } + + @Test(dependsOnMethods = {"testFirstDuplicate"}) + public void testTwoQueriesOneDuplicate() { + queries.add(new DefaultQuery<>(generateWord())); + Assert.assertEquals(queries.size(), 2); + oracle.processQueries(queries); + Assert.assertEquals(getNumberOfPosedQueries(), 2); + } + + @Test(dependsOnMethods = {"testTwoQueriesOneDuplicate"}) + public void testOneNewQuery() { + queries.clear(); + queries.add(new DefaultQuery<>(generateWord())); + oracle.processQueries(queries); + + Assert.assertEquals(getNumberOfPosedQueries(), 3); + } + + @Test(dependsOnMethods = {"testOneNewQuery"}) + public void testPrefix() { + Assert.assertFalse(queries.isEmpty()); + + final Word firstQueryInput = queries.get(0).getInput(); + final Word prefix = firstQueryInput.prefix(firstQueryInput.size() - 1); + final long oldCount = getNumberOfPosedQueries(); + + queries.add(new DefaultQuery<>(prefix)); + oracle.processQueries(queries); + + if (supportsPrefixes()) { + Assert.assertEquals(getNumberOfPosedQueries(), oldCount); + } else { + Assert.assertEquals(getNumberOfPosedQueries(), oldCount + 1); + } + } + + @Test(dependsOnMethods = {"testPrefix"}) + public void testCacheConsistency() { + + final EquivalenceOracle eqOracle = oracle.createCacheConsistencyTest(); + final A target = getTargetModel(); + final A invalidTarget = getInvalidTargetModel(); + + final DefaultQuery targetCE = eqOracle.findCounterExample(target, getAlphabet()); + final DefaultQuery invalidTargetCE = eqOracle.findCounterExample(invalidTarget, getAlphabet()); + + Assert.assertNull(targetCE); + Assert.assertNotNull(invalidTargetCE); + + Assert.assertNotEquals(invalidTarget.computeOutput(invalidTargetCE.getInput()), + target.computeOutput(invalidTargetCE.getInput())); + } + + private Word generateWord() { + final WordBuilder result = new WordBuilder<>(LENGTH); + + for (int i = 0; i < LENGTH; ++i) { + int symidx = random.nextInt(alphabet.size()); + I sym = alphabet.getSymbol(symidx); + result.append(sym); + } + + return result.toWord(); + } + + protected abstract Alphabet getAlphabet(); + + protected abstract A getTargetModel(); + + protected abstract A getInvalidTargetModel(); + + protected abstract LearningCacheOracle getCachedOracle(); + + protected abstract long getNumberOfPosedQueries(); + + protected abstract boolean supportsPrefixes(); + +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/CacheTestUtils.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/CacheTestUtils.java new file mode 100644 index 0000000000..b8dca9deee --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/CacheTestUtils.java @@ -0,0 +1,57 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache; + +import java.util.Random; + +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * @author frohme + */ +public final class CacheTestUtils { + + public static final Alphabet INPUT_ALPHABET; + public static final Alphabet OUTPUT_ALPHABET; + + public static final CompactDFA DFA; + public static final CompactDFA DFA_INVALID; + public static final CompactMealy MEALY; + public static final CompactMealy MEALY_INVALID; + + static { + INPUT_ALPHABET = Alphabets.characters('a', 'c'); + OUTPUT_ALPHABET = Alphabets.integers(1, 3); + + final Random random = new Random(42); + final int size = 20; + DFA = RandomAutomata.randomDFA(random, size, INPUT_ALPHABET); + MEALY = RandomAutomata.randomMealy(random, size, INPUT_ALPHABET, OUTPUT_ALPHABET); + + DFA_INVALID = new CompactDFA<>(DFA); + DFA_INVALID.flipAcceptance(); + + // we rely on two generations not producing the same automaton + MEALY_INVALID = RandomAutomata.randomMealy(random, size, INPUT_ALPHABET, OUTPUT_ALPHABET); + } + + private CacheTestUtils() {} + +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/DFACacheOracleTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/DFACacheOracleTest.java deleted file mode 100644 index ae7f995d4f..0000000000 --- a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/DFACacheOracleTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.filter.cache; - -import java.util.ArrayList; -import java.util.Collection; - -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.Query; -import de.learnlib.examples.dfa.ExampleAngluin; -import de.learnlib.filter.cache.dfa.DFACacheOracle; -import de.learnlib.filter.statistic.oracle.CounterOracle; -import de.learnlib.oracle.membership.SimulatorOracle; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -/** - * A simple test against the {@link DFACacheOracle}. - * - * @author Oliver Bauer - */ -@SuppressWarnings("deprecation") -public class DFACacheOracleTest { - - private MembershipOracle oracle; - private CounterOracle counterOracle; - private Collection> queries; - - @BeforeClass - public void setup() { - // use angluin's example - ExampleAngluin exampleAngluin = ExampleAngluin.createExample(); - DFA fm = exampleAngluin.getReferenceAutomaton(); - Alphabet alphabet = exampleAngluin.getAlphabet(); - - // use simulated environment - SimulatorOracle simulatorOracle = new SimulatorOracle<>(fm); - - // we count the number of delegated queries from the cache to this - // counter to the simulator - counterOracle = new CounterOracle<>(simulatorOracle, "counterOracle"); - - // we query against the DFA cache, duplicate queries should be filtered - oracle = new DFACacheOracle<>(alphabet, counterOracle); - - queries = new ArrayList<>(); - } - - @Test - public void testNoQueriesReceived() { - Assert.assertTrue(queries.size() == 0); - oracle.processQueries(queries); - Assert.assertTrue(counterOracle.getCount() == 0); - } - - @Test(dependsOnMethods = {"testNoQueriesReceived"}) - public void testFirstQuery() { - queries.add(new DefaultQuery<>(Word.fromLetter(0))); - - Assert.assertTrue(queries.size() == 1); - oracle.processQueries(queries); - Assert.assertTrue(counterOracle.getCount() == 1); - } - - @Test(dependsOnMethods = {"testFirstQuery"}) - public void testFirstDuplicate() { - Assert.assertTrue(queries.size() == 1); - oracle.processQueries(queries); - Assert.assertTrue(counterOracle.getCount() == 1); - } - - @Test(dependsOnMethods = {"testFirstDuplicate"}) - public void testTwoQueriesOneDuplicate() { - queries.add(new DefaultQuery<>(Word.fromSymbols(0, 0))); - Assert.assertTrue(queries.size() == 2); - oracle.processQueries(queries); - Assert.assertTrue(counterOracle.getCount() == 2); - } - - @Test(dependsOnMethods = {"testTwoQueriesOneDuplicate"}) - public void testOneNewQuery() { - queries.clear(); - - Assert.assertTrue(queries.size() == 0); - queries.add(new DefaultQuery<>(Word.fromLetter(1))); - Assert.assertTrue(queries.size() == 1); - oracle.processQueries(queries); - long count = counterOracle.getCount(); - Assert.assertTrue(count == 3); - } -} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/AbstractDFACacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/AbstractDFACacheTest.java new file mode 100644 index 0000000000..71969f8d48 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/AbstractDFACacheTest.java @@ -0,0 +1,71 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.dfa; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.filter.cache.AbstractCacheTest; +import de.learnlib.filter.cache.CacheTestUtils; +import de.learnlib.filter.cache.LearningCacheOracle; +import de.learnlib.filter.cache.LearningCacheOracle.DFALearningCacheOracle; +import de.learnlib.filter.statistic.oracle.CounterOracle.DFACounterOracle; +import de.learnlib.oracle.membership.SimulatorOracle.DFASimulatorOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.words.Alphabet; + +/** + * @author frohme + */ +public abstract class AbstractDFACacheTest extends AbstractCacheTest, Character, Boolean> { + + private final DFACounterOracle counter; + + public AbstractDFACacheTest() { + counter = new DFACounterOracle<>(new DFASimulatorOracle<>(CacheTestUtils.DFA), "counterOracle"); + } + + @Override + protected DFA getTargetModel() { + return CacheTestUtils.DFA; + } + + @Override + protected DFA getInvalidTargetModel() { + return CacheTestUtils.DFA_INVALID; + } + + @Override + protected LearningCacheOracle, Character, Boolean> getCachedOracle() { + return getCache(counter); + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getCount(); + } + + @Override + protected boolean supportsPrefixes() { + return false; + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } + + protected abstract DFALearningCacheOracle getCache(DFAMembershipOracle delegate); + +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFADAGCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFADAGCacheTest.java new file mode 100644 index 0000000000..a9b430a813 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFADAGCacheTest.java @@ -0,0 +1,29 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.dfa; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; + +/** + * @author frohme + */ +public class DFADAGCacheTest extends AbstractDFACacheTest { + + @Override + protected DFACacheOracle getCache(DFAMembershipOracle delegate) { + return DFACaches.createCache(getAlphabet(), delegate); + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFAHashCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFAHashCacheTest.java new file mode 100644 index 0000000000..2efad65b39 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFAHashCacheTest.java @@ -0,0 +1,30 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.dfa; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.filter.cache.LearningCacheOracle.DFALearningCacheOracle; + +/** + * @author frohme + */ +public class DFAHashCacheTest extends AbstractDFACacheTest { + + @Override + protected DFALearningCacheOracle getCache(DFAMembershipOracle delegate) { + return DFACaches.createHashCache(delegate); + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFATreeCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFATreeCacheTest.java new file mode 100644 index 0000000000..b126582d50 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFATreeCacheTest.java @@ -0,0 +1,29 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.dfa; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; + +/** + * @author frohme + */ +public class DFATreeCacheTest extends AbstractDFACacheTest { + + @Override + protected DFACacheOracle getCache(DFAMembershipOracle delegate) { + return DFACaches.createTreeCache(getAlphabet(), delegate); + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/AbstractMealyCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/AbstractMealyCacheTest.java new file mode 100644 index 0000000000..9ffe0394cd --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/AbstractMealyCacheTest.java @@ -0,0 +1,83 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.mealy; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.filter.cache.AbstractCacheTest; +import de.learnlib.filter.cache.CacheTestUtils; +import de.learnlib.filter.cache.LearningCacheOracle; +import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; +import de.learnlib.filter.statistic.oracle.CounterOracle.MealyCounterOracle; +import de.learnlib.oracle.membership.SimulatorOracle.MealySimulatorOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public abstract class AbstractMealyCacheTest + extends AbstractCacheTest, Character, Word> { + + private final MealyCounterOracle counter; + protected final Mapping errorMapper; + + public AbstractMealyCacheTest() { + counter = new MealyCounterOracle<>(new MealySimulatorOracle<>(CacheTestUtils.MEALY), "counterOracle"); + errorMapper = o -> { + switch (o) { + case 1: { + return 10; + } + default: + return null; + } + }; + } + + @Override + protected MealyMachine getTargetModel() { + return CacheTestUtils.MEALY; + } + + @Override + protected MealyMachine getInvalidTargetModel() { + return CacheTestUtils.MEALY_INVALID; + } + + @Override + protected LearningCacheOracle, Character, Word> getCachedOracle() { + return getCache(counter); + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getCount(); + } + + @Override + protected boolean supportsPrefixes() { + return true; + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } + + protected abstract MealyLearningCacheOracle getCache(MealyMembershipOracle delegate); +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGCacheTest.java new file mode 100644 index 0000000000..39349f083d --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGCacheTest.java @@ -0,0 +1,29 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.mealy; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; + +/** + * @author frohme + */ +public class MealyDAGCacheTest extends AbstractMealyCacheTest { + + @Override + protected MealyCacheOracle getCache(MealyMembershipOracle delegate) { + return MealyCaches.createCache(getAlphabet(), delegate); + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGMapperCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGMapperCacheTest.java new file mode 100644 index 0000000000..dacdb5cea3 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGMapperCacheTest.java @@ -0,0 +1,29 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.mealy; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; + +/** + * @author frohme + */ +public class MealyDAGMapperCacheTest extends AbstractMealyCacheTest { + + @Override + protected MealyCacheOracle getCache(MealyMembershipOracle delegate) { + return MealyCaches.createDAGCache(getAlphabet(), super.errorMapper, delegate); + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeCacheTest.java new file mode 100644 index 0000000000..f7e857884b --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeCacheTest.java @@ -0,0 +1,29 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.mealy; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; + +/** + * @author frohme + */ +public class MealyTreeCacheTest extends AbstractMealyCacheTest { + + @Override + protected MealyCacheOracle getCache(MealyMembershipOracle delegate) { + return MealyCaches.createTreeCache(getAlphabet(), delegate); + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeMapperCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeMapperCacheTest.java new file mode 100644 index 0000000000..f1a36ea4df --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeMapperCacheTest.java @@ -0,0 +1,29 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.mealy; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; + +/** + * @author frohme + */ +public class MealyTreeMapperCacheTest extends AbstractMealyCacheTest { + + @Override + protected MealyCacheOracle getCache(MealyMembershipOracle delegate) { + return MealyCaches.createTreeCache(getAlphabet(), super.errorMapper, delegate); + } +} \ No newline at end of file diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/SymbolQueryCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/SymbolQueryCacheTest.java new file mode 100644 index 0000000000..7c5973ee5c --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/SymbolQueryCacheTest.java @@ -0,0 +1,70 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.mealy; + +import de.learnlib.driver.util.MealySimulatorSUL; +import de.learnlib.filter.cache.AbstractCacheTest; +import de.learnlib.filter.cache.CacheTestUtils; +import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; +import de.learnlib.filter.statistic.oracle.CounterSymbolQueryOracle; +import de.learnlib.oracle.membership.SULSymbolQueryOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class SymbolQueryCacheTest + extends AbstractCacheTest, Character, Word> { + + private final CounterSymbolQueryOracle counter; + + public SymbolQueryCacheTest() { + counter = + new CounterSymbolQueryOracle<>(new SULSymbolQueryOracle<>(new MealySimulatorSUL<>(CacheTestUtils.MEALY))); + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } + + @Override + protected MealyMachine getTargetModel() { + return CacheTestUtils.MEALY; + } + + @Override + protected MealyMachine getInvalidTargetModel() { + return CacheTestUtils.MEALY_INVALID; + } + + @Override + protected MealyLearningCacheOracle getCachedOracle() { + return new SymbolQueryCache<>(counter, getAlphabet()); + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getResetCount(); + } + + @Override + protected boolean supportsPrefixes() { + return true; + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/AbstractSULCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/AbstractSULCacheTest.java new file mode 100644 index 0000000000..ba4deff503 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/AbstractSULCacheTest.java @@ -0,0 +1,72 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.sul; + +import de.learnlib.api.SUL; +import de.learnlib.driver.util.MealySimulatorSUL; +import de.learnlib.filter.cache.AbstractCacheTest; +import de.learnlib.filter.cache.CacheTestUtils; +import de.learnlib.filter.cache.LearningCacheOracle; +import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; +import de.learnlib.filter.statistic.sul.ResetCounterSUL; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public abstract class AbstractSULCacheTest + extends AbstractCacheTest, Character, Word> { + + private final ResetCounterSUL counter; + + public AbstractSULCacheTest() { + counter = new ResetCounterSUL<>("counterOracle", new MealySimulatorSUL<>(CacheTestUtils.MEALY)); + } + + @Override + protected MealyMachine getTargetModel() { + return CacheTestUtils.MEALY; + } + + @Override + protected MealyMachine getInvalidTargetModel() { + return CacheTestUtils.MEALY_INVALID; + } + + @Override + protected LearningCacheOracle, Character, Word> getCachedOracle() { + return getCache(counter); + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getStatisticalData().getCount(); + } + + @Override + protected boolean supportsPrefixes() { + return true; + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } + + protected abstract MealyLearningCacheOracle getCache(SUL delegate); +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULDAGCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULDAGCacheTest.java new file mode 100644 index 0000000000..f220869bcd --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULDAGCacheTest.java @@ -0,0 +1,30 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.sul; + +import de.learnlib.api.SUL; +import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; + +/** + * @author frohme + */ +public class SULDAGCacheTest extends AbstractSULCacheTest { + + @Override + protected MealyLearningCacheOracle getCache(SUL delegate) { + return SULCaches.createCache(getAlphabet(), delegate); + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULTreeCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULTreeCacheTest.java new file mode 100644 index 0000000000..bb7d83b830 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULTreeCacheTest.java @@ -0,0 +1,30 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.cache.sul; + +import de.learnlib.api.SUL; +import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; + +/** + * @author frohme + */ +public class SULTreeCacheTest extends AbstractSULCacheTest { + + @Override + protected MealyLearningCacheOracle getCache(SUL delegate) { + return SULCaches.createTreeCache(getAlphabet(), delegate); + } +} From e470f38ffe6804fa2672fdbfa01091e273e71b69 Mon Sep 17 00:00:00 2001 From: Jeroen Meijer Date: Mon, 26 Feb 2018 09:36:57 +0100 Subject: [PATCH 016/125] Add Black-Box Checking. (#53) * Add black-box checking to the LearnLib. * Fix copyright date. * Add option to mvn command so that all errors are collected. * Fix default versions of dependencies. * Add several more modules to the distribution. * Add sources to distribution too. * Add examples to distribition too. --- .travis.yml | 8 +- algorithms/active/ttt-vpda/pom.xml | 2 +- algorithms/passive/rpni-edsm/pom.xml | 4 - algorithms/passive/rpni-mdl/pom.xml | 4 - algorithms/passive/rpni/pom.xml | 4 - api/pom.xml | 15 + .../java/de/learnlib/api/ObservableSUL.java | 68 ++++ api/src/main/java/de/learnlib/api/SUL.java | 2 + .../api/exception/ModelCheckingException.java | 33 ++ .../api/logging/LoggingBlackBoxProperty.java | 147 +++++++ .../modelchecking/counterexample/Lasso.java | 356 ++++++++++++++++ .../modelchecker/ModelChecker.java | 114 ++++++ .../learnlib/api/oracle/AutomatonOracle.java | 300 ++++++++++++++ .../learnlib/api/oracle/BlackBoxOracle.java | 198 +++++++++ .../learnlib/api/oracle/EmptinessOracle.java | 76 ++++ .../learnlib/api/oracle/InclusionOracle.java | 59 +++ .../api/oracle/OmegaMembershipOracle.java | 92 +++++ .../api/oracle/OmegaQueryAnswerer.java | 47 +++ .../api/oracle/SingleQueryOmegaOracle.java | 54 +++ .../de/learnlib/api/query/OmegaQuery.java | 101 +++++ .../counterexample/LassoTest.java | 240 +++++++++++ build-parent/pom.xml | 3 + build-tools/install-ltsmin.sh | 20 + .../learnlib-checkstyle-suppressions.xml | 2 +- commons/util/pom.xml | 14 +- .../util/AbstractBreadthFirstOracle.java | 140 +++++++ .../java/de/learnlib/util/BBCExperiment.java | 175 ++++++++ .../java/de/learnlib/util/Experiment.java | 204 +++++----- .../main/java/de/learnlib/util/MQUtil.java | 38 ++ distribution/pom.xml | 76 ++++ drivers/basic/pom.xml | 4 - examples/pom.xml | 28 ++ .../examples/bbc/example1/Example.java | 114 ++++++ .../examples/bbc/example2/Example.java | 118 ++++++ .../examples/bbc/example3/Example.java | 99 +++++ model-checkers/pom.xml | 78 ++++ .../modelchecker/AbstractLTSminLTL.java | 383 ++++++++++++++++++ .../modelchecker/AbstractLTSminLTLMealy.java | 170 ++++++++ .../AbstractUnfoldingModelChecker.java | 113 ++++++ .../modelchecker/LTSminLTLAlternating.java | 68 ++++ .../modelchecker/LTSminLTLDFA.java | 129 ++++++ .../modelchecker/LTSminLTLIO.java | 70 ++++ .../AbstractLTSminLTLMealyTest.java | 66 +++ .../modelchecker/AbstractLTSminLTLTest.java | 90 ++++ .../AbstractUnfoldingModelCheckerTest.java | 73 ++++ .../LTSminLTLAlternatingTest.java | 54 +++ .../modelchecker/LTSminLTLDFATest.java | 73 ++++ .../modelchecker/LTSminLTLIOTest.java | 53 +++ model-checkers/src/test/resources/test.etf | 26 ++ model-checkers/src/test/resources/test.fsm | 9 + oracles/black-box-oracles/pom.xml | 60 +++ .../blackbox/AbstractBlackBoxOracle.java | 76 ++++ .../oracle/blackbox/CExFirstBBOracle.java | 121 ++++++ .../blackbox/DisproveFirstBBOracle.java | 121 ++++++ .../blackbox/ModelCheckingBBProperty.java | 279 +++++++++++++ .../blackbox/AbstractBlackBoxOracleTest.java | 53 +++ .../oracle/blackbox/CExFirstBBOracleTest.java | 97 +++++ .../blackbox/DisproveFirstBBOracleTest.java | 88 ++++ .../blackbox/ModelCheckingBBPropertyTest.java | 130 ++++++ oracles/emptiness-oracles/pom.xml | 77 ++++ .../AbstractBreadthFirstEmptinessOracle.java | 64 +++ ...AbstractLassoAutomatonEmptinessOracle.java | 138 +++++++ ...stractBreadthFirstEmptinessOracleTest.java | 192 +++++++++ .../AbstractLassoAutomatonEmptinessTest.java | 210 ++++++++++ .../oracle/equivalence/WpMethodEQOracle.java | 3 +- .../sul/ResetCounterObservableSUL.java | 69 ++++ .../filter/statistic/sul/ResetCounterSUL.java | 22 +- .../sul/SymbolCounterObservableSUL.java | 69 ++++ .../statistic/sul/SymbolCounterSUL.java | 22 +- oracles/inclusion-oracles/pom.xml | 66 +++ .../AbstractBreadthFirstInclusionOracle.java | 61 +++ ...stractBreadthFirstInclusionOracleTest.java | 188 +++++++++ oracles/membership-oracles/pom.xml | 4 + .../membership/AbstractSULOmegaOracle.java | 324 +++++++++++++++ .../membership/SimulatorOmegaOracle.java | 146 +++++++ .../membership/SimulatorOmegaOracleTest.java | 75 ++++ ...acleTest.java => SimulatorOracleTest.java} | 2 +- oracles/pom.xml | 3 + pom.xml | 76 +++- .../learnlib/examples/LearningExamples.java | 8 +- .../learnlib/examples/dfa/ExampleTinyDFA.java | 59 +++ .../examples/mealy/ExampleTinyMealy.java | 56 +++ test-support/learnlib-oracles-support/pom.xml | 36 ++ .../util/AbstractBreadthFirstOracleTest.java | 78 ++++ .../de/learnlib/util/AutomatonOracleTest.java | 24 ++ test-support/pom.xml | 1 + 86 files changed, 7367 insertions(+), 145 deletions(-) create mode 100644 api/src/main/java/de/learnlib/api/ObservableSUL.java create mode 100644 api/src/main/java/de/learnlib/api/exception/ModelCheckingException.java create mode 100644 api/src/main/java/de/learnlib/api/logging/LoggingBlackBoxProperty.java create mode 100644 api/src/main/java/de/learnlib/api/modelchecking/counterexample/Lasso.java create mode 100644 api/src/main/java/de/learnlib/api/modelchecking/modelchecker/ModelChecker.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/OmegaMembershipOracle.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/OmegaQueryAnswerer.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java create mode 100644 api/src/main/java/de/learnlib/api/query/OmegaQuery.java create mode 100644 api/src/test/java/de/learnlib/api/modelchecking/counterexample/LassoTest.java create mode 100755 build-tools/install-ltsmin.sh create mode 100644 commons/util/src/main/java/de/learnlib/util/AbstractBreadthFirstOracle.java create mode 100644 commons/util/src/main/java/de/learnlib/util/BBCExperiment.java create mode 100644 examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java create mode 100644 examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java create mode 100644 examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java create mode 100644 model-checkers/pom.xml create mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java create mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java create mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelChecker.java create mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java create mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java create mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java create mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java create mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java create mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java create mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternatingTest.java create mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java create mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIOTest.java create mode 100644 model-checkers/src/test/resources/test.etf create mode 100644 model-checkers/src/test/resources/test.fsm create mode 100644 oracles/black-box-oracles/pom.xml create mode 100644 oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java create mode 100644 oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java create mode 100644 oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java create mode 100644 oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java create mode 100644 oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java create mode 100644 oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java create mode 100644 oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java create mode 100644 oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java create mode 100644 oracles/emptiness-oracles/pom.xml create mode 100644 oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java create mode 100644 oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java create mode 100644 oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java create mode 100644 oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java create mode 100644 oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterObservableSUL.java create mode 100644 oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterObservableSUL.java create mode 100644 oracles/inclusion-oracles/pom.xml create mode 100644 oracles/inclusion-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java create mode 100644 oracles/inclusion-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java create mode 100644 oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java create mode 100644 oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java create mode 100644 oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java rename oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/{OracleTest.java => SimulatorOracleTest.java} (98%) create mode 100644 test-support/learning-examples/src/main/java/de/learnlib/examples/dfa/ExampleTinyDFA.java create mode 100644 test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleTinyMealy.java create mode 100644 test-support/learnlib-oracles-support/pom.xml create mode 100644 test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AbstractBreadthFirstOracleTest.java create mode 100644 test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AutomatonOracleTest.java diff --git a/.travis.yml b/.travis.yml index 36e314bc7f..70868084c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ jdk: cache: directories: - $HOME/.m2 + - $HOME/ltsmin before_cache: # do not cache our local archives @@ -29,10 +30,13 @@ before_install: - mvn install -DskipTests - popd -install: true # skip mvn install, because we essentially run the same command in the script routine +install: + # install LTSmin + - build-tools/install-ltsmin.sh + - PATH="$PATH:$HOME/ltsmin/bin" script: - - mvn install -B -Pintegration-tests,code-analysis,code-coverage,bundles + - mvn install -B -Pintegration-tests,code-analysis,code-coverage,bundles --fail-at-end - mvn coveralls:report jobs: diff --git a/algorithms/active/ttt-vpda/pom.xml b/algorithms/active/ttt-vpda/pom.xml index 1af6ea2312..47adf94b0c 100644 --- a/algorithms/active/ttt-vpda/pom.xml +++ b/algorithms/active/ttt-vpda/pom.xml @@ -1,6 +1,6 @@ - - de.learnlib.testsupport - learnlib-learning-examples - de.learnlib.testsupport learnlib-learner-it-support diff --git a/algorithms/passive/rpni-mdl/pom.xml b/algorithms/passive/rpni-mdl/pom.xml index 00aa18ed4c..dbe0dabd22 100644 --- a/algorithms/passive/rpni-mdl/pom.xml +++ b/algorithms/passive/rpni-mdl/pom.xml @@ -48,10 +48,6 @@ limitations under the License. de.learnlib learnlib-rpni - - de.learnlib.testsupport - learnlib-learning-examples - de.learnlib.testsupport learnlib-learner-it-support diff --git a/algorithms/passive/rpni/pom.xml b/algorithms/passive/rpni/pom.xml index 84563a466c..2169872f7d 100644 --- a/algorithms/passive/rpni/pom.xml +++ b/algorithms/passive/rpni/pom.xml @@ -70,10 +70,6 @@ limitations under the License. - - de.learnlib.testsupport - learnlib-learning-examples - de.learnlib.testsupport learnlib-learner-it-support diff --git a/api/pom.xml b/api/pom.xml index e739c1e9fa..8f604f3e85 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -65,6 +65,12 @@ limitations under the License. org.testng testng + test + + + junit + junit + test - - - - org.testng - testng - diff --git a/commons/util/src/main/java/de/learnlib/util/AbstractBreadthFirstOracle.java b/commons/util/src/main/java/de/learnlib/util/AbstractBreadthFirstOracle.java new file mode 100644 index 0000000000..1ae733b96c --- /dev/null +++ b/commons/util/src/main/java/de/learnlib/util/AbstractBreadthFirstOracle.java @@ -0,0 +1,140 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.util; + +import java.util.LinkedList; +import java.util.Queue; + +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.oracle.AutomatonOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.Query; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Word; + +/** + * Finds counterexamples to a given hypothesis by generating words in that hypothesis in a breadth-first manner. + * + * @author Jeroen Meijer + * + * @param the automaton type + * @param the input type + * @param the output type + * @param the Query type + */ +@ParametersAreNonnullByDefault +public abstract class AbstractBreadthFirstOracle, I, D, Q extends Query> + implements AutomatonOracle { + + /** + * The queue containing the words to find a counterexample with. + */ + private final Queue> queue = new LinkedList<>(); + + /** + * The maximum number of words to generate. + */ + private final int maxWords; + + /** + * Constructs a new AbstractBreadthFirstOracle. + * + * @param maxWords the maximum number of words to generate. + */ + protected AbstractBreadthFirstOracle(int maxWords) { + this.maxWords = maxWords; + } + + /** + * Returns the maximum number of words to generate. + * + * @return the maximum number of words to generate. + */ + @Override + public int getMaxWords() { + return maxWords; + } + + /** + * Returns the next input word, by popping from a queue. + * + * @see AutomatonOracle#nextInput() + */ + @Override + public Word nextInput() { + final Word input = queue.remove(); + return input; + } + + /** + * Adds a new input word to the queue. + * + * @see AutomatonOracle#addWord(Word) + */ + @Override + public void addWord(Word input) { + queue.add(input); + } + + /** + * Clears the queue. + */ + @Override + public void pre() { + queue.clear(); + } + + /** + * An implementation of a {@link AbstractBreadthFirstOracle}, that uses {@link DefaultQuery}s, and a + * {@link MembershipOracle}. + * + * @param the automaton type + * @param the input type + * @param the output type + */ + public abstract static class AbstractDefaultBFOracle, I, D> + extends AbstractBreadthFirstOracle> + implements DefaultOracle { + + /** + * The {@link MembershipOracle} used to answer {@link DefaultQuery}s. + */ + private final MembershipOracle membershipOracle; + + /** + * Constructs a new AbstractDefaultBFOracle. + * + * @param maxWords the maximum number of words to generate. + * @param membershipOracle the membership oracle to answer {@link DefaultQuery}s. + */ + protected AbstractDefaultBFOracle(int maxWords, MembershipOracle membershipOracle) { + super(maxWords); + this.membershipOracle = membershipOracle; + } + + /** + * Returns the membership oracle used to answer {@link DefaultQuery}s. + * + * @return the MembershipOracle. + */ + @Override + public MembershipOracle getMembershipOracle() { + return membershipOracle; + } + } +} diff --git a/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java b/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java new file mode 100644 index 0000000000..edff14b10d --- /dev/null +++ b/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java @@ -0,0 +1,175 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.util; + +import javax.annotation.Nonnull; + +import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.logging.LearnLogger; +import de.learnlib.api.oracle.BlackBoxOracle; +import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.filter.statistic.Counter; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * A black-box checking experiment. The experiment can be started with {@link #run()}. + * + * @author Jeroen Meijer + * + * @param the automaton type + * @param the input type + * @param the output type + */ +public class BBCExperiment extends Experiment { + + private static final LearnLogger LOGGER = LearnLogger.getLogger(BBCExperiment.class); + + /** + * @see #getRoundsBBC() + */ + private final Counter roundsBBC = new Counter("BBC rounds", "#"); + + /** + * @see #getRoundsPropertyViolation() + */ + private final Counter roundsPropertyViolation = new Counter("property violation detection rounds", "#"); + + /** + * @see #getBlackBoxOracle() + */ + private final BlackBoxOracle> blackBoxOracle; + + /** + * Indicates whether the {@link BlackBoxOracle} should continue learning when all properties have been violated. + */ + private final boolean keepLearning; + + /** + * Constructs a new BBCExperiment. + * + * @param learningAlgorithm the learner. + * @param equivalenceAlgorithm the equivalence oracle. + * @param inputs the alphabet. + * @param blackBoxOracle the black-box oracle. + * @param keepLearning whether to keep learning the hypothesis when all properties have been violated. + */ + protected BBCExperiment( + LearningAlgorithm learningAlgorithm, + EquivalenceOracle equivalenceAlgorithm, + Alphabet inputs, + BlackBoxOracle> blackBoxOracle, + boolean keepLearning) { + super(learningAlgorithm, equivalenceAlgorithm, inputs); + this.blackBoxOracle = blackBoxOracle; + this.keepLearning = keepLearning; + } + + /** + * Returns a {@link Counter} that indicates how many main iterations where done. + * + * @return the Counter. + */ + public Counter getRoundsBBC() { + return roundsBBC; + } + + /** + * Returns a {@link Counter} that indicates how many nested iterations where done. + * + * @return the Counter. + */ + public Counter getRoundsPropertyViolation() { + return roundsPropertyViolation; + } + + /** + * Gets the {@link BlackBoxOracle} for this experiment. + * + * @return the {@link BlackBoxOracle} + */ + public BlackBoxOracle> getBlackBoxOracle() { + return blackBoxOracle; + } + + /** + * Runs a black-box checking experiment. + * + * @return the final hypothesis. + */ + @Nonnull + @Override + public A run() { + init(); + + do { + roundsBBC.increment(); + DefaultQuery ce; + do { + roundsPropertyViolation.increment(); + LOGGER.logPhase("Searching for property violation"); + profileStart("Searching for property violation"); + ce = blackBoxOracle.findCounterExample(getLearningAlgorithm().getHypothesisModel(), getInputs()); + profileStop("Searching for property violation"); + assert blackBoxOracle.allPropertiesViolated() == (ce == null); + } while (!blackBoxOracle.allPropertiesViolated() && ce != null && getLearningAlgorithm().refineHypothesis(ce)); + } while ((keepLearning || !blackBoxOracle.allPropertiesViolated()) && refineHypothesis()); + + setFinalHypothesis(getLearningAlgorithm().getHypothesisModel()); + + return getLearningAlgorithm().getHypothesisModel(); + } + + public static class DFABBCExperiment extends BBCExperiment, I, Boolean> { + + public DFABBCExperiment(LearningAlgorithm.DFALearner learningAlgorithm, + EquivalenceOracle.DFAEquivalenceOracle equivalenceAlgorithm, + Alphabet inputs, + BlackBoxOracle.DFABlackBoxOracle blackBoxOracle, + boolean keepLearning) { + super(learningAlgorithm, equivalenceAlgorithm, inputs, blackBoxOracle, keepLearning); + } + + public DFABBCExperiment(LearningAlgorithm.DFALearner learningAlgorithm, + EquivalenceOracle.DFAEquivalenceOracle equivalenceAlgorithm, + Alphabet inputs, + BlackBoxOracle.DFABlackBoxOracle blackBoxOracle) { + this(learningAlgorithm, equivalenceAlgorithm, inputs, blackBoxOracle, false); + } + } + + public static class MealyBBCExperiment extends BBCExperiment, I, Word> { + + public MealyBBCExperiment(LearningAlgorithm.MealyLearner learningAlgorithm, + EquivalenceOracle.MealyEquivalenceOracle equivalenceAlgorithm, + Alphabet inputs, + BlackBoxOracle.MealyBlackBoxOracle blackBoxOracle, + boolean keepLearning) { + super(learningAlgorithm, equivalenceAlgorithm, inputs, blackBoxOracle, keepLearning); + } + + public MealyBBCExperiment(LearningAlgorithm.MealyLearner learningAlgorithm, + EquivalenceOracle.MealyEquivalenceOracle equivalenceAlgorithm, + Alphabet inputs, + BlackBoxOracle.MealyBlackBoxOracle blackBoxOracle) { + this(learningAlgorithm, equivalenceAlgorithm, inputs, blackBoxOracle, false); + } + } +} diff --git a/commons/util/src/main/java/de/learnlib/util/Experiment.java b/commons/util/src/main/java/de/learnlib/util/Experiment.java index 38f2e4590f..085dc77f3d 100644 --- a/commons/util/src/main/java/de/learnlib/util/Experiment.java +++ b/commons/util/src/main/java/de/learnlib/util/Experiment.java @@ -32,149 +32,155 @@ /** * runs a learning experiment. * - * @param + * @param the automaton type + * @param the input type + * @param the output type * * @author falkhowar + * @author Jeroen Meijer */ @ParametersAreNonnullByDefault -public class Experiment { +public class Experiment { private static final LearnLogger LOGGER = LearnLogger.getLogger(Experiment.class); - private final ExperimentImpl impl; + private boolean logModels; + private boolean profile; - private final Counter rounds = new Counter("rounds", "#"); + + private final Counter rounds = new Counter("learning rounds", "#"); + private A finalHypothesis; - public Experiment(LearningAlgorithm learningAlgorithm, - EquivalenceOracle equivalenceAlgorithm, - Alphabet inputs) { - this.impl = new ExperimentImpl<>(learningAlgorithm, equivalenceAlgorithm, inputs); + private final LearningAlgorithm learningAlgorithm; + + private final EquivalenceOracle equivalenceAlgorithm; + + private final Alphabet inputs; + + public Experiment(LearningAlgorithm learningAlgorithm, + EquivalenceOracle equivalenceAlgorithm, + Alphabet inputs) { + this.learningAlgorithm = learningAlgorithm; + this.equivalenceAlgorithm = equivalenceAlgorithm; + this.inputs = inputs; } - /** - * - */ - @Nonnull - public A run() { - finalHypothesis = impl.run(); - return finalHypothesis; + public boolean isLogModels() { + return logModels; } - @Nonnull - public A getFinalHypothesis() { - if (finalHypothesis == null) { - throw new IllegalStateException("Experiment has not yet been run"); - } - return finalHypothesis; + public Counter getRounds() { + return rounds; } - private void profileStart(String taskname) { - if (profile) { - SimpleProfiler.start(taskname); - } + public LearningAlgorithm getLearningAlgorithm() { + return learningAlgorithm; } - private void profileStop(String taskname) { - if (profile) { - SimpleProfiler.stop(taskname); - } + public EquivalenceOracle getEquivalenceAlgorithm() { + return equivalenceAlgorithm; + } + + public Alphabet getInputs() { + return inputs; } - /** - * @param logModels - * the logModels to set - */ public void setLogModels(boolean logModels) { this.logModels = logModels; } - /** - * @param profile - * the profile to set - */ public void setProfile(boolean profile) { this.profile = profile; } - /** - * @return the rounds - */ - @Nonnull - public Counter getRounds() { - return rounds; + protected void init() { + getRounds().increment(); + LOGGER.logPhase("Starting round " + getRounds().getCount()); + LOGGER.logPhase("Learning"); + profileStart("Learning"); + getLearningAlgorithm().startLearning(); + profileStop("Learning"); } - public static class DFAExperiment extends Experiment> { + protected boolean refineHypothesis() { + A hyp = getLearningAlgorithm().getHypothesisModel(); - public DFAExperiment(LearningAlgorithm, I, Boolean> learningAlgorithm, - EquivalenceOracle, I, Boolean> equivalenceAlgorithm, - Alphabet inputs) { - super(learningAlgorithm, equivalenceAlgorithm, inputs); + if (isLogModels()) { + LOGGER.logModel(hyp); } + + LOGGER.logPhase("Searching for counterexample"); + profileStart("Searching for counterexample"); + DefaultQuery ce = getEquivalenceAlgorithm().findCounterExample(hyp, getInputs()); + profileStop("Searching for counterexample"); + if (ce != null) { + LOGGER.logCounterexample(ce.toString()); + + // next round ... + getRounds().increment(); + LOGGER.logPhase("Starting round " + getRounds().getCount()); + LOGGER.logPhase("Learning"); + profileStart("Learning"); + getLearningAlgorithm().refineHypothesis(ce); + profileStop("Learning"); + } + return ce != null; } - public static class MealyExperiment extends Experiment> { + @Nonnull + public A run() { - public MealyExperiment(LearningAlgorithm, I, Word> learningAlgorithm, - EquivalenceOracle, I, Word> equivalenceAlgorithm, - Alphabet inputs) { - super(learningAlgorithm, equivalenceAlgorithm, inputs); + init(); + + while (refineHypothesis()) { } + + finalHypothesis = getLearningAlgorithm().getHypothesisModel(); + + return finalHypothesis; + + } + + protected void setFinalHypothesis(A hyp) { + finalHypothesis = hyp; + } + + @Nonnull + public A getFinalHypothesis() { + if (finalHypothesis == null) { + throw new IllegalStateException("Experiment has not yet been run"); } + return finalHypothesis; + } + protected void profileStart(String taskname) { + if (profile) { + SimpleProfiler.start(taskname); + } } - private final class ExperimentImpl { + protected void profileStop(String taskname) { + if (profile) { + SimpleProfiler.stop(taskname); + } + } - private final LearningAlgorithm learningAlgorithm; - private final EquivalenceOracle equivalenceAlgorithm; - private final Alphabet inputs; + public static class DFAExperiment extends Experiment, I, Boolean> { - ExperimentImpl(LearningAlgorithm learningAlgorithm, - EquivalenceOracle equivalenceAlgorithm, - Alphabet inputs) { - this.learningAlgorithm = learningAlgorithm; - this.equivalenceAlgorithm = equivalenceAlgorithm; - this.inputs = inputs; + public DFAExperiment(LearningAlgorithm.DFALearner learningAlgorithm, + EquivalenceOracle.DFAEquivalenceOracle equivalenceAlgorithm, + Alphabet inputs) { + super(learningAlgorithm, equivalenceAlgorithm, inputs); } + } - public A run() { - rounds.increment(); - LOGGER.logPhase("Starting round " + rounds.getCount()); - LOGGER.logPhase("Learning"); - profileStart("Learning"); - learningAlgorithm.startLearning(); - profileStop("Learning"); + public static class MealyExperiment extends Experiment, I, Word> { - boolean done = false; - A hyp = null; - while (!done) { - hyp = learningAlgorithm.getHypothesisModel(); - if (logModels) { - LOGGER.logModel(hyp); - } - - LOGGER.logPhase("Searching for counterexample"); - profileStart("Searching for counterexample"); - DefaultQuery ce = equivalenceAlgorithm.findCounterExample(hyp, inputs); - profileStop("Searching for counterexample"); - if (ce == null) { - done = true; - continue; - } - - LOGGER.logCounterexample(ce.getInput().toString()); - - // next round ... - rounds.increment(); - LOGGER.logPhase("Starting round " + rounds.getCount()); - LOGGER.logPhase("Learning"); - profileStart("Learning"); - learningAlgorithm.refineHypothesis(ce); - profileStop("Learning"); - } - - return hyp; + public MealyExperiment(LearningAlgorithm.MealyLearner learningAlgorithm, + EquivalenceOracle.MealyEquivalenceOracle equivalenceAlgorithm, + Alphabet inputs) { + super(learningAlgorithm, equivalenceAlgorithm, inputs); } } } + diff --git a/commons/util/src/main/java/de/learnlib/util/MQUtil.java b/commons/util/src/main/java/de/learnlib/util/MQUtil.java index 42ca3c4755..e0ed4aba52 100644 --- a/commons/util/src/main/java/de/learnlib/util/MQUtil.java +++ b/commons/util/src/main/java/de/learnlib/util/MQUtil.java @@ -16,18 +16,23 @@ package de.learnlib.util; import java.util.Collection; +import java.util.List; import java.util.Objects; +import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.oracle.OmegaQueryAnswerer; import de.learnlib.api.oracle.QueryAnswerer; import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; import de.learnlib.api.query.Query; import de.learnlib.setting.LearnLibSettings; import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.commons.util.Pair; import net.automatalib.words.Word; @ParametersAreNonnullByDefault @@ -84,6 +89,15 @@ public static void answerQueriesAuto(QueryAnswerer answerer, } } + public static void answerOmegaQueriesAuto(OmegaQueryAnswerer answerer, + Collection> queries) { + if (PARALLEL_THRESHOLD < 0 || queries.size() < PARALLEL_THRESHOLD) { + answerOmegaQueries(answerer, queries); + } else { + answerOmegaQueriesParallel(answerer, queries); + } + } + public static void answerQueries(QueryAnswerer answerer, Collection> queries) { for (Query query : queries) { Word prefix = query.getPrefix(); @@ -93,6 +107,18 @@ public static void answerQueries(QueryAnswerer answerer, Collection } } + public static void answerOmegaQueries(OmegaQueryAnswerer answerer, + Collection> queries) { + for (OmegaQuery query : queries) { + Word prefix = query.getPrefix(); + Word suffix = query.getSuffix(); + Set indices = query.getIndices(); + Pair> answer = answerer.answerQuery(prefix, suffix, indices); + query.answer(answer.getFirst()); + query.setStates(answer.getSecond()); + } + } + public static void answerQueriesParallel(QueryAnswerer answerer, Collection> queries) { queries.parallelStream().forEach(q -> { @@ -103,6 +129,18 @@ public static void answerQueriesParallel(QueryAnswerer answerer, }); } + public static void answerOmegaQueriesParallel(OmegaQueryAnswerer answerer, + Collection> queries) { + queries.parallelStream().forEach(q -> { + Word prefix = q.getPrefix(); + Word suffix = q.getSuffix(); + Set indices = q.getIndices(); + Pair> answer = answerer.answerQuery(prefix, suffix, indices); + q.answer(answer.getFirst()); + q.setStates(answer.getSecond()); + }); + } + public static boolean isCounterexample(DefaultQuery query, SuffixOutput hyp) { D qryOut = query.getOutput(); D hypOut = hyp.computeSuffixOutput(query.getPrefix(), query.getSuffix()); diff --git a/distribution/pom.xml b/distribution/pom.xml index ad829628fb..e8e73cc8fa 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -171,6 +171,17 @@ limitations under the License. learnlib-drivers-simulator + + + de.learnlib + learnlib-examples + + + + de.learnlib.testsupport + learnlib-learning-examples + + de.learnlib @@ -202,6 +213,27 @@ limitations under the License. learnlib-parallelism + + de.learnlib + learnlib-black-box-oracles + + + + de.learnlib + learnlib-emptiness-oracles + + + + de.learnlib + learnlib-inclusion-oracles + + + + + de.learnlib + learnlib-model-checkers + + net.automatalib.distribution @@ -418,6 +450,21 @@ limitations under the License. sources + + + de.learnlib + learnlib-examples + ${project.version} + sources + + + + de.learnlib.testsupport + learnlib-learning-examples + ${project.version} + sources + + de.learnlib @@ -460,6 +507,35 @@ limitations under the License. ${project.version} sources + + + de.learnlib + learnlib-black-box-oracles + ${project.version} + sources + + + + de.learnlib + learnlib-emptiness-oracles + ${project.version} + sources + + + + de.learnlib + learnlib-inclusion-oracles + ${project.version} + sources + + + + + de.learnlib + learnlib-model-checkers + ${project.version} + sources + diff --git a/drivers/basic/pom.xml b/drivers/basic/pom.xml index 1b309c1e17..47234b72ad 100644 --- a/drivers/basic/pom.xml +++ b/drivers/basic/pom.xml @@ -65,10 +65,6 @@ limitations under the License. - - de.learnlib.testsupport - learnlib-learning-examples - de.learnlib learnlib-membership-oracles diff --git a/examples/pom.xml b/examples/pom.xml index a9ee40d290..1c0499e557 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -131,5 +131,33 @@ limitations under the License. logback-classic runtime + + de.learnlib + learnlib-model-checkers + + + de.learnlib + learnlib-black-box-oracles + + + de.learnlib + learnlib-emptiness-oracles + + + de.learnlib + learnlib-inclusion-oracles + + + de.learnlib + learnlib-ttt + + + de.learnlib.testsupport + learnlib-learning-examples + + + de.learnlib + learnlib-acex + diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java new file mode 100644 index 0000000000..79340d0674 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java @@ -0,0 +1,114 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.bbc.example1; + +import java.util.function.Function; + +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.algorithms.ttt.dfa.TTTLearnerDFA; +import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; +import de.learnlib.api.logging.LoggingBlackBoxProperty.DFALoggingBlackBoxProperty; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelCheckerLasso; +import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxOracle; +import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxProperty; +import de.learnlib.api.oracle.EmptinessOracle.DFALassoEmptinessOracle; +import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; +import de.learnlib.api.oracle.InclusionOracle.DFAInclusionOracle; +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; +import de.learnlib.examples.LearningExample.DFALearningExample; +import de.learnlib.examples.dfa.ExampleTinyDFA; +import de.learnlib.modelchecking.modelchecker.LTSminLTLDFABuilder; +import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstDFABBOracle; +import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.DFABBPropertyDFALasso; +import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.DFALassoDFAEmptinessOracle; +import de.learnlib.oracle.equivalence.WpMethodEQOracle.DFAWpMethodEQOracle; +import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.DFABreadthFirstInclusionOracle; +import de.learnlib.oracle.membership.SimulatorOmegaOracle.DFASimulatorOmegaOracle; +import de.learnlib.util.BBCExperiment.DFABBCExperiment; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; +import net.automatalib.words.Alphabet; + +/** + * Runs a black-box checking experiment for a DFA. + * + * @author Jeroen Meijer + */ +public final class Example { + + /** + * A function that transforms edges in an FSM source to actual input for a DFA. + */ + public static final Function EDGE_PARSER = s -> s.charAt(0); + + private Example() {} + + public static void main(String[] args) { + + DFALearningExample le = ExampleTinyDFA.createExample(); + + // define the alphabet + Alphabet sigma = le.getAlphabet(); + + // create the DFA to be verified/learned + DFA dfa = le.getReferenceAutomaton(); + + // create an omega membership oracle + DFAOmegaMembershipOracle omqOracle = new DFASimulatorOmegaOracle<>(dfa); + + // create a regular membership oracle + DFAMembershipOracle mqOracle = omqOracle.getDFAMembershipOracle(); + + // create an equivalence oracle + DFAEquivalenceOracle eqOracle = new DFAWpMethodEQOracle<>(mqOracle, 3); + + // create a learner + DFALearner learner = new TTTLearnerDFA<>(sigma, mqOracle, AcexAnalyzers.LINEAR_FWD); + + // create a model checker + DFAModelCheckerLasso modelChecker = + new LTSminLTLDFABuilder().withString2Input(EDGE_PARSER).create(); + + // create an emptiness oracle, that is used to disprove properties + DFALassoEmptinessOracle emptinessOracle = new DFALassoDFAEmptinessOracle<>(omqOracle); + + // create an inclusion oracle, that is used to find counterexamples to hypotheses + DFAInclusionOracle inclusionOracle = new DFABreadthFirstInclusionOracle<>(1, mqOracle); + + // create an LTL formula + DFABlackBoxProperty ltl = new DFALoggingBlackBoxProperty<>( + new DFABBPropertyDFALasso<>(modelChecker, + emptinessOracle, + inclusionOracle, + "letter==\"b\"")); + + // create a black-box oracle + DFABlackBoxOracle blackBoxOracle = new CExFirstDFABBOracle<>(ltl); + + // create a black-box checking experiment + DFABBCExperiment experiment = new DFABBCExperiment<>(learner, eqOracle, sigma, blackBoxOracle); + + // run the experiment + experiment.run(); + + // get the result + final DFA result = experiment.getFinalHypothesis(); + + // assert we have the correct result + assert DeterministicEquivalenceTest.findSeparatingWord(dfa, result, sigma) == null; + } +} diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java new file mode 100644 index 0000000000..1244d40389 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java @@ -0,0 +1,118 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.bbc.example2; + +import java.util.function.Function; + +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; +import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelCheckerLasso; +import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxOracle; +import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; +import de.learnlib.api.oracle.EmptinessOracle.MealyLassoEmptinessOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.InclusionOracle.MealyInclusionOracle; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; +import de.learnlib.examples.LearningExample.MealyLearningExample; +import de.learnlib.examples.mealy.ExampleTinyMealy; +import de.learnlib.modelchecking.modelchecker.LTSminLTLIOBuilder; +import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstMealyBBOracle; +import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.MealyBBPropertyMealyLasso; +import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; +import de.learnlib.oracle.equivalence.WpMethodEQOracle.MealyWpMethodEQOracle; +import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; +import de.learnlib.oracle.membership.SimulatorOmegaOracle.MealySimulatorOmegaOracle; +import de.learnlib.util.BBCExperiment.MealyBBCExperiment; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; +import net.automatalib.words.Alphabet; + +/** + * Run a black-box checking experiment with Mealy machines and straightforward edge semantics. + * + * The main difference with {@link de.learnlib.examples.bbc.example3.Example} is how the LTL formula is written. + * + * @see de.learnlib.examples.bbc.example3.Example + * + * @author Jeroen Meijer + */ +public final class Example { + + /** + * A function that transforms edges in an FSM source to actual input, and output in the Mealy machine. + */ + public static final Function EDGE_PARSER = s -> s.charAt(0); + + private Example() { } + + public static void main(String[] args) { + + MealyLearningExample le = ExampleTinyMealy.createExample(); + + // define the alphabet + Alphabet sigma = le.getAlphabet(); + + // define the Mealy machine to be verified/learned + MealyMachine mealy = le.getReferenceAutomaton(); + + // create an omega membership oracle + MealyOmegaMembershipOracle omqOracle = new MealySimulatorOmegaOracle<>(mealy); + + // create a regular membership oracle + MealyMembershipOracle mqOracle = omqOracle.getMealyMembershipOracle(); + + // create an equivalence oracle + MealyEquivalenceOracle eqOracle = new MealyWpMethodEQOracle<>(mqOracle, 3); + + // create a learner + MealyLearner learner = new TTTLearnerMealy<>(sigma, mqOracle, AcexAnalyzers.LINEAR_FWD); + + // create a model checker + MealyModelCheckerLasso modelChecker = + new LTSminLTLIOBuilder().withString2Input(EDGE_PARSER). + withString2Output(EDGE_PARSER).create(); + + // create an emptiness oracle, that is used to disprove properties + MealyLassoEmptinessOracle emptinessOracle = new MealyLassoMealyEmptinessOracle<>(omqOracle); + + // create an inclusion oracle, that is used to find counterexamples to hypotheses + MealyInclusionOracle inclusionOracle = new MealyBreadthFirstInclusionOracle<>(1, mqOracle); + + // create an ltl formula + MealyBlackBoxProperty ltl = new MealyBBPropertyMealyLasso<>(modelChecker, + emptinessOracle, + inclusionOracle, + "X output==\"2\""); + + // create a black-box oracle + MealyBlackBoxOracle blackBoxOracle = new CExFirstMealyBBOracle<>(ltl); + + // create an experiment + MealyBBCExperiment experiment = new MealyBBCExperiment<>(learner, + eqOracle, sigma, blackBoxOracle); + + // run the experiment + experiment.run(); + + // get the final result + MealyMachine result = experiment.getFinalHypothesis(); + + // check we have the correct result + assert DeterministicEquivalenceTest.findSeparatingWord(mealy, result, sigma) == null; + } +} diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java new file mode 100644 index 0000000000..2e1c79bef3 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java @@ -0,0 +1,99 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.bbc.example3; + +import java.util.function.Function; + +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; +import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelCheckerLasso; +import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxOracle; +import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; +import de.learnlib.api.oracle.EmptinessOracle.MealyLassoEmptinessOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.InclusionOracle.MealyInclusionOracle; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; +import de.learnlib.examples.LearningExample.MealyLearningExample; +import de.learnlib.examples.mealy.ExampleTinyMealy; +import de.learnlib.modelchecking.modelchecker.LTSminLTLAlternatingBuilder; +import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstMealyBBOracle; +import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.MealyBBPropertyMealyLasso; +import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; +import de.learnlib.oracle.equivalence.WpMethodEQOracle.MealyWpMethodEQOracle; +import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; +import de.learnlib.oracle.membership.SimulatorOmegaOracle.MealySimulatorOmegaOracle; +import de.learnlib.util.BBCExperiment.MealyBBCExperiment; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; +import net.automatalib.words.Alphabet; + +/** + * Run a black-box checking experiment with a Mealy machine and alternating edge semantics. + * + * The main difference with {@link de.learnlib.examples.bbc.example2.Example} is how the LTL formula is written. + * + * @see de.learnlib.examples.bbc.example2.Example + * + * @author Jeroen Meijer + */ +public final class Example { + + public static final Function EDGE_PARSER = s -> s.charAt(0); + + private Example() { } + + public static void main(String[] args) { + + MealyLearningExample le = ExampleTinyMealy.createExample(); + + // define the alphabet + Alphabet sigma = le.getAlphabet(); + + // define the Mealy machine to be verified/learned + MealyMachine mealy = le.getReferenceAutomaton(); + + MealyOmegaMembershipOracle omqOracle = new MealySimulatorOmegaOracle<>(mealy); + + MealyMembershipOracle mqOracle = omqOracle.getMealyMembershipOracle(); + + MealyEquivalenceOracle eqOracle = new MealyWpMethodEQOracle<>(mqOracle, 3); + + MealyLearner learner = new TTTLearnerMealy<>(sigma, mqOracle, AcexAnalyzers.LINEAR_FWD); + + MealyModelCheckerLasso modelChecker = + new LTSminLTLAlternatingBuilder().withString2Input(EDGE_PARSER). + withString2Output(EDGE_PARSER).create(); + + MealyLassoEmptinessOracle emptinessOracle = new MealyLassoMealyEmptinessOracle<>(omqOracle); + + MealyInclusionOracle inclusionOracle = new MealyBreadthFirstInclusionOracle<>(1, mqOracle); + + MealyBlackBoxProperty ltl = + new MealyBBPropertyMealyLasso<>(modelChecker, emptinessOracle, inclusionOracle, "X X X letter==\"2\""); + + MealyBlackBoxOracle blackBoxOracle = new CExFirstMealyBBOracle<>(ltl); + + MealyBBCExperiment experiment = new MealyBBCExperiment<>(learner, eqOracle, sigma, blackBoxOracle); + + experiment.run(); + + MealyMachine result = experiment.getFinalHypothesis(); + + assert DeterministicEquivalenceTest.findSeparatingWord(mealy, result, sigma) == null; + } +} diff --git a/model-checkers/pom.xml b/model-checkers/pom.xml new file mode 100644 index 0000000000..ee4ba361cd --- /dev/null +++ b/model-checkers/pom.xml @@ -0,0 +1,78 @@ + + + + + 4.0.0 + + + learnlib-build-parent + de.learnlib + 0.14.0-SNAPSHOT + ../build-parent/pom.xml + + + learnlib-model-checkers + LearnLib :: Model Checkers + Module for model checkers + + + de.learnlib + learnlib-api + + + net.automatalib + automata-util + + + net.automatalib + automata-core + + + net.automatalib + automata-serialization-etf + + + net.automatalib + automata-serialization-fsm + + + net.automatalib + automata-api + + + com.github.misberner.buildergen + buildergen + + + junit + junit + test + + + org.mockito + mockito-core + test + + + de.learnlib + learnlib-settings + + + \ No newline at end of file diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java new file mode 100644 index 0000000000..ff6b327913 --- /dev/null +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java @@ -0,0 +1,383 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; + +import de.learnlib.api.exception.ModelCheckingException; +import de.learnlib.api.modelchecking.counterexample.Lasso; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker; +import de.learnlib.setting.LearnLibSettings; +import net.automatalib.automata.concepts.Output; +import net.automatalib.serialization.etf.writer.AbstractETFWriter; +import net.automatalib.serialization.fsm.parser.AbstractFSMParser; +import net.automatalib.serialization.fsm.parser.FSMParseException; +import net.automatalib.ts.simple.SimpleDTS; + +/** + * An LTL model checker using LTSmin. + * + * The user must install LTSmin in order for {@link AbstractLTSminLTL} to run without exceptions. Once LTSmin is installed + * the user may specify the path to the installed LTSmin binaries with the property + * de.learnlib.external.ltsmin.path. If this property is not set the binaries will be run as usual (e.g. simply + * by invoking etf2lts-mc, and ltsmin-convert), which means the user can also specify the location of the binaries + * in the PATH environment variable. + * + * This model checker is implemented as follows. The hypothesis automaton is first written to an LTS in ETF + * {@link AbstractETFWriter} file, which serves as input for the etf2lts-mc binary. + * Then the etf2lts-mc binary is run, which will write an LTS in GCF format. This LTS will be a subset of the + * language of the given hypothesis. Next, the GCF is converted to FSM using the ltsmin-convert binary. Lastly, the + * FSM is read back into an automaton using an {@link AbstractFSMParser}. + * + * @author Jeroen Meijer + * + * @see http://ltsmin.utwente.nl + * @see AbstractFSMParser + * @see AbstractETFWriter + * @see LearnLibSettings + * + * @param the input type. + * @param the output type. + * @param the Lasso type. + */ +public abstract class AbstractLTSminLTL & Output, + L extends Lasso> + extends AbstractUnfoldingModelChecker implements ModelChecker { + + public static final String LTSMIN_PATH; + + public static final String LTSMIN_PATH_PROPERTY = "de.learnlib.external.ltsmin.path"; + + static { + LearnLibSettings settings = LearnLibSettings.getInstance(); + + LTSMIN_PATH = settings.getProperty(LTSMIN_PATH_PROPERTY, ""); + } + + public static final String ETF2LTS_MC = LTSMIN_PATH + "etf2lts-mc"; + + public static final String LTSMIN_CONVERT = LTSMIN_PATH + "ltsmin-convert"; + + public static final String CHECK = "An exception occurred while checking if LTSmin is installed. " + + "Could not run binary '%s', the following exception occurred: %s. " + + "LTSmin can be obtained at https://ltsmin.utwente.nl. If you installed LTSmin " + + "in a non standard location you can set the property: " + + "'de.learnlib.external.ltsmin.path', which must end with a '/'. Setting the " + + "PATH variable works too."; + + /** + * The exit code for running an LTSmin binary with --version. + */ + public static final int VERSION_EXIT = 255; + + /** + * @see #isKeepFiles() + */ + private final boolean keepFiles; + + /** + * @see #isInheritIO() + */ + private final boolean inheritIO; + + /** + * @see #getString2Input() + */ + private final Function string2Input; + + /** + * Whether or not we made sure the LTSmin binaries can be run. + */ + private static boolean binariesChecked; + + /** + * Constructs a new AbstractLTSminLTL. + * + * @param keepFiles whether to keep intermediate files, (e.g. etfs, gcfs etc.). + * @param string2Input a function that transforms edges in FSM files to actual input. + * @param minimumUnfolds the minimum number of unfolds. + * @param multiplier the multiplier + * @param inheritIO whether to print output from LTSmin on stdout, and stderr. + * + * @throws ModelCheckingException when the LTSmin binaries can not be run successfully. + */ + protected AbstractLTSminLTL(boolean keepFiles, + Function string2Input, + int minimumUnfolds, + double multiplier, + boolean inheritIO) throws ModelCheckingException { + super(minimumUnfolds, multiplier); + this.keepFiles = keepFiles; + this.string2Input = string2Input; + this.inheritIO = inheritIO; + + if (!binariesChecked) { + checkBinary(ETF2LTS_MC); + checkBinary(LTSMIN_CONVERT); + binariesChecked = true; + } + } + + /** + * Returns whether intermediate files should be kept, e.g. etfs, gcfs, etc. + * + * @return the boolean + */ + protected boolean isKeepFiles() { + return keepFiles; + } + + /** + * Returns the function that transforms edges in FSM files to actual input. + * + * @return the Function. + */ + public Function getString2Input() { + return string2Input; + } + + /** + * Returns whether all streams from standard-in, -out, and -error should be inherited. + * + * @return the boolean + */ + public boolean isInheritIO() { + return inheritIO; + } + + /** + * Writes the given {@code automaton} to the given {@code etf} file. + * + * @param automaton the automaton to write. + * @param inputs the alphabet. + * @param etf the file to write to. + * + * @throws IOException when the given {@code automaton} can not be written to {@code etf}. + */ + protected abstract void automaton2ETF(A automaton, Collection inputs, File etf) throws IOException; + + /** + * Reads the {@code fsm} and converts it to a {@link Lasso}. + * + * @param fsm the FSM to read. + * @param automaton the automaton that was used as a hypothesis. + * + * @return the {@link Lasso}. + * + * @throws IOException when {@code fsm} can not be read correctly. + * @throws FSMParseException when the FSM definition in {@code fsm} is invalid. + */ + protected abstract L fsm2Lasso(File fsm, A automaton) throws IOException, FSMParseException; + + /** + * Finds a counterexample for the given {@code formula}, and given {@code hypothesis}. + * + * @see AbstractLTSminLTL + */ + @Override + public final L findCounterExample(A hypothesis, Collection inputs, String formula) throws ModelCheckingException { + + final File etf, gcf; + try { + // create the ETF that will contain the LTS of the hypothesis + etf = File.createTempFile("automaton2etf", ".etf"); + + // create the GCF that will possibly contain the counterexample + gcf = File.createTempFile("etf2gcf", ".gcf"); + + // write to the ETF file + automaton2ETF(hypothesis, inputs, etf); + + } catch (IOException ioe) { + throw new ModelCheckingException(ioe); + } + + // the command lines for the ProcessBuilder + final List commandLines = new ArrayList<>(); + + // add the etf2lts-mc binary + commandLines.add(ETF2LTS_MC); + + // add the ETF file that contains the LTS of the hypothesis + commandLines.add(etf.getAbsolutePath()); + + // add the LTL formula + commandLines.add("--ltl=" + formula); + + // use Buchi automata created by spot + commandLines.add("--buchi-type=spotba"); + + // use the Union-Find strategy + commandLines.add("--strategy=ufscc"); + + // write the lasso to this file + commandLines.add("--trace=" + gcf.getAbsolutePath()); + + // use only one thread (hypotheses are always small) + commandLines.add("--threads=1"); + + // use LTSmin LTL semantics + commandLines.add("--ltl-semantics=ltsmin"); + + // do not abort on partial LTSs + commandLines.add("--allow-undefined-edges"); + + final Process ltsmin; + try { + // run the etf2lts-mc binary + ProcessBuilder processBuilder = new ProcessBuilder(commandLines); + if (inheritIO) { + processBuilder = processBuilder.inheritIO(); + } + ltsmin = processBuilder.start(); + ltsmin.waitFor(); + } catch (IOException | InterruptedException e) { + throw new ModelCheckingException(e); + } + + // check if we need to delete the ETF + if (!keepFiles && !etf.delete()) { + throw new ModelCheckingException("Could not delete file: " + etf.getAbsolutePath()); + } + + final L result; + + if (ltsmin.exitValue() == 1) { + // we have found a counterexample + commandLines.clear(); + + final File fsm; + try { + // create a file for the FSM + fsm = File.createTempFile("gcf2fsm", ".fsm"); + } catch (IOException ioe) { + throw new ModelCheckingException(ioe); + } + + // add the ltsmin-convert binary + commandLines.add(LTSMIN_CONVERT); + + // use the GCF as input + commandLines.add(gcf.getAbsolutePath()); + + // use the FSM as output + commandLines.add(fsm.getAbsolutePath()); + + // required option + commandLines.add("--rdwr"); + + final Process convert; + try { + // convert the GCF to FSM + ProcessBuilder processBuilder = new ProcessBuilder(commandLines); + if (inheritIO) { + processBuilder = processBuilder.inheritIO(); + } + convert = processBuilder.start(); + convert.waitFor(); + } catch (IOException | InterruptedException e) { + throw new ModelCheckingException(e); + } + + // check the conversion is successful + if (convert.exitValue() != 0) { + throw new ModelCheckingException("Could not convert gcf to fsm"); + } + + try { + // convert the FSM to a Lasso + result = fsm2Lasso(fsm, hypothesis); + + // check if we must keep the FSM file + if (!keepFiles && !fsm.delete()) { + throw new ModelCheckingException("Could not delete file: " + fsm.getAbsolutePath()); + } + } catch (IOException | FSMParseException e) { + throw new ModelCheckingException(e); + } + } else { + result = null; + } + + // check if we must keep the GCF + if (!keepFiles && !gcf.delete()) { + throw new ModelCheckingException("Could not delete file: " + gcf.getAbsolutePath()); + } + + return result; + } + + /** + * Checks whether the given binary can be executed, by performing a version check. + * + * @param bin the binary to check. + * + * @throws ModelCheckingException when the given binary can not be run successfully. + */ + private void checkBinary(String bin) throws ModelCheckingException { + + // the command lines for the ProcessBuilder + final List commandLines = new ArrayList<>(); + + // add the binary + commandLines.add(bin); + + // just run a version check + commandLines.add("--version"); + + final Process check; + try { + ProcessBuilder processBuilder = new ProcessBuilder(commandLines); + if (inheritIO) { + processBuilder = processBuilder.inheritIO(); + } + check = processBuilder.start(); + check.waitFor(); + } catch (IOException | InterruptedException e) { + throw new ModelCheckingException(String.format(CHECK, bin, e.toString())); + } + + if (check.exitValue() != VERSION_EXIT) { + throw new ModelCheckingException( + String.format(CHECK, bin, String.format("Command '%s --version' did not exit with 255", bin))); + } + } + + public static class BuilderDefaults { + + public static boolean keepFiles() { + return false; + } + + public static int minimumUnfolds() { + return 3; // super arbitrary number + } + + public static double multiplier() { + return 1.0; // quite arbitrary too + } + + public static boolean inheritIO() { + return false; + } + } +} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java new file mode 100644 index 0000000000..222b7f0588 --- /dev/null +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java @@ -0,0 +1,170 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.function.Function; + +import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelChecker; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelCheckerLasso; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.serialization.fsm.parser.FSMParseException; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.util.automata.transout.MealyFilter; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * An LTL model checker using LTSmin for Mealy machines. + * + * A feature of this {@link de.learnlib.api.modelchecking.modelchecker.ModelChecker}, is that one can remove + * particular output symbols from the a given MealyMachine hypothesis. This is useful when those symbols are actually + * symbols representing system deadlocks. When checking LTL formulae special attention has to be given to deadlock + * situations. + * + * @author Jeroen Meijer + * + * @param the input type. + * @param the output type. + */ +public abstract class AbstractLTSminLTLMealy + extends AbstractLTSminLTL, MealyLasso> + implements MealyModelChecker>, MealyModelCheckerLasso { + + /** + * @see #getString2Output() + */ + private final Function string2Output; + + /** + * @see #getSkipOutputs() + * @see #setSkipOutputs(Collection) + */ + private Collection skipOutputs; + + /** + * Constructs a new AbstractLTSminLTLMealy. + * + * @param string2Output the function that transforms edges in the FSM file to actual output. + * @param skipOutputs the set of outputs that need to be skipped while writing the Mealy machine to ETF. + * + * @see AbstractLTSminLTL + */ + protected AbstractLTSminLTLMealy( + boolean keepFiles, + Function string2Input, + Function string2Output, + int minimumUnfolds, + double multiplier, + boolean inheritIO, + Collection skipOutputs) { + super(keepFiles, string2Input, minimumUnfolds, multiplier, inheritIO); + this.string2Output = string2Output; + this.skipOutputs = skipOutputs == null ? Collections.emptyList() : skipOutputs; + } + + /** + * Gets a function that transforms edges in the FSM file to actual output. + * + * @return the Function. + */ + public Function getString2Output() { + return string2Output; + } + + /** + * Gets a set of outputs that need to be skipped while writing the Mealy machine to ETF. + * + * @return the Colleciton. + */ + public Collection getSkipOutputs() { + return skipOutputs; + } + + /** + * Sets a set of outputs that need to be skipped while writing the Mealy machine to ETF. + */ + public void setSkipOutputs(Collection skipOutputs) { + this.skipOutputs = skipOutputs; + } + + /** + * Converts the given {@code fsm} to a {@link CompactMealy}. + * + * @param fsm the FSM to convert. + * + * @return the {@link CompactMealy}. + * + * @throws IOException when {@code fsm} can not be read. + * @throws FSMParseException when {@code fsm} is invalid. + */ + protected abstract CompactMealy fsm2Mealy(File fsm) throws IOException, FSMParseException; + + /** + * Writes the {@link MealyMachine} to the {@code etf} file while pruning way the outputs given in + * {@link #getSkipOutputs()}. + * + * @param mealyMachine the {@link MealyMachine} to write. + * + * @see AbstractLTSminLTL#automaton2ETF(SimpleDTS, Collection, File) + * + * @throws IOException see {@link #mealy2ETF(MealyMachine, Collection, File)}. + */ + @Override + protected final void automaton2ETF(MealyMachine mealyMachine, Collection inputs, File etf) + throws IOException { + final Alphabet alphabet = Alphabets.fromCollection(inputs); + mealy2ETF(MealyFilter.pruneTransitionsWithOutput(mealyMachine, alphabet, skipOutputs), inputs, etf); + } + + /** + * Writes the given {@link MealyMachine} to the {@code etf} file. + * + * @param automaton the {@link MealyMachine} to write. + * @param inputs the alphabet. + * @param etf the file to write to. + * + * @throws IOException when {@code etf} can not be read. + */ + protected abstract void mealy2ETF(MealyMachine automaton, Collection inputs, File etf) + throws IOException; + + /** + * Converts the FSM to a Lasso. + * + * @param fsm the FSM to read. + * @param hypothesis the hypothesis used to compute the number of loop unfolds. + * + * @return the {@link MealyLasso}. + * + * @throws IOException see {@link #fsm2Mealy(File)}. + * @throws FSMParseException see {@link #fsm2Mealy(File)}. + */ + @Override + protected final MealyLasso fsm2Lasso(File fsm, MealyMachine hypothesis) + throws IOException, FSMParseException { + CompactMealy mealy = fsm2Mealy(fsm); + // miniminzation is generally not possible, since a Lasso is partial. + // mealy = HopcroftMinimization.minimizeMealy(mealy); + + return new MealyLasso<>(mealy, mealy.getInputAlphabet(), computeUnfolds(hypothesis.size())); + } +} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelChecker.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelChecker.java new file mode 100644 index 0000000000..540202c7b4 --- /dev/null +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelChecker.java @@ -0,0 +1,113 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import de.learnlib.api.modelchecking.counterexample.Lasso; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.ModelCheckerLasso; +import net.automatalib.automata.concepts.Output; +import net.automatalib.ts.simple.SimpleDTS; + +/** + * An {@link ModelCheckerLasso} that can unfold loops of lassos. + * + * Unfolding a lasso is done according to two conditions: + * 1. the lasso has to be unfolded a minimum number of times ({@link #getMinimumUnfolds()}. + * 2. the lasso has to be unfolded relative to the number of states in an hypothesis, multiplied by some double + * ({@link #getMultiplier()}. + * + * Note that one can unfold a lasso a fixed number of times if the multiplier is set to {@code 0.0}. + * Also note that a lasso needs to be unfolded at least once, and the multiplier can not be negative. + * + * @param the input type + * @param the automaton type + * @param

the property type + * @param the Lasso type + */ +public abstract class AbstractUnfoldingModelChecker & Output, + P, + L extends Lasso> + implements ModelCheckerLasso { + + /** + * The minimum number of unfolds. + * + * @see AbstractUnfoldingModelChecker + */ + private int minimumUnfolds; + + /** + * The multiplier. + * + * @see AbstractUnfoldingModelChecker + */ + private double multiplier; + + /** + * Constructs a new AbstractUnfoldingModelChecker. + * + * @param minimumUnfolds the minimum number of unfolds. + * @param multiplier the multiplier + * + * @throws IllegalArgumentException when {@code minimumUnfolds < 1 || multiplier < 0.0}. + */ + protected AbstractUnfoldingModelChecker(int minimumUnfolds, double multiplier) throws IllegalArgumentException { + setMinimumUnfolds(minimumUnfolds); + setMultiplier(multiplier); + } + + /** + * Compute the number of unfolds according to {@code size}. + * + * @param size the number of states in the hypothesis. + * + * @return the number of times the loop of a lasso has to be unfolded. + */ + protected final int computeUnfolds(int size) { + if (size < 1) { + throw new IllegalArgumentException("Illegal size: " + size); + } + final int relativeUnfolds = (int) Math.ceil(size * multiplier); + return Math.max(minimumUnfolds, relativeUnfolds); + } + + @Override + public int getMinimumUnfolds() { + assert minimumUnfolds > 0; + return minimumUnfolds; + } + + @Override + public void setMinimumUnfolds(int minimumUnfolds) throws IllegalArgumentException { + if (minimumUnfolds < 1) { + throw new IllegalArgumentException("must unfold at least once"); + } + this.minimumUnfolds = minimumUnfolds; + } + + @Override + public void setMultiplier(double multiplier) throws IllegalArgumentException { + if (multiplier < 0.0) { + throw new IllegalArgumentException("multiplier must be >= 0.0"); + } + this.multiplier = multiplier; + } + + @Override + public double getMultiplier() { + return multiplier; + } +} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java new file mode 100644 index 0000000000..409c5545c9 --- /dev/null +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java @@ -0,0 +1,68 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.function.Function; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.serialization.etf.writer.Mealy2ETFWriterAlternating; +import net.automatalib.serialization.fsm.parser.FSM2MealyParserAlternating; +import net.automatalib.serialization.fsm.parser.FSMParseException; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * An LTL model checker using LTSmin for Mealy machines using alternating edge semantics. + * + * The implementation uses {@link FSM2MealyParserAlternating}, and {@link Mealy2ETFWriterAlternating}, to read the + * {@link de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso}, and write the {@link MealyMachine} + * respectively. + * + * @author Jeroen Meijer + * + * @param the input type + * @param the output type + */ +public class LTSminLTLAlternating extends AbstractLTSminLTLMealy { + + @GenerateBuilder(defaults = BuilderDefaults.class) + public LTSminLTLAlternating(boolean keepFiles, + Function string2Input, + Function string2Output, + int minimumUnfolds, + double multiplier, + boolean inheritIO, + Collection skipOutputs) { + super(keepFiles, string2Input, string2Output, minimumUnfolds, multiplier, inheritIO, skipOutputs); + } + + @Override + protected CompactMealy fsm2Mealy(File fsm) throws IOException, FSMParseException { + return FSM2MealyParserAlternating.parse(fsm, getString2Input(), getString2Output()); + } + + @Override + protected void mealy2ETF(MealyMachine automaton, Collection inputs, File etf) + throws IOException { + final Alphabet alphabet = Alphabets.fromCollection(inputs); + Mealy2ETFWriterAlternating.write(etf, automaton, alphabet); + } +} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java new file mode 100644 index 0000000000..e83f72c771 --- /dev/null +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java @@ -0,0 +1,129 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.function.Function; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import de.learnlib.api.exception.ModelCheckingException; +import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelCheckerLasso; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.MutableDFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.serialization.etf.writer.DFA2ETFWriter; +import net.automatalib.serialization.fsm.parser.FSM2DFAParser; +import net.automatalib.serialization.fsm.parser.FSMParseException; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.util.automata.copy.AutomatonCopyMethod; +import net.automatalib.util.automata.copy.AutomatonLowLevelCopy; +import net.automatalib.util.automata.fsa.DFAs; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * An LTL model checker using LTSmin for DFAs. + * + * An important feature of this {@link de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelChecker}, is + * that it will check if a given DFA hypothesis is prefix-closed. + * + * Another important feature is that rejecting states are NOT part of the LTS. This avoids the need for an + * unconditional fairness constraint in LTL formulae. + * + * @author Jeroen Meijer + * + * @see DFAs#isPrefixClosed(DFA, Alphabet) + * + * @param the input type + */ +public class LTSminLTLDFA + extends AbstractLTSminLTL, DFALasso> + implements DFAModelCheckerLasso { + + /** + * The index in the FSM state vector for accept/reject. + */ + public static final String LABEL_NAME = "label"; + + /** + * The value in the state vector for acceptance. + */ + public static final String LABEL_VALUE = "accept"; + + @GenerateBuilder(defaults = BuilderDefaults.class) + public LTSminLTLDFA(boolean keepFiles, + Function string2Input, + int minimumUnfolds, + double multiplier, + boolean inheritIO) { + super(keepFiles, string2Input, minimumUnfolds, multiplier, inheritIO); + } + + + @Override + protected void automaton2ETF(DFA automaton, Collection inputs, File etf) throws IOException { + dfa2ETF(automaton, inputs, etf); + } + + /** + * Writes the given {@code dfa} to {@code etf}, while skipping rejecting states. + * + * @param dfa the DFA to write. + * @param inputs the alphabet. + * @param etf the file to write to. + * + * @param the state type + * + * @throws IOException see {@link DFA2ETFWriter#write(File, DFA, Alphabet)}. + */ + private void dfa2ETF(DFA dfa, Collection inputs, File etf) throws IOException { + // check that the DFA rejects the empty language + if (DFAs.acceptsEmptyLanguage(dfa)) { + throw new ModelCheckingException("DFA accepts the empty language, the LTS for such a DFA is not defined."); + } + + final Alphabet alphabet = Alphabets.fromCollection(inputs); + + // check the DFA is prefix-closed + if (!DFAs.isPrefixClosed(dfa, alphabet)) { + throw new ModelCheckingException("DFA is not prefix closed."); + } + + // remove all rejecting states + final MutableDFA copy = new CompactDFA<>(alphabet, dfa.size()); + AutomatonLowLevelCopy.copy(AutomatonCopyMethod.STATE_BY_STATE, dfa, inputs, copy, s -> dfa.isAccepting(s), (s, i, t) -> true); + DFA2ETFWriter.write(etf, copy, alphabet); + } + + /** + * Converts the FSM file to a {@link DFALasso}. + * + * @param hypothesis the DFA used to compute the number of loop unrolls. + * + * @see AbstractLTSminLTL#fsm2Lasso(File, SimpleDTS) + */ + @Override + protected DFALasso fsm2Lasso(File fsm, DFA hypothesis) throws IOException, FSMParseException { + CompactDFA dfa = FSM2DFAParser.parse(fsm, getString2Input(), LABEL_NAME, LABEL_VALUE); + //dfa = DFAs.complete(dfa, dfa.getInputAlphabet()); + //dfa = HopcroftMinimization.minimizeDFA(dfa, dfa.getInputAlphabet()); + + return new DFALasso<>(dfa, dfa.getInputAlphabet(), computeUnfolds(hypothesis.size())); + } +} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java new file mode 100644 index 0000000000..5ca6108437 --- /dev/null +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java @@ -0,0 +1,70 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.function.Function; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.serialization.etf.writer.Mealy2ETFWriterIO; +import net.automatalib.serialization.fsm.parser.FSM2MealyParserIO; +import net.automatalib.serialization.fsm.parser.FSMParseException; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * An LTL model checker using LTSmin for Mealy machines using alternating edge semantics. + * + * The implementation uses {@link FSM2MealyParserIO}, and {@link Mealy2ETFWriterIO}, to read the + * {@link de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso}, and write the {@link MealyMachine} + * respectively. + * + * @author Jeroen Meijer + * + * @param the input type + * @param the output type + */ +public class LTSminLTLIO extends AbstractLTSminLTLMealy { + + @GenerateBuilder(defaults = BuilderDefaults.class) + public LTSminLTLIO( + boolean keepFiles, + Function string2Input, + Function string2Output, + int minimumUnfolds, + double multiplier, + boolean inheritIO, + Collection skipOutputs) { + super(keepFiles, string2Input, string2Output, minimumUnfolds, multiplier, inheritIO, skipOutputs); + } + + @Override + protected CompactMealy fsm2Mealy(File fsm) throws IOException, FSMParseException { + final CompactMealy mealy = FSM2MealyParserIO.parse(fsm, getString2Input(), getString2Output()); + return mealy; + } + + @Override + protected void mealy2ETF(MealyMachine automaton, Collection inputs, File etf) + throws IOException { + final Alphabet alphabet = Alphabets.fromCollection(inputs); + Mealy2ETFWriterIO.write(etf, automaton, alphabet); + } +} diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java new file mode 100644 index 0000000000..266e1c8770 --- /dev/null +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java @@ -0,0 +1,66 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import java.io.File; +import java.util.HashSet; + +import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +/** + * @author Jeroen Meijer + */ +public abstract class AbstractLTSminLTLMealyTest> + extends AbstractLTSminLTLTest, M, MealyLasso> { + + @SuppressWarnings("unchecked") + @Test + public void testSkipOutputs() throws Exception { + final HashSet skip = new HashSet<>(); + skip.add("1"); + getModelChecker().setSkipOutputs(skip); + + final Alphabet alphabet = Alphabets.fromArray("a"); + final MealyMachine mealy = AutomatonBuilders.forMealy( + new CompactMealy(alphabet) + ).from("q0").on("a").withOutput("1").loop().withInitial("q0").create(); + + AbstractLTSminLTLMealy spy = Mockito.spy(getModelChecker()); + + File etf = File.createTempFile("tmp", ".etf"); + etf.deleteOnExit(); + + spy.automaton2ETF(mealy, alphabet, etf); + + // test the transition is removed from the Mealy machine + ArgumentCaptor> modifiedMealy = ArgumentCaptor.forClass(MealyMachine.class); + Mockito.verify(spy).mealy2ETF(modifiedMealy.capture(), Mockito.eq(alphabet), Mockito.eq(etf)); + Assert.assertEquals(modifiedMealy.getValue().computeOutput(Word.fromSymbols("a")), Word.epsilon()); + if (!etf.delete()) { + throw new Exception(); + } + } +} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java new file mode 100644 index 0000000000..ed400f8046 --- /dev/null +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java @@ -0,0 +1,90 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import de.learnlib.api.modelchecking.counterexample.Lasso; +import net.automatalib.automata.concepts.Output; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Tests for AbstractLTSminLTL with arbitrary LTSs. + * + * @author Jeroen Meijer + */ +public abstract class AbstractLTSminLTLTest & Output, + M extends AbstractLTSminLTL, + L extends Lasso> + extends AbstractUnfoldingModelCheckerTest { + + private static String ltsminPathPropertyDefault; + + private final Alphabet alphabet = Alphabets.fromArray("a", "b"); + + private L lasso; + + private A automaton; + + private String falseProperty; + + public Alphabet getAlphabet() { + return alphabet; + } + + protected abstract L createLasso(); + + protected abstract A createAutomaton(); + + protected abstract String createFalseProperty(); + + @BeforeClass + public static void setUpBeforeClass() { + ltsminPathPropertyDefault = System.getProperty(AbstractLTSminLTL.LTSMIN_PATH_PROPERTY); + } + + @Before + public void setUp() throws Exception { + super.setUp(); + lasso = createLasso(); + automaton = createAutomaton(); + falseProperty = createFalseProperty(); + } + + @After + public void tearDown() { + if (ltsminPathPropertyDefault != null) { + System.setProperty(AbstractLTSminLTL.LTSMIN_PATH_PROPERTY, ltsminPathPropertyDefault); + } + } + + /** + * First test for the absence of a counterexample, then test for the presence. + */ + @Test + public void testFindCounterExample() { + Object lasso = getModelChecker().findCounterExample(automaton, alphabet, "true"); + Assert.assertNull(lasso); + + L actualLasso = getModelChecker().findCounterExample(automaton, alphabet, falseProperty); + Assert.assertEquals(actualLasso.getWord(), this.lasso.getWord()); + } +} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java new file mode 100644 index 0000000000..abaa917aa3 --- /dev/null +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java @@ -0,0 +1,73 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Jeroen Meijer + */ +public abstract class AbstractUnfoldingModelCheckerTest> { + + private M modelChecker; + + public M getModelChecker() { + return modelChecker; + } + + protected abstract M createModelChecker(); + + @Before + public void setUp() throws Exception { + modelChecker = createModelChecker(); + } + + @Test + public void testComputeUnfolds() throws Exception { + Assert.assertEquals(modelChecker.computeUnfolds(1), 3); + modelChecker.setMultiplier(2.0); + Assert.assertEquals(modelChecker.computeUnfolds(2), 4); + } + + @Test(expected = IllegalArgumentException.class) + public void testComputeUnfoldsExcept() { + modelChecker.computeUnfolds(0); + } + + @Test + public void testSetMinimumUnfolds() throws Exception { + modelChecker.setMinimumUnfolds(1337); + Assert.assertEquals(modelChecker.getMinimumUnfolds(), 1337); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetMinimumUnfoldsExcept() { + modelChecker.setMinimumUnfolds(0); + } + + @Test + public void testSetMultiplier() throws Exception { + modelChecker.setMultiplier(1337.0); + Assert.assertEquals(modelChecker.getMultiplier(), 1337.0, 0.0); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetMultiplierExcept() { + modelChecker.setMultiplier(-1.0); + } +} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternatingTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternatingTest.java new file mode 100644 index 0000000000..504fa93f93 --- /dev/null +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternatingTest.java @@ -0,0 +1,54 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.util.automata.builders.AutomatonBuilders; + +/** + * Tests whether LTSminLTLAlternating actually uses alternating edge semantics. + * + * @see LTSminLTLIOTest + * + * @author Jeroen Meijer + */ +public class LTSminLTLAlternatingTest extends AbstractLTSminLTLMealyTest> { + + @Override + protected LTSminLTLAlternating createModelChecker() { + return new LTSminLTLAlternatingBuilder().withString2Input(s -> s). + withString2Output(s -> s).create(); + } + + @Override + protected MealyLasso createLasso() { + return new MealyLasso<>(createAutomaton(), getAlphabet(), 4); + } + + @Override + protected MealyMachine createAutomaton() { + return AutomatonBuilders.forMealy(new CompactMealy(getAlphabet())). + withInitial("q0"). + from("q0").on("a").withOutput("1").loop().create(); + } + + @Override + protected String createFalseProperty() { + return "X letter == \"a\""; + } +} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java new file mode 100644 index 0000000000..19f7206b53 --- /dev/null +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java @@ -0,0 +1,73 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import de.learnlib.api.exception.ModelCheckingException; +import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import org.junit.Test; + +/** + * @author Jeroen Meijer + */ +public class LTSminLTLDFATest extends AbstractLTSminLTLTest, LTSminLTLDFA, DFALasso> { + + @Override + protected LTSminLTLDFA createModelChecker() { + return new LTSminLTLDFABuilder().withString2Input(s -> s).create(); + } + + @Override + protected DFALasso createLasso() { + return new DFALasso<>(createAutomaton(), getAlphabet(), 4); + } + + @Override + protected DFA createAutomaton() { + return AutomatonBuilders.newDFA(getAlphabet()). + withInitial("q0").withAccepting("q0"). + from("q0").on("a").loop().create(); + } + + @Override + protected String createFalseProperty() { + return "letter == \"b\""; + } + + /** + * Test that a {@link ModelCheckingException} is thrown when a {@link DFA} is not prefix-closed. + */ + @Test(expected = ModelCheckingException.class) + public void testPrefixClosed() { + final DFA dfa = AutomatonBuilders.newDFA(getAlphabet()). + withInitial("q0").withAccepting("q1"). + from("q0").on("a").to("q1").create(); + + getModelChecker().findCounterExample(dfa, getAlphabet(), "true"); + } + + /** + * Test that a {@link ModelCheckingException} is thrown when a {@link DFA} accepts the empty language. + */ + @Test(expected = ModelCheckingException.class) + public void testEmptyLanguage() { + final DFA dfa = AutomatonBuilders.newDFA(getAlphabet()). + withInitial("q0").from("q0").on("a").loop().from("q0").on("b").loop().create(); + + getModelChecker().findCounterExample(dfa, getAlphabet(), "true"); + } +} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIOTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIOTest.java new file mode 100644 index 0000000000..ea42f070af --- /dev/null +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIOTest.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.util.automata.builders.AutomatonBuilders; + +/** + * Tests whether LTSminLTLAlternating actually uses regular edge semantics. + * + * @see LTSminLTLAlternatingTest + * + * @author Jeroen Meijer + */ +public class LTSminLTLIOTest extends AbstractLTSminLTLMealyTest> { + + @Override + protected LTSminLTLIO createModelChecker() { + return new LTSminLTLIOBuilder().withString2Input(s -> s).withString2Output(s -> s).create(); + } + + @Override + protected MealyLasso createLasso() { + return new MealyLasso<>(createAutomaton(), getAlphabet(), 4); + } + + @Override + protected MealyMachine createAutomaton() { + return AutomatonBuilders.forMealy(new CompactMealy(getAlphabet())). + withInitial("q0"). + from("q0").on("a").withOutput("1").loop().create(); + } + + @Override + protected String createFalseProperty() { + return "input == \"b\""; + } +} \ No newline at end of file diff --git a/model-checkers/src/test/resources/test.etf b/model-checkers/src/test/resources/test.etf new file mode 100644 index 0000000000..90b4450941 --- /dev/null +++ b/model-checkers/src/test/resources/test.etf @@ -0,0 +1,26 @@ +begin state +id:id +end state +begin edge +letter:letter +end edge +begin init +0 +end init +begin sort id +"0" +end sort +begin sort letter +"a" +"b" +end sort +begin trans +0/0 0 +end trans +begin sort label +"reject" +"accept" +end sort +begin map label:label +0 1 +end map \ No newline at end of file diff --git a/model-checkers/src/test/resources/test.fsm b/model-checkers/src/test/resources/test.fsm new file mode 100644 index 0000000000..ba8b550409 --- /dev/null +++ b/model-checkers/src/test/resources/test.fsm @@ -0,0 +1,9 @@ +ltl(0) buchi +id(1) id "0" +label(2) label "reject" "accept" +buchi_accept(0) LTL_bool +weak_ltl_progress(0) LTL_bool +--- + 0 0 1 1 0 +--- +1 1 "a" diff --git a/oracles/black-box-oracles/pom.xml b/oracles/black-box-oracles/pom.xml new file mode 100644 index 0000000000..fb597fe678 --- /dev/null +++ b/oracles/black-box-oracles/pom.xml @@ -0,0 +1,60 @@ + + + + + learnlib-oracles-parent + de.learnlib + 0.14.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + learnlib-black-box-oracles + LearnLib :: Oracles :: Black-Box Oracles + A collection of black-box oracles + + + de.learnlib + learnlib-api + + + org.mockito + mockito-core + test + + + com.google.code.findbugs + jsr305 + + + net.automatalib + automata-core + + + net.automatalib + automata-api + + + junit + junit + test + + + \ No newline at end of file diff --git a/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java b/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java new file mode 100644 index 0000000000..6174d4d257 --- /dev/null +++ b/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java @@ -0,0 +1,76 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.blackbox; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import de.learnlib.api.oracle.BlackBoxOracle; +import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; + +/** + * A {@link BlackBoxOracle} that contains a set of {@link BlackBoxProperty}s. + * + * @author Jeroen Meijer + * + * @param the automaton type + * @param the input type + * @param the output type + * @param

the BlackBoxProperty type + */ +public abstract class AbstractBlackBoxOracle> + implements BlackBoxOracle { + + /** + * The set of properties that need to be verified. + */ + private final Set

properties; + + /** + * Constructs a new {@link AbstractBlackBoxOracle} with a set of properties. + * + * @param properties the set of {@link BlackBoxProperty}s that need to be verified. + */ + protected AbstractBlackBoxOracle(Set

properties) { + this.properties = new HashSet<>(); + this.properties.addAll(properties); + for (P p : this.properties) { + p.useCache(); + } + } + + /** + * Constructs a new {@link AbstractBlackBoxOracle} with a single property. + * + * @param property the {@link BlackBoxProperty}. + */ + protected AbstractBlackBoxOracle(P property) { + this(Collections.singleton(property)); + } + + /** + * Constructs a new {@link AbstractBlackBoxOracle} with no properties. + */ + protected AbstractBlackBoxOracle() { + this(Collections.emptySet()); + } + + @Override + public Set

getProperties() { + return properties; + } +} diff --git a/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java b/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java new file mode 100644 index 0000000000..12e0e63536 --- /dev/null +++ b/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java @@ -0,0 +1,121 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.blackbox; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import javax.annotation.Nullable; + +import de.learnlib.api.exception.ModelCheckingException; +import de.learnlib.api.oracle.BlackBoxOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +/** + * A {@link de.learnlib.api.oracle.BlackBoxOracle} that first tries to disprove a property, but before trying to + * disprove the next property, first try to find a counterexample to the current hypothesis. + * + * This implementation may be used when refining a hypothesis is inexpensive compared to disproving properties. + * + * This oracle will use a cache on each {@link BlackBoxProperty}. + * + * @author Jeroen Meijer + * + * @see DisproveFirstBBOracle + * + * @param the automaton type. + * @param the input type. + * @param the output type. + * @param

the {@link BlackBoxProperty} type. + */ +public class CExFirstBBOracle> + extends AbstractBlackBoxOracle { + + public CExFirstBBOracle(Set

properties) { + super(properties); + } + + public CExFirstBBOracle(P property) { + super(property); + } + + public CExFirstBBOracle() { + super(); + } + + /** + * Find a counterexample to the given hypothesis according to strategy described at {@link CExFirstBBOracle}. + * + * @see de.learnlib.api.oracle.BlackBoxOracle#findCounterExample(Object, Collection) + */ + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { + DefaultQuery result = null; + final List

properties = new ArrayList<>(getProperties()); + for (int i = 0; i < properties.size() && result == null; i++) { + final P p = properties.get(i); + if (!p.isDisproved()) { + final DefaultQuery ce = p.disprove(hypothesis, inputs); + if (ce == null) { + result = p.findCounterExample(hypothesis, inputs); + } + p.clearCache(); + } + } + + return result; + } + + public static class CExFirstDFABBOracle + extends CExFirstBBOracle, I, Boolean, DFABlackBoxProperty> + implements DFABlackBoxOracle { + + public CExFirstDFABBOracle(Set> properties) { + super(properties); + } + + public CExFirstDFABBOracle(DFABlackBoxProperty property) { + super(property); + } + + public CExFirstDFABBOracle() { + super(); + } + } + + public static class CExFirstMealyBBOracle + extends CExFirstBBOracle, I, Word, MealyBlackBoxProperty> + implements MealyBlackBoxOracle { + + public CExFirstMealyBBOracle(Set> properties) { + super(properties); + } + + public CExFirstMealyBBOracle(MealyBlackBoxProperty property) { + super(property); + } + + public CExFirstMealyBBOracle() { + super(); + } + } +} diff --git a/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java b/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java new file mode 100644 index 0000000000..4e7240fb12 --- /dev/null +++ b/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java @@ -0,0 +1,121 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.blackbox; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import javax.annotation.Nullable; + +import de.learnlib.api.exception.ModelCheckingException; +import de.learnlib.api.oracle.BlackBoxOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +/** + * A {@link de.learnlib.api.oracle.BlackBoxOracle} that first tries to disprove all properties before finding a + * counterexample to the current hypothesis. + * + * One may favor this implementation if refining a hypothesis is expensive compared to trying to disprove properties. + * + * @author Jeroen Meijer + * + * @param the automaton type. + * @param the input type. + * @param the output type. + * @param

the {@link BlackBoxProperty} type. + */ +public class DisproveFirstBBOracle> + extends AbstractBlackBoxOracle { + + public DisproveFirstBBOracle(Set

properties) { + super(properties); + } + + public DisproveFirstBBOracle(P property) { + super(property); + } + + public DisproveFirstBBOracle() { + super(); + } + + /** + * Find a counterexample to the current hypothesis according to the strategy described at + * {@link DisproveFirstBBOracle}. + * + * @see de.learnlib.api.oracle.BlackBoxOracle#findCounterExample(Object, Collection) + */ + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { + for (P p : getProperties()) { + if (!p.isDisproved()) { + p.disprove(hypothesis, inputs); + } + } + + DefaultQuery ce = null; + final List

properties = new ArrayList<>(getProperties()); + for (int i = 0; i < properties.size() && ce == null; i++) { + final P p = properties.get(i); + if (!p.isDisproved()) { + ce = p.findCounterExample(hypothesis, inputs); + p.clearCache(); + } + } + + return ce; + } + + public static class DisproveFirstDFABBOracle + extends DisproveFirstBBOracle, I, Boolean, DFABlackBoxProperty> + implements DFABlackBoxOracle { + + public DisproveFirstDFABBOracle(Set> properties) { + super(properties); + } + + public DisproveFirstDFABBOracle(DFABlackBoxProperty property) { + super(property); + } + + public DisproveFirstDFABBOracle() { + super(); + } + } + + public static class DisproveFirstMealyBBOracle + extends DisproveFirstBBOracle, I, Word, MealyBlackBoxProperty> + implements MealyBlackBoxOracle { + + public DisproveFirstMealyBBOracle(Set> properties) { + super(properties); + } + + public DisproveFirstMealyBBOracle(MealyBlackBoxProperty property) { + super(property); + } + + public DisproveFirstMealyBBOracle() { + super(); + } + } +} diff --git a/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java b/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java new file mode 100644 index 0000000000..f41d92f296 --- /dev/null +++ b/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java @@ -0,0 +1,279 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.blackbox; + +import java.util.Collection; + +import javax.annotation.Nullable; + +import de.learnlib.api.exception.ModelCheckingException; +import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; +import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelChecker; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelCheckerLasso; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelChecker; +import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelCheckerLasso; +import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; +import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxProperty; +import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.EmptinessOracle.DFAEmptinessOracle; +import de.learnlib.api.oracle.EmptinessOracle.DFALassoEmptinessOracle; +import de.learnlib.api.oracle.EmptinessOracle.MealyEmptinessOracle; +import de.learnlib.api.oracle.EmptinessOracle.MealyLassoEmptinessOracle; +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.InclusionOracle.DFAInclusionOracle; +import de.learnlib.api.oracle.InclusionOracle.MealyInclusionOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Word; + +/** + * A {@link BlackBoxProperty} that needs a {@link ModelChecker} to verify. + * + * The main part of the implementation involves caching results in between calls to + * {@link #disprove(Output, Collection)} {@link #findCounterExample(Output, Collection)}. + * + * @author Jeroen Meijer + * + * @param

the property type. + * @param the automaton type. + * @param the input type. + * @param the output type. + * @param the result type of the {@link ModelChecker}. + */ +public class ModelCheckingBBProperty & SimpleDTS, I, D, R extends A> + implements BlackBoxProperty { + + /** + * The property to check. + */ + private P property; + + private ModelChecker modelChecker; + + private EmptinessOracle emptinessOracle; + + private InclusionOracle inclusionOracle; + + /** + * The cached result of a model checking counterexample. + */ + private R cacheResult; + + /** + * The inputs used to find the cached result. + */ + private Collection cacheInputs; + + /** + * The counterexample for this property. + */ + private R modelCheckingResult; + + /** + * The counterexample for this property as a {@link DefaultQuery}. + */ + private DefaultQuery counterExample; + + /** + * Whether to use the cache. + */ + private boolean cache; + + public ModelCheckingBBProperty( + ModelChecker modelChecker, + EmptinessOracle emptinessOracle, + InclusionOracle inclusionOracle, + P property) { + this.modelChecker = modelChecker; + this.emptinessOracle = emptinessOracle; + this.inclusionOracle = inclusionOracle; + this.property = property; + } + + public ModelChecker getModelChecker() { + return modelChecker; + } + + public void setModelChecker(ModelChecker modelChecker) { + this.modelChecker = modelChecker; + } + + public EmptinessOracle getEmptinessOracle() { + return emptinessOracle; + } + + public void setEmptinessOracle(EmptinessOracle emptinessOracle) { + this.emptinessOracle = emptinessOracle; + } + + public InclusionOracle getInclusionOracle() { + return inclusionOracle; + } + + public void setInclusionOracle(InclusionOracle inclusionOracle) { + this.inclusionOracle = inclusionOracle; + } + + @Override + public P getProperty() { + return property; + } + + @Override + public void setProperty(P property) { + this.property = property; + } + + @Override + public boolean isDisproved() { + assert (modelCheckingResult == null) == (counterExample == null); + return counterExample != null; + } + + @Override + @Nullable + public DefaultQuery getCounterExample() { + assert (modelCheckingResult == null) == (counterExample == null); + return counterExample; + } + + /** + * Finds a counterexample for the given {@code hypothesis} to this property. + * + * The model checker will only be invoked in case of a cache-miss. + * + * @param hypothesis the hypothesis. + * @param inputs the alphabet. + * @return the counterexample, or {@code null} if a counterexample could not be found. + * + * @throws ModelCheckingException see ModelChecker{@link #findCounterExample(Output, Collection)}. + */ + @Nullable + private R findCachedCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { + if (!cache || !inputs.equals(cacheInputs)) { + cacheInputs = inputs; + cacheResult = modelChecker.findCounterExample(hypothesis, inputs, property); + } + + return cacheResult; + } + + @Override + public void useCache() { + cache = true; + } + + @Override + public void clearCache() { + cacheInputs = null; + } + + /** + * Try to disprove this property given a {@code hypothesis} by means of an {@link EmptinessOracle}. + * + * @see BlackBoxProperty#disprove(Object, Collection) + */ + @Override + @Nullable + public DefaultQuery disprove(A hypothesis, Collection inputs) throws ModelCheckingException { + modelCheckingResult = findCachedCounterExample(hypothesis, inputs); + if (modelCheckingResult != null) { + counterExample = emptinessOracle.findCounterExample(modelCheckingResult, inputs); + } + return counterExample; + } + + /** + * Try to find a counterexample to the given {@code hypothesis}. + * + * @see BlackBoxProperty#findCounterExample(Object, Collection) + */ + @Override + @Nullable + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { + final R ce = findCachedCounterExample(hypothesis, inputs); + final DefaultQuery result; + if (ce != null) { + result = inclusionOracle.findCounterExample(ce, inputs); + } else { + result = null; + } + return result; + } + + @Override + public String toString() { + return property.toString(); + } + + public static class DFABBPropertyDFA + extends ModelCheckingBBProperty, I, Boolean, DFA> + implements DFABlackBoxProperty { + + public DFABBPropertyDFA( + DFAModelChecker> modelChecker, + DFAEmptinessOracle emptinessOracle, + DFAInclusionOracle inclusionOracle, + P property) { + super(modelChecker, emptinessOracle, inclusionOracle, property); + } + } + + public static class MealyBBPropertyMealy + extends ModelCheckingBBProperty, I, Word, MealyMachine> + implements MealyBlackBoxProperty { + + public MealyBBPropertyMealy( + MealyModelChecker> modelChecker, + MealyEmptinessOracle emptinessOracle, + MealyInclusionOracle inclusionOracle, + P property) { + super(modelChecker, emptinessOracle, inclusionOracle, property); + } + } + + public static class DFABBPropertyDFALasso + extends ModelCheckingBBProperty, I, Boolean, DFALasso> + implements DFABlackBoxProperty { + + public DFABBPropertyDFALasso( + DFAModelCheckerLasso modelChecker, + DFALassoEmptinessOracle emptinessOracle, + DFAInclusionOracle inclusionOracle, + P property) { + super(modelChecker, emptinessOracle, inclusionOracle, property); + } + } + + public static class MealyBBPropertyMealyLasso + extends ModelCheckingBBProperty, I, Word, MealyLasso> + implements MealyBlackBoxProperty { + + public MealyBBPropertyMealyLasso( + MealyModelCheckerLasso modelChecker, + MealyLassoEmptinessOracle emptinessOracle, + MealyInclusionOracle inclusionOracle, + P property) { + super(modelChecker, emptinessOracle, inclusionOracle, property); + } + } +} diff --git a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java b/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java new file mode 100644 index 0000000000..a9fb148f07 --- /dev/null +++ b/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.blackbox; + +import java.util.Set; + +import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; +import net.automatalib.automata.concepts.Output; +import net.automatalib.ts.simple.SimpleDTS; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * @author Jeroen Meijer + */ +@RunWith(MockitoJUnitRunner.class) +public abstract class AbstractBlackBoxOracleTest { + + public abstract AbstractBlackBoxOracle> + getBaseBlackBoxOracle(); + + @Test + public void testAmount() { + final Set> bbps = getBaseBlackBoxOracle().getProperties(); + Assert.assertEquals(bbps.size(), 2); + } + + @Test + public void testCache() { + final Set> bbps = getBaseBlackBoxOracle().getProperties(); + for (BlackBoxProperty bbp : bbps) { + Mockito.verify(bbp).useCache(); + } + } + + interface AutomatonMock extends SimpleDTS, Output {} +} diff --git a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java b/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java new file mode 100644 index 0000000000..a80a5dcf38 --- /dev/null +++ b/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java @@ -0,0 +1,97 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.blackbox; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.words.Alphabet; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * @author Jeroen Meijer + */ +@RunWith(MockitoJUnitRunner.class) +public class CExFirstBBOracleTest extends AbstractBlackBoxOracleTest { + + private CExFirstBBOracle> oracle; + + @Mock + private BlackBoxProperty blackBoxProperty1; + + @Mock + private BlackBoxProperty blackBoxProperty2; + + @Mock + private DefaultQuery defaultQuery; + + @Mock + private AutomatonMock automaton; + + @Mock + private Alphabet alphabet; + + @Before + public void setUp() { + + Mockito.when(blackBoxProperty1.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); + Mockito.when(blackBoxProperty2.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); + + final Set> bbps = new HashSet<>(); + bbps.add(blackBoxProperty1); + bbps.add(blackBoxProperty2); + oracle = new CExFirstBBOracle<>(bbps); + } + + @Override + public AbstractBlackBoxOracle> + getBaseBlackBoxOracle() { + return oracle; + } + + /** + * Tests: + * 1. whether the correct counterexample is given by the {@link CExFirstBBOracle}, and + * 2. whether {@link BlackBoxProperty#disprove(Object, Collection)} is called only on {@link #blackBoxProperty2}. + * + * This method assumes an order on the {@link BlackBoxProperty}s, i.e.: + * {@code oracle.getProperties().iterator().next().equals(blackBoxProperty2}. + */ + @Test + public void testFindCounterExample() { + final DefaultQuery cex = oracle.findCounterExample(automaton, alphabet); + + Assert.assertEquals(cex, defaultQuery); + + final Iterator> it = oracle.getProperties().iterator(); + + final BlackBoxProperty p1 = it.next(); + final BlackBoxProperty p2 = it.next(); + + Mockito.verify(p1).disprove(automaton, alphabet); + Mockito.verify(p2, Mockito.never()).disprove(automaton, alphabet); + } +} \ No newline at end of file diff --git a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java b/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java new file mode 100644 index 0000000000..c5da2b2761 --- /dev/null +++ b/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java @@ -0,0 +1,88 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.blackbox; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.words.Alphabet; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * @author Jeroen Meijer + */ +@RunWith(MockitoJUnitRunner.class) +public class DisproveFirstBBOracleTest extends AbstractBlackBoxOracleTest { + + private DisproveFirstBBOracle> oracle; + + @Mock + private BlackBoxProperty blackBoxProperty1; + + @Mock + private BlackBoxProperty blackBoxProperty2; + + @Mock + private DefaultQuery defaultQuery; + + @Mock + private AutomatonMock automaton; + + @Mock + private Alphabet alphabet; + + @Before + public void setUp() { + + Mockito.when(blackBoxProperty1.findCounterExample(automaton, alphabet)).thenReturn(null); + Mockito.when(blackBoxProperty2.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); + + final Set> bbps = new HashSet<>(); + bbps.add(blackBoxProperty1); + bbps.add(blackBoxProperty2); + oracle = new DisproveFirstBBOracle<>(bbps); + } + + @Override + public AbstractBlackBoxOracle> + getBaseBlackBoxOracle() { + return oracle; + } + + /** + * Tests: + * 1. whether the correct counterexample is given by the {@link DisproveFirstBBOracle}, and + * 2. whether {@link BlackBoxProperty#disprove(Object, Collection)} is called on all {@link BlackBoxProperty}s. + */ + @Test + public void testFindCounterExample() { + final DefaultQuery cex = oracle.findCounterExample(automaton, alphabet); + + Assert.assertEquals(cex, defaultQuery); + + Mockito.verify(blackBoxProperty1).disprove(automaton, alphabet); + Mockito.verify(blackBoxProperty2).disprove(automaton, alphabet); + } +} \ No newline at end of file diff --git a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java b/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java new file mode 100644 index 0000000000..ee862f8267 --- /dev/null +++ b/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java @@ -0,0 +1,130 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.blackbox; + +import java.util.Collection; + +import de.learnlib.api.modelchecking.modelchecker.ModelChecker; +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * Tests the cached, and uncached implementations of {@link ModelCheckingBBProperty#disprove(Output, Collection)}, and + * {@link ModelCheckingBBProperty#findCounterExample(Output, Collection)}. + * + * @author Jeroen Meijer + */ +@RunWith(MockitoJUnitRunner.class) +public class ModelCheckingBBPropertyTest { + + private Alphabet alphabet = Alphabets.fromArray("a"); + + @Mock + private AutomatonMock automaton; + + @Mock + private ResultMock result; + + @Mock + private ModelChecker modelChecker; + + @Mock + private EmptinessOracle> emptinessOracle; + + @Mock + private InclusionOracle> inclusionOracle; + + private ModelCheckingBBProperty mcbbp; + + @Before + public void setUp() { + mcbbp = new ModelCheckingBBProperty<>(modelChecker, emptinessOracle, inclusionOracle, ""); + Mockito.when(modelChecker.findCounterExample(automaton, alphabet, "")).thenReturn(result); + } + + @Test + public void testDisproveUncached() throws Exception { + mcbbp.disprove(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + Mockito.verify(emptinessOracle, Mockito.times(1)).findCounterExample(result, alphabet); + mcbbp.disprove(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(2)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + } + + @Test + public void testDisproveCached() throws Exception { + mcbbp.useCache(); + + mcbbp.disprove(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + Mockito.verify(emptinessOracle, Mockito.times(1)).findCounterExample(result, alphabet); + + mcbbp.disprove(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + + mcbbp.disprove(automaton, Alphabets.singleton("no-cache")); + Mockito.verify(modelChecker, Mockito.times(2)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + + mcbbp.clearCache(); + + mcbbp.disprove(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(3)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + } + + @Test + public void testFindCounterExampleUncached() throws Exception { + mcbbp.findCounterExample(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + Mockito.verify(inclusionOracle, Mockito.times(1)).findCounterExample(result, alphabet); + mcbbp.findCounterExample(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(2)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + } + + @Test + public void testFindCounterExampleCached() throws Exception { + mcbbp.useCache(); + + mcbbp.findCounterExample(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + Mockito.verify(inclusionOracle, Mockito.times(1)).findCounterExample(result, alphabet); + + mcbbp.findCounterExample(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + + mcbbp.findCounterExample(automaton, Alphabets.singleton("no-cache")); + Mockito.verify(modelChecker, Mockito.times(2)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + + mcbbp.clearCache(); + + mcbbp.findCounterExample(automaton, alphabet); + Mockito.verify(modelChecker, Mockito.times(3)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); + } + + interface AutomatonMock extends SimpleDTS, Output {} + + interface ResultMock extends AutomatonMock {} +} \ No newline at end of file diff --git a/oracles/emptiness-oracles/pom.xml b/oracles/emptiness-oracles/pom.xml new file mode 100644 index 0000000000..4bde283311 --- /dev/null +++ b/oracles/emptiness-oracles/pom.xml @@ -0,0 +1,77 @@ + + + + + learnlib-oracles-parent + de.learnlib + 0.14.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + learnlib-emptiness-oracles + LearnLib :: Oracles :: Emptiness Oracles + A collection of emptiness oracles + + + de.learnlib + learnlib-api + + + junit + junit + test + + + org.mockito + mockito-core + test + + + de.learnlib.testsupport + learnlib-oracle-support + + + de.learnlib.testsupport + learnlib-learning-examples + test + + + com.google.code.findbugs + jsr305 + + + net.automatalib + automata-api + + + net.automatalib + automata-core + + + net.automatalib + automata-util + + + de.learnlib + learnlib-util + + + \ No newline at end of file diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java new file mode 100644 index 0000000000..6888b57258 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java @@ -0,0 +1,64 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.util.AbstractBreadthFirstOracle; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Word; + +/** + * An {@link EmptinessOracle} that generates words in a breadth-first manner. + * + * @author Jeroen Meijer + * + * @see EmptinessOracle + * @see AbstractBreadthFirstOracle + */ +@ParametersAreNonnullByDefault +public abstract class AbstractBreadthFirstEmptinessOracle & SimpleDTS, I, D> + extends AbstractBreadthFirstOracle.AbstractDefaultBFOracle + implements EmptinessOracle> { + + protected AbstractBreadthFirstEmptinessOracle(int maxWords, MembershipOracle membershipOracle) { + super(maxWords, membershipOracle); + } + + public static class DFABFEmptinessOracle + extends AbstractBreadthFirstEmptinessOracle, I, Boolean> + implements DFAEmptinessOracle { + + public DFABFEmptinessOracle(int maxWords, MembershipOracle membershipOracle) { + super(maxWords, membershipOracle); + } + } + + public static class MealyBreadthFirstEmptinessOracle + extends AbstractBreadthFirstEmptinessOracle, I, Word> + implements MealyEmptinessOracle { + + public MealyBreadthFirstEmptinessOracle(int maxWords, MembershipOracle> membershipOracle) { + super(maxWords, membershipOracle); + } + } +} diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java new file mode 100644 index 0000000000..b872b39c6f --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java @@ -0,0 +1,138 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import java.util.ArrayList; +import java.util.List; +import java.util.SortedSet; + +import de.learnlib.api.modelchecking.counterexample.Lasso; +import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; +import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; +import de.learnlib.api.oracle.EmptinessOracle.LassoEmptinessOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import de.learnlib.util.AbstractBreadthFirstOracle; +import net.automatalib.automata.concepts.Output; +import net.automatalib.words.Word; + +/** + * A {@link LassoEmptinessOracle}, where the {@link Lasso} is given as an automaton. + * + * @author Jeroen Meijer + * + * @param the Lasso type + * @param the state type + * @param the input type + * @param the output type + */ +public abstract class AbstractLassoAutomatonEmptinessOracle, S, I, D> + extends AbstractBreadthFirstOracle> + implements LassoEmptinessOracle { + + /** + * The omega membership oracle used to answer {@link OmegaQuery}s. + */ + private final OmegaMembershipOracle omegaMembershipOracle; + + /** + * Constructs a new {@link AbstractLassoAutomatonEmptinessOracle}. + * + * @param omegaMembershipOracle the {@link OmegaMembershipOracle} used to answer {@link OmegaQuery}s. + */ + protected AbstractLassoAutomatonEmptinessOracle(OmegaMembershipOracle omegaMembershipOracle) { + super(1); + this.omegaMembershipOracle = omegaMembershipOracle; + } + + @Override + public OmegaMembershipOracle getOmegaMembershipOracle() { + return omegaMembershipOracle; + } + + /** + * Checks whether the answered {@link OmegaQuery} is a counterexample for the given {@code lasso}. + * + * @see LassoEmptinessOracle#isCounterExample(Output, DefaultQuery) + * + * @return whether the two conditions hold: + * 1. {@link LassoEmptinessOracle#isCounterExample(Output, DefaultQuery)}, and + * 2. The {@code query} contains a closed-loop, i.e. there exists {@code 0 <= i < j < query.getStates().size()}, + * such that {@code query.getStates().get(i).equals(query.getStates().get(j))}. + */ + @Override + public boolean isCounterExample(L lasso, OmegaQuery query) { + final boolean result; + // check condition 1 + if (!LassoEmptinessOracle.super.isCounterExample(lasso, query)) { + result = false; + } else { + // the states the SUL evolved through. + final List states = query.getStates(); + + // get the indices in the Lasso where the loop begins + final SortedSet indices = lasso.getLoopBeginIndices(); + + assert indices.size() > 1; + + final List indexList = new ArrayList<>(indices); + + boolean loopClosed = false; + + // check whether the loop is closed + for (int i = 0; i < indexList.size() && !loopClosed; i++) { + final S s1 = states.get(i); + final int i1 = indexList.get(i); + + // compute the first access sequence + final Word w1 = lasso.getWord().prefix(i1); + + for (int j = i + 1; j < indexList.size() && !loopClosed; j++) { + final S s2 = states.get(j); + final int i2 = indexList.get(j); + + // compute the second access sequence + final Word w2 = lasso.getWord().prefix(i2); + + loopClosed = omegaMembershipOracle.isSameState(w1, s1, w2, s2); + } + } + + result = loopClosed; + } + + return result; + } + + public static class DFALassoDFAEmptinessOracle + extends AbstractLassoAutomatonEmptinessOracle, S, I, Boolean> + implements DFALassoEmptinessOracle { + + public DFALassoDFAEmptinessOracle(OmegaMembershipOracle membershipOracle) { + super(membershipOracle); + } + } + + public static class MealyLassoMealyEmptinessOracle + extends AbstractLassoAutomatonEmptinessOracle, S, I, Word> + implements MealyLassoEmptinessOracle { + + public MealyLassoMealyEmptinessOracle(OmegaMembershipOracle> membershipOracle) { + super(membershipOracle); + } + } +} diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java new file mode 100644 index 0000000000..d0613aa404 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java @@ -0,0 +1,192 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.examples.dfa.ExampleAngluin; +import de.learnlib.examples.mealy.ExampleCoffeeMachine; +import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; +import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.DFABFEmptinessOracle; +import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.MealyBreadthFirstEmptinessOracle; +import de.learnlib.util.AbstractBreadthFirstOracle; +import de.learnlib.util.AbstractBreadthFirstOracleTest; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +@RunWith(MockitoJUnitRunner.class) +public abstract class AbstractBreadthFirstEmptinessOracleTest & Output, I, D> extends + AbstractBreadthFirstOracleTest { + + private AbstractBreadthFirstEmptinessOracle bfeo; + + private A automaton; + + private Alphabet alphabet; + + private DefaultQuery query; + + protected abstract AbstractBreadthFirstEmptinessOracle createBreadthFirstEmptinessOracle(); + + protected abstract A createAutomaton(); + + protected abstract Alphabet createAlphabet(); + + protected abstract DefaultQuery createQuery(); + + @Before + public void setUp() { + super.setUp(); + bfeo = createBreadthFirstEmptinessOracle(); + automaton = createAutomaton(); + alphabet = createAlphabet(); + query = createQuery(); + } + + @Test + public void testFindCounterExample() throws Exception { + final DefaultQuery cex = bfeo.findCounterExample(automaton, alphabet); + Assert.assertEquals(query, cex); + } + + public static class DFABFEmptinessOracleTest + extends AbstractBreadthFirstEmptinessOracleTest, Integer, Boolean> { + + @Mock + private DFAMembershipOracle dfaMembershipOracle; + + @Mock + private DFAMembershipOracle dfaMembershipOracle2; + + @Before + public void setUp() { + super.setUp(); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + final DefaultQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(0, 0))) { + q.answer(false); + } else { + q.answer(true); + } + return null; + } + }).when(dfaMembershipOracle).processQuery(Matchers.any()); + } + + @Override + protected DFA createAutomaton() { + return ExampleAngluin.constructMachine(); + } + + @Override + protected AbstractBreadthFirstEmptinessOracle, Integer, Boolean> createBreadthFirstEmptinessOracle() { + return new DFABFEmptinessOracle<>(5, dfaMembershipOracle); + } + + @Override + protected Alphabet createAlphabet() { + return ExampleAngluin.createInputAlphabet(); + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols(1, 1), true); + } + + @Override + protected AbstractBreadthFirstOracle, + Character, + Boolean, + DefaultQuery> createBreadthFirstOracle(int maxWords) { + return new DFABFEmptinessOracle<>(maxWords, dfaMembershipOracle2); + } + } + + public static class MealyBFEmptinessOracleTest + extends AbstractBreadthFirstEmptinessOracleTest, Input, Word> { + + @Mock + private MealyMembershipOracle mealyMembershipOracle; + + @Mock + private MealyMembershipOracle mealyMembershipOracle2; + + @Before + public void setUp() { + super.setUp(); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + final DefaultQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(Input.POD))) { + q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); + } else { + q.answer(Word.fromSymbols("not-an-output")); + } + return null; + } + }).when(mealyMembershipOracle).processQuery(Matchers.any()); + } + + @Override + protected AbstractBreadthFirstEmptinessOracle, Input, Word> + createBreadthFirstEmptinessOracle() { + return new MealyBreadthFirstEmptinessOracle<>(5, mealyMembershipOracle); + } + + @Override + protected MealyMachine createAutomaton() { + return ExampleCoffeeMachine.constructMachine(); + } + + @Override + protected Alphabet createAlphabet() { + return ExampleCoffeeMachine.createInputAlphabet(); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), + Word.fromSymbols(Input.POD), + Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); + } + + @Override + protected AbstractBreadthFirstOracle, + Character, + Word, + DefaultQuery>> createBreadthFirstOracle(int maxWords) { + return new MealyBreadthFirstEmptinessOracle<>(maxWords, mealyMembershipOracle2); + } + } +} diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java new file mode 100644 index 0000000000..9810a38340 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java @@ -0,0 +1,210 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.api.modelchecking.counterexample.Lasso; +import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; +import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; +import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.DFALassoDFAEmptinessOracle; +import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; +import de.learnlib.util.AbstractBreadthFirstOracle; +import de.learnlib.util.AbstractBreadthFirstOracleTest; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +@RunWith(MockitoJUnitRunner.class) +public abstract class AbstractLassoAutomatonEmptinessTest, D> extends + AbstractBreadthFirstOracleTest { + + public static final Alphabet ALPHABET = Alphabets.fromArray("a"); + + private AbstractLassoAutomatonEmptinessOracle laeo; + + private L lasso; + + private DefaultQuery query; + + protected abstract AbstractLassoAutomatonEmptinessOracle createLassoAutomatonEmptinessOracle(); + + protected abstract L createLasso(); + + protected abstract DefaultQuery createQuery(); + + @Before + public void setUp() { + super.setUp(); + laeo = createLassoAutomatonEmptinessOracle(); + lasso = createLasso(); + query = createQuery(); + } + + @Test + public void testFindCounterExample() throws Exception { + final DefaultQuery cex = laeo.findCounterExample(lasso, ALPHABET); + Assert.assertEquals(query, cex); + } + + public static class DFALassoDFAEmptinessOracleTest + extends AbstractLassoAutomatonEmptinessTest, Boolean> { + + @Mock + private DFAOmegaMembershipOracle dfaOmegaMembershipOracle; + + @Mock + private DFAOmegaMembershipOracle dfaOmegaMembershipOracle2; + + @Before + public void setUp() { + super.setUp(); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + final OmegaQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { + q.answer(true); + final List states = new ArrayList<>(); + states.add(0); + states.add(0); + states.add(0); + states.add(0); + q.setStates(states); + } else { + q.answer(false); + } + return null; + } + }).when(dfaOmegaMembershipOracle).processQuery(Matchers.any()); + Mockito.when(dfaOmegaMembershipOracle.isSameState(Matchers.any(), + Matchers.any(), + Matchers.any(), + Matchers.any())).thenReturn(true); + } + + @Override + protected AbstractLassoAutomatonEmptinessOracle, ?, String, ?> + createLassoAutomatonEmptinessOracle() { + return new DFALassoDFAEmptinessOracle<>(dfaOmegaMembershipOracle); + } + + @Override + protected DFALasso createLasso() { + final DFA dfa = AutomatonBuilders.forDFA(new CompactDFA<>(ALPHABET)). + from("q0").on("a").loop().withAccepting("q0").withInitial("q0").create(); + return new DFALasso<>(dfa, ALPHABET, 3); + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols("a", "a", "a"), true); + } + + @Override + protected AbstractBreadthFirstOracle, + Character, + Boolean, + OmegaQuery> createBreadthFirstOracle(int maxWords) { + return new DFALassoDFAEmptinessOracle<>(dfaOmegaMembershipOracle2); + } + } + + public static class MealyLassoMealyEmptinessOracleTest + extends AbstractLassoAutomatonEmptinessTest, Word> { + + @Mock + private MealyOmegaMembershipOracle mealyOmegaMembershipOracle; + + @Mock + private MealyOmegaMembershipOracle mealyOmegaMembershipOracle2; + + @Before + public void setUp() { + super.setUp(); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + final OmegaQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { + q.answer(Word.fromSymbols("1", "1", "1")); + final List states = new ArrayList<>(); + states.add(0); + states.add(0); + states.add(0); + states.add(0); + q.setStates(states); + } else { + q.answer(Word.fromSymbols("not-an-output")); + } + return null; + } + }).when(mealyOmegaMembershipOracle).processQuery(Matchers.any()); + Mockito.when(mealyOmegaMembershipOracle.isSameState(Matchers.any(), + Matchers.any(), + Matchers.any(), + Matchers.any())).thenReturn(true); + } + + @Override + protected AbstractLassoAutomatonEmptinessOracle, ?, String, ?> + createLassoAutomatonEmptinessOracle() { + return new MealyLassoMealyEmptinessOracle<>(mealyOmegaMembershipOracle); + } + + @Override + protected MealyLasso createLasso() { + final MealyMachine mealy = AutomatonBuilders.forMealy( + new CompactMealy(ALPHABET)). + from("q0").on("a").withOutput("1").loop().withInitial("q0").create(); + return new MealyLasso<>(mealy, ALPHABET, 3); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols("a", "a", "a"), Word.fromSymbols("1", "1", "1")); + } + + @Override + protected AbstractBreadthFirstOracle, + Character, + Word, + OmegaQuery>> createBreadthFirstOracle(int maxWords) { + return new MealyLassoMealyEmptinessOracle<>(mealyOmegaMembershipOracle2); + } + } +} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java index ae5abfd2b7..4b019e3a75 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java @@ -88,7 +88,8 @@ public DFAWpMethodEQOracle(MembershipOracle sulOracle, int maxDepth, } } - public static class MealyWpMethodEQOracle extends WpMethodEQOracle, I, Word> { + public static class MealyWpMethodEQOracle extends WpMethodEQOracle, I, Word> + implements MealyEquivalenceOracle { public MealyWpMethodEQOracle(MembershipOracle> sulOracle, int maxDepth) { super(sulOracle, maxDepth); diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterObservableSUL.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterObservableSUL.java new file mode 100644 index 0000000000..ea56bbf1f9 --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterObservableSUL.java @@ -0,0 +1,69 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.statistic.sul; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.ObservableSUL; +import de.learnlib.filter.statistic.Counter; + +@ParametersAreNonnullByDefault +public class ResetCounterObservableSUL extends ResetCounterSUL implements ObservableSUL { + + private final ObservableSUL sul; + + public ResetCounterObservableSUL(String name, ObservableSUL sul) { + super(name, sul); + this.sul = sul; + } + + private ResetCounterObservableSUL(Counter counter, ObservableSUL sul) { + super(counter, sul); + this.sul = sul; + } + + @Override + public ObservableSUL fork() { + return new ResetCounterObservableSUL<>(getStatisticalData(), sul.fork()); + } + + @Nonnull + @Override + public S getState() { + return sul.getState(); + } + + @Override + public boolean deepCopies() { + return sul.deepCopies(); + } + + @Override + public boolean equals(Object obj) { + return sul.equals(obj); + } + + @Override + public int hashCode() { + return sul.hashCode(); + } + + @Override + public String toString() { + return sul.toString(); + } +} diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterSUL.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterSUL.java index 3639904bc1..355bf24b89 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterSUL.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterSUL.java @@ -31,13 +31,12 @@ public class ResetCounterSUL implements StatisticSUL { private final Counter counter; public ResetCounterSUL(String name, SUL sul) { - this.sul = sul; - this.counter = new Counter(name, "resets"); + this(new Counter(name, "resets"), sul); } - private ResetCounterSUL(Counter counter, SUL sul) { - this.sul = sul; + protected ResetCounterSUL(Counter counter, SUL sul) { this.counter = counter; + this.sul = sul; } @Override @@ -72,4 +71,19 @@ public SUL fork() { public Counter getStatisticalData() { return counter; } + + @Override + public boolean equals(Object obj) { + return sul.equals(obj); + } + + @Override + public int hashCode() { + return sul.hashCode(); + } + + @Override + public String toString() { + return sul.toString(); + } } diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterObservableSUL.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterObservableSUL.java new file mode 100644 index 0000000000..317dd344a6 --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterObservableSUL.java @@ -0,0 +1,69 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.statistic.sul; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.ObservableSUL; +import de.learnlib.filter.statistic.Counter; + +@ParametersAreNonnullByDefault +public class SymbolCounterObservableSUL extends SymbolCounterSUL implements ObservableSUL { + + private final ObservableSUL sul; + + public SymbolCounterObservableSUL(String name, ObservableSUL sul) { + super(name, sul); + this.sul = sul; + } + + private SymbolCounterObservableSUL(Counter counter, ObservableSUL sul) { + super(counter, sul); + this.sul = sul; + } + + @Override + public ObservableSUL fork() { + return new SymbolCounterObservableSUL<>(getStatisticalData(), sul.fork()); + } + + @Nonnull + @Override + public S getState() { + return sul.getState(); + } + + @Override + public boolean deepCopies() { + return sul.deepCopies(); + } + + @Override + public boolean equals(Object obj) { + return sul.equals(obj); + } + + @Override + public int hashCode() { + return sul.hashCode(); + } + + @Override + public String toString() { + return sul.toString(); + } +} diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterSUL.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterSUL.java index bef5125a7c..9f68ebf362 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterSUL.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterSUL.java @@ -31,13 +31,12 @@ public class SymbolCounterSUL implements StatisticSUL { private final Counter counter; public SymbolCounterSUL(String name, SUL sul) { - this.sul = sul; - this.counter = new Counter(name, "symbols"); + this(new Counter(name, "symbols"), sul); } - private SymbolCounterSUL(Counter counter, SUL sul) { - this.sul = sul; + protected SymbolCounterSUL(Counter counter, SUL sul) { this.counter = counter; + this.sul = sul; } @Override @@ -72,4 +71,19 @@ public SUL fork() { public Counter getStatisticalData() { return counter; } + + @Override + public boolean equals(Object obj) { + return sul.equals(obj); + } + + @Override + public int hashCode() { + return sul.hashCode(); + } + + @Override + public String toString() { + return sul.toString(); + } } diff --git a/oracles/inclusion-oracles/pom.xml b/oracles/inclusion-oracles/pom.xml new file mode 100644 index 0000000000..77e5ebcabc --- /dev/null +++ b/oracles/inclusion-oracles/pom.xml @@ -0,0 +1,66 @@ + + + + + learnlib-oracles-parent + de.learnlib + 0.14.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + learnlib-inclusion-oracles + LearnLib :: Oracles :: Inclusion Oracles + A collection of language inclusion oracles + + + de.learnlib + learnlib-api + + + net.automatalib + automata-api + + + de.learnlib + learnlib-util + + + org.mockito + mockito-core + test + + + junit + junit + test + + + de.learnlib.testsupport + learnlib-oracle-support + test + + + de.learnlib.testsupport + learnlib-learning-examples + + + + \ No newline at end of file diff --git a/oracles/inclusion-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java b/oracles/inclusion-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java new file mode 100644 index 0000000000..f2d7063ce1 --- /dev/null +++ b/oracles/inclusion-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java @@ -0,0 +1,61 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.inclusion; + +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.util.AbstractBreadthFirstOracle; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Word; + +/** + * An {@link InclusionOracle} that generates words in a breadth-first manner. + * + * @author Jeroen Meijer + * + * @see InclusionOracle + * @see AbstractBreadthFirstOracle + */ +public abstract class AbstractBreadthFirstInclusionOracle & SimpleDTS, I, D> + extends AbstractBreadthFirstOracle.AbstractDefaultBFOracle + implements InclusionOracle> { + + public AbstractBreadthFirstInclusionOracle(int maxWords, MembershipOracle membershipOracle) { + super(maxWords, membershipOracle); + } + + public static class DFABreadthFirstInclusionOracle + extends AbstractBreadthFirstInclusionOracle, I, Boolean> + implements DFAInclusionOracle { + + public DFABreadthFirstInclusionOracle(int maxWords, MembershipOracle membershipOracle) { + super(maxWords, membershipOracle); + } + } + + public static class MealyBreadthFirstInclusionOracle + extends AbstractBreadthFirstInclusionOracle, I, Word> + implements MealyInclusionOracle { + + public MealyBreadthFirstInclusionOracle(int maxWords, MembershipOracle> membershipOracle) { + super(maxWords, membershipOracle); + } + } +} diff --git a/oracles/inclusion-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java b/oracles/inclusion-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java new file mode 100644 index 0000000000..a3408ec05b --- /dev/null +++ b/oracles/inclusion-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java @@ -0,0 +1,188 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.inclusion; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.examples.dfa.ExampleAngluin; +import de.learnlib.examples.mealy.ExampleCoffeeMachine; +import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; +import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.DFABreadthFirstInclusionOracle; +import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; +import de.learnlib.util.AbstractBreadthFirstOracle; +import de.learnlib.util.AbstractBreadthFirstOracleTest; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +@RunWith(MockitoJUnitRunner.class) +public abstract class AbstractBreadthFirstInclusionOracleTest & Output, I, D> extends + AbstractBreadthFirstOracleTest { + + private AbstractBreadthFirstInclusionOracle bfeo; + + private A automaton; + + private Alphabet alphabet; + + private DefaultQuery query; + + protected abstract AbstractBreadthFirstInclusionOracle createBreadthFirstInclusionOracle(); + + protected abstract A createAutomaton(); + + protected abstract Alphabet createAlphabet(); + + protected abstract DefaultQuery createQuery(); + + @Before + public void setUp() { + super.setUp(); + bfeo = createBreadthFirstInclusionOracle(); + automaton = createAutomaton(); + alphabet = createAlphabet(); + query = createQuery(); + } + + @Test + public void testFindCounterExample() throws Exception { + final DefaultQuery cex = bfeo.findCounterExample(automaton, alphabet); + Assert.assertEquals(query, cex); + } + + public static class DFABreadthFirstInclusionOracleTest + extends AbstractBreadthFirstInclusionOracleTest, Integer, Boolean> { + + @Mock + private DFAMembershipOracle dfaMembershipOracle; + + @Mock + private DFAMembershipOracle dfaMembershipOracle2; + + @Before + public void setUp() { + super.setUp(); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + final DefaultQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(0, 0))) { + q.answer(true); + } else { + q.answer(false); + } + return null; + } + }).when(dfaMembershipOracle).processQuery(Matchers.any()); + } + + @Override + protected DFA createAutomaton() { + return ExampleAngluin.constructMachine(); + } + + @Override + protected AbstractBreadthFirstInclusionOracle, Integer, Boolean> createBreadthFirstInclusionOracle() { + return new DFABreadthFirstInclusionOracle<>(5, dfaMembershipOracle); + } + + @Override + protected Alphabet createAlphabet() { + return ExampleAngluin.createInputAlphabet(); + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols(1, 1), false); + } + + @Override + protected AbstractBreadthFirstOracle, Character, Boolean, DefaultQuery> + createBreadthFirstOracle(int maxWords) { + return new DFABreadthFirstInclusionOracle<>(maxWords, dfaMembershipOracle2); + } + } + + public static class MealyBreadthFirstInclusionOracleTest + extends AbstractBreadthFirstInclusionOracleTest, Input, Word> { + + @Mock + private MealyMembershipOracle mealyMembershipOracle; + + @Mock + private MealyMembershipOracle mealyMembershipOracle2; + + @Before + public void setUp() { + super.setUp(); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + final DefaultQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(Input.WATER))) { + q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); + } else { + q.answer(Word.fromSymbols("not-an-output")); + } + return null; + } + }).when(mealyMembershipOracle).processQuery(Matchers.any()); + + } + + @Override + protected AbstractBreadthFirstInclusionOracle, Input, Word> + createBreadthFirstInclusionOracle() { + return new MealyBreadthFirstInclusionOracle<>(5, mealyMembershipOracle); + } + + @Override + protected MealyMachine createAutomaton() { + return ExampleCoffeeMachine.constructMachine(); + } + + @Override + protected Alphabet createAlphabet() { + return ExampleCoffeeMachine.createInputAlphabet(); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols(Input.POD), Word.fromSymbols("not-an-output")); + } + + @Override + protected AbstractBreadthFirstOracle, + Character, Word, DefaultQuery>> + createBreadthFirstOracle(int maxWords) { + return new MealyBreadthFirstInclusionOracle<>(maxWords, mealyMembershipOracle2); + } + } +} diff --git a/oracles/membership-oracles/pom.xml b/oracles/membership-oracles/pom.xml index 03c31363cf..b60f2bb1e9 100644 --- a/oracles/membership-oracles/pom.xml +++ b/oracles/membership-oracles/pom.xml @@ -48,6 +48,10 @@ limitations under the License. net.automatalib automata-api + + net.automatalib + automata-commons-util + net.automatalib automata-core diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java new file mode 100644 index 0000000000..e7d4fda4c2 --- /dev/null +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java @@ -0,0 +1,324 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.membership; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import javax.annotation.Nonnull; + +import de.learnlib.api.ObservableSUL; +import de.learnlib.api.SUL; +import de.learnlib.api.exception.SULException; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; +import de.learnlib.api.query.OmegaQuery; +import net.automatalib.commons.util.Pair; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; + +/** + * An omega membership oracle for an {@link ObservableSUL}. + * + * The behavior is similar to a {@link SULOracle}, except that this class answers {@link OmegaQuery}s. + * + * After some symbols (as specified in {@link OmegaQuery#getIndices()}) in an input word the state of the {@link + * ObservableSUL} is retrieved, and used to answer the query. + * + * Like {@link SULOracle} this class is thread-safe. + * + * @author Jeroen Meijer + * + * @param the state type of the {@link ObservableSUL} + * @param the input type + * @param the output type + * @param the state information type that is used to answer {@link OmegaQuery}s + */ +public abstract class AbstractSULOmegaOracle implements MealyOmegaMembershipOracle { + + private final ObservableSUL sul; + private final ThreadLocal> localSul; + + protected AbstractSULOmegaOracle(ObservableSUL sul) { + this.sul = sul; + if (sul.canFork()) { + this.localSul = ThreadLocal.withInitial(sul::fork); + } else { + this.localSul = null; + } + } + + /** + * Gets the {@link ObservableSUL}. + * + * @return the {@link ObservableSUL}. + */ + public ObservableSUL getSul() { + return sul; + } + + @Override + public void processQueries(Collection>> queries) { + if (localSul != null) { + processQueries(localSul.get(), queries); + } else { + synchronized (sul) { + processQueries(sul, queries); + } + } + } + + private void processQueries(ObservableSUL sul, Collection>> queries) { + for (OmegaQuery> q : queries) { + final Pair, List> output = answerQuery(sul, q.getPrefix(), q.getSuffix(), q.getIndices()); + q.answer(output.getFirst()); + q.setStates(output.getSecond()); + } + } + + protected abstract Q getQueryState(ObservableSUL sul); + + @Nonnull + private Pair, List> answerQuery(ObservableSUL sul, + Word prefix, + Word suffix, + Set indices) throws SULException { + sul.pre(); + try { + int index = 0; + final List states = new ArrayList<>(); + + // Prefix: Execute symbols, don't record output + for (I sym : prefix) { + sul.step(sym); + } + + if (indices.contains(index++)) { + states.add(getQueryState(sul)); + } + + // Suffix: Execute symbols, outputs constitute output word + WordBuilder wb = new WordBuilder<>(suffix.length()); + for (I sym : suffix) { + wb.add(sul.step(sym)); + if (indices.contains(index++)) { + states.add(getQueryState(sul)); + } + } + + return Pair.make(wb.toWord(), states); + } finally { + sul.post(); + } + } + + @Override + public MealyMembershipOracle getMealyMembershipOracle() { + return new SULOracle<>(sul); + } + + /** + * Creates a new {@link AbstractSULOmegaOracle}, while making sure the invariants of the {@link ObservableSUL} are + * satisfied. + * + * @param sul the {@link ObservableSUL} to wrap around. + * @param deepCopies whether to test for state equivalence directly on the retrieved state. + * + * @param the state type + * @param the input type + * @param the output type + * + * @return the {@link AbstractSULOmegaOracle}. + */ + public static AbstractSULOmegaOracle newOracle(ObservableSUL sul, + boolean deepCopies) { + final AbstractSULOmegaOracle abstractSulOmegaOracle; + if (deepCopies) { + if (!sul.deepCopies()) { + throw new IllegalArgumentException("SUL can not make deep copies of states."); + } else { + abstractSulOmegaOracle = new DeepCopySULOmegaOracle<>(sul); + } + } else { + if (!sul.canFork()) { + throw new IllegalArgumentException("SUL must be forkable."); + } else { + abstractSulOmegaOracle = new ShallowCopySULOmegaOracle<>(sul); + } + } + + return abstractSulOmegaOracle; + } + + /** + * Creates a new {@link AbstractSULOmegaOracle} that assumes the {@link SUL} can not make deep copies. + * + * @see #newOracle(ObservableSUL, boolean) + * + * @param the state type + * @param the input type + * @param the output type + */ + public static AbstractSULOmegaOracle newOracle(ObservableSUL sul) { + return newOracle(sul, !sul.canFork()); + } + + /** + * A {@link AbstractSULOmegaOracle} that uses {@link Object#hashCode()}, and {@link Object#equals(Object)} to test + * for state equivalence. When the hash codes of two states are equal this class will use two access sequences to + * move two {@link ObservableSUL}s to those states and perform an equality check. + * + * The state information used to answer {@link OmegaQuery}s is of type {@link Integer}. The values of those integers + * are actually hash codes of states of the {@link ObservableSUL}. + * + * @author Jeroen Meijer + * + * @param the state type + * @param the input type + * @param the output type + */ + private static final class ShallowCopySULOmegaOracle extends AbstractSULOmegaOracle { + + /** + * A forked {@link SUL} is necessary when we need to step to two particular states at the same time. + */ + private final ObservableSUL forkedSUL; + + /** + * Constructs a new {@link ShallowCopySULOmegaOracle}, use {@link #newOracle(ObservableSUL)} to create an + * instance. This method makes sure the invariants of the {@link ObservableSUL} are satisfied (i.e. the {@link + * ObservableSUL} must be forkable, i.e. ({@code {@link SUL#canFork()} == true}. + * + * @param sul the SUL + */ + private ShallowCopySULOmegaOracle(ObservableSUL sul) { + super(sul); + assert sul.canFork(); + forkedSUL = sul.fork(); + } + + /** + * Returns the state as a hash code. + * + * @param sul the {@link ObservableSUL} to retrieve the current state from. + * + * @return the hash code of the state. + */ + @Override + protected Integer getQueryState(ObservableSUL sul) { + return sul.getState().hashCode(); + } + + /** + * Test for state equivalence, by means of {@link Object#hashCode()}, and {@link Object#equals(Object)}. + * + * @see OmegaMembershipOracle#isSameState(Word, Object, Word, Object) + * + * @return whether the following conditions hold: + * 1. the hash codes are the same, i.e. {@code s1.equals(s2)}, and + * 2. the two access sequences lead to the same state. + */ + @Override + public boolean isSameState(Word input1, Integer s1, Word input2, Integer s2) { + final boolean result; + if (!s1.equals(s2)) { + result = false; + } else { + // in this case the hash codes are equal, now we must check if we accidentally had a hash-collision. + final ObservableSUL sul1 = getSul(); + final ObservableSUL sul2 = forkedSUL; + sul1.pre(); + try { + // step through the first SUL + for (I sym : input1) { + sul1.step(sym); + } + sul2.pre(); + try { + // step through the second SUL + for (I sym : input2) { + sul2.step(sym); + } + + assert sul1.getState().hashCode() == sul2.getState().hashCode(); + assert s1.equals(sul1.getState().hashCode()); + assert s2.equals(sul2.getState().hashCode()); + + // check for state equivalence + result = sul1.getState().equals(sul2.getState()); + } finally { + sul2.post(); + } + + } finally { + sul1.post(); + } + } + + return result; + } + } + + /** + * A {@link AbstractSULOmegaOracle} for states that are deep copies. When a state is a deep copy, this means we can + * simply invoke {@link Object#equals(Object)} on both. + * + * The state information used to answer {@link OmegaQuery}s is of type {@link S}. + * + * @author Jeroen Meijer + * + * @param the state type + * @param the input type + * @param the output type + */ + private static final class DeepCopySULOmegaOracle extends AbstractSULOmegaOracle { + + /** + * Constructs a {@link DeepCopySULOmegaOracle}, use {@link #newOracle(ObservableSUL, boolean)} to create an + * actual instance. This method will make sure the invariants of the {@link ObservableSUL} are satisfied. + * + * @param sul the {@link ObservableSUL}. + */ + private DeepCopySULOmegaOracle(ObservableSUL sul) { + super(sul); + } + + /** + * Returns the current state of the {@link ObservableSUL}. + * + * @param sul the {@link ObservableSUL} to retrieve the current state from. + * + * @return the current state. + */ + @Override + protected S getQueryState(ObservableSUL sul) { + return sul.getState(); + } + + /** + * Test for state equivalence using {@link Object#equals(Object)}. + * + * @see OmegaMembershipOracle#isSameState(Word, Object, Word, Object) + */ + @Override + public boolean isSameState(Word input1, S s1, Word input2, S s2) { + return s1.equals(s2); + } + } +} diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java new file mode 100644 index 0000000000..fe73ccebe5 --- /dev/null +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java @@ -0,0 +1,146 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.membership; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle; +import de.learnlib.api.oracle.OmegaQueryAnswerer; +import de.learnlib.api.oracle.SingleQueryOmegaOracle; +import de.learnlib.api.query.OmegaQuery; +import de.learnlib.oracle.membership.SimulatorOracle.DFASimulatorOracle; +import de.learnlib.oracle.membership.SimulatorOracle.MealySimulatorOracle; +import de.learnlib.util.MQUtil; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.commons.util.Pair; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Word; + +/** + * Answers {@link OmegaQuery}s by simulating an automaton. + * + * @author Jeroen Meijer + * + * @see SimulatorOracle + * + * @param the state type. + * @param the input type. + * @param the output type. + * @param the SimulatorOracle type. + */ +public class SimulatorOmegaOracle> + implements SingleQueryOmegaOracle { + + /** + * The automaton to simulate. + */ + private final SimpleDTS simpleDTS; + + /** + * @see #getSimulatorOracle() + */ + private final SO simulatorOracle; + + /** + * Constructs a new {@link SimulatorOmegaOracle}. + * + * @param automaton the automaton to simulate. + * @param simulatorOracle the {@link SimulatorOracle} used to answer {@link de.learnlib.api.query.Query}s. + * @param the automaton type. + */ + public & SimpleDTS> SimulatorOmegaOracle(A automaton, SO simulatorOracle) { + this.simpleDTS = automaton; + this.simulatorOracle = simulatorOracle; + } + + /** + * Gets the {@link SimulatorOracle} used to answer {@link de.learnlib.api.query.Query}s. + * + * @return the SimulatorOracle. + */ + public SO getSimulatorOracle() { + return simulatorOracle; + } + + /** + * Test for state equivalence by simply invoking {@link Object#equals(Object)}. + * + * @see OmegaMembershipOracle#isSameState(Word, Object, Word, Object) + */ + @Override + public boolean isSameState(Word input1, S s1, Word input2, S s2) { + return s1.equals(s2); + } + + @Override + public void processQueries(Collection> queries) { + MQUtil.answerOmegaQueriesAuto(this, queries); + } + + /** + * Returns an answer for an {@link OmegaQuery}. + * + * The output is obtained through the {@link SimulatorOracle}, while the states are obtained by means of creating + * several access sequences to states in the simulated automaton. + * + * @see OmegaQueryAnswerer#answerQuery(Word, Word, Set) + */ + @Override + public Pair> answerQuery(Word prefix, Word suffix, Set indices) { + final List states = new ArrayList<>(); + + for (int i : indices) { + states.add(simpleDTS.getState(prefix.concat(suffix).prefix(i))); + } + + return Pair.make(simulatorOracle.answerQuery(prefix, suffix), states); + } + + public static class DFASimulatorOmegaOracle + extends SimulatorOmegaOracle> + implements DFAOmegaMembershipOracle { + + public DFASimulatorOmegaOracle(DFA automaton) { + super(automaton, new DFASimulatorOracle<>(automaton)); + } + + @Override + public DFAMembershipOracle getDFAMembershipOracle() { + return getSimulatorOracle(); + } + } + + public static class MealySimulatorOmegaOracle + extends SimulatorOmegaOracle, MealySimulatorOracle> + implements MealyOmegaMembershipOracle { + + public MealySimulatorOmegaOracle(MealyMachine automaton) { + super(automaton, new MealySimulatorOracle<>(automaton)); + } + + @Override + public MealyMembershipOracle getMealyMembershipOracle() { + return getSimulatorOracle(); + } + } +} diff --git a/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java new file mode 100644 index 0000000000..9e6b92c9b2 --- /dev/null +++ b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java @@ -0,0 +1,75 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.membership; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import de.learnlib.api.query.OmegaQuery; +import de.learnlib.examples.dfa.ExamplePaulAndMary; +import de.learnlib.oracle.membership.SimulatorOmegaOracle.DFASimulatorOmegaOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Symbol; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * Tests the same functionality as in {@link SimulatorOracleTest}, but also tests whether the correct states are + * visited. + * + * @author Jeroen Meijer + */ +public class SimulatorOmegaOracleTest { + + @Test + public void testDFASimulatorOmegaOracle() { + + DFA dfa = ExamplePaulAndMary.constructMachine(); + + DFASimulatorOmegaOracle oracle = new DFASimulatorOmegaOracle<>(dfa); + + List> queries = new ArrayList<>(); + + OmegaQuery q1 = new OmegaQuery<>(Word.fromSymbols(ExamplePaulAndMary.IN_PAUL, + ExamplePaulAndMary.IN_LOVES, + ExamplePaulAndMary.IN_MARY), + new HashSet<>(Arrays.asList(new Integer[] {0, 1, 2, 3}))); + OmegaQuery q2 = new OmegaQuery<>(Word.fromSymbols(ExamplePaulAndMary.IN_MARY, + ExamplePaulAndMary.IN_LOVES, + ExamplePaulAndMary.IN_PAUL), + new HashSet<>(Arrays.asList(new Integer[] {0, 1, 2, 3}))); + queries.add(q1); + queries.add(q2); + + Assert.assertEquals(queries.get(0).getInput().size(), 3); + Assert.assertEquals(queries.get(0).getIndices().size(), 4); + Assert.assertEquals(queries.get(1).getInput().size(), 3); + Assert.assertEquals(queries.get(1).getIndices().size(), 4); + + oracle.processQueries(queries); + + // Paul loves Mary... + Assert.assertEquals(queries.get(0).getOutput(), Boolean.TRUE); + Assert.assertEquals(queries.get(0).getStates(), Arrays.asList(new Integer[] {0, 1, 3, 4})); + + // ... but Mary does not love Paul :-( + Assert.assertEquals(queries.get(1).getOutput(), Boolean.FALSE); + Assert.assertEquals(queries.get(1).getStates(), Arrays.asList(new Integer[] {0, 2, 2, 2})); + } +} diff --git a/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/OracleTest.java b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOracleTest.java similarity index 98% rename from oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/OracleTest.java rename to oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOracleTest.java index 226aa40357..702c46cfc1 100644 --- a/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/OracleTest.java +++ b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOracleTest.java @@ -30,7 +30,7 @@ /** * @author Maik Merten */ -public class OracleTest { +public class SimulatorOracleTest { @Test public void testDFASimulatorOracle() { diff --git a/oracles/pom.xml b/oracles/pom.xml index b95416301b..5d52321d45 100644 --- a/oracles/pom.xml +++ b/oracles/pom.xml @@ -37,6 +37,9 @@ limitations under the License. membership-oracles equivalence-oracles parallelism + emptiness-oracles + inclusion-oracles + black-box-oracles \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8b7f9daac3..8615514da6 100644 --- a/pom.xml +++ b/pom.xml @@ -120,6 +120,16 @@ limitations under the License. Developer (inactive) + + meijuh + Jeroen Meijer + j.j.g.meijer@utwente.nl + University of Twente, Formal Methods and Tools + http://fmt.cs.utwente.nl/ + + Developer + + + 3.6 0.8.0-SNAPSHOT 0.1 8.1 3.0.2 22.0 + 4.12 1.2.3 + 2.0.59-beta 1.7.25 6.11 @@ -392,6 +407,16 @@ limitations under the License. maven-scm-publish-plugin ${scm-publish-plugin.version} + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler-plugin.version} + + + -Xlint:all,-options,-path + + + @@ -987,12 +1012,11 @@ limitations under the License. - - + @@ -1036,6 +1060,28 @@ limitations under the License. learnlib-parallelism ${project.version} + + de.learnlib + learnlib-black-box-oracles + ${project.version} + + + de.learnlib + learnlib-emptiness-oracles + ${project.version} + + + de.learnlib + learnlib-inclusion-oracles + ${project.version} + + + + + de.learnlib + learnlib-model-checkers + ${project.version} + @@ -1048,7 +1094,6 @@ limitations under the License. de.learnlib.testsupport learnlib-learning-examples ${project.version} - test de.learnlib.testsupport @@ -1056,6 +1101,12 @@ limitations under the License. ${project.version} test + + de.learnlib.testsupport + learnlib-oracle-support + ${project.version} + test + @@ -1073,6 +1124,17 @@ limitations under the License. ${testng.version} test + + org.mockito + mockito-core + ${mockito.version} + test + + + junit + junit + ${junit.version} + @@ -1082,6 +1144,12 @@ limitations under the License. ${guava.version} + + org.apache.commons + commons-lang3 + ${apache-commons.version} + + com.google.code.findbugs diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java index b101a19568..3656245ed4 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java @@ -24,11 +24,13 @@ import de.learnlib.examples.dfa.ExampleAngluin; import de.learnlib.examples.dfa.ExampleKeylock; import de.learnlib.examples.dfa.ExamplePaulAndMary; +import de.learnlib.examples.dfa.ExampleTinyDFA; import de.learnlib.examples.mealy.ExampleCoffeeMachine; import de.learnlib.examples.mealy.ExampleGrid; import de.learnlib.examples.mealy.ExampleRandomMealy; import de.learnlib.examples.mealy.ExampleShahbazGroz; import de.learnlib.examples.mealy.ExampleStack; +import de.learnlib.examples.mealy.ExampleTinyMealy; import net.automatalib.words.Alphabet; import net.automatalib.words.impl.Alphabets; @@ -50,7 +52,8 @@ public static List> createDFAExamples() { return Arrays.asList(ExampleAngluin.createExample(), ExamplePaulAndMary.createExample(), ExampleKeylock.createExample(KEYLOCK_SIZE, false), - ExampleKeylock.createExample(KEYLOCK_SIZE, true)); + ExampleKeylock.createExample(KEYLOCK_SIZE, true), + ExampleTinyDFA.createExample()); } public static List> createMealyExamples() { @@ -61,7 +64,8 @@ public static List> createDFAExamples() { ExampleRandomMealy.createExample(new Random(RANDOM_SEED), RANDOM_ALPHABET, RANDOM_SIZE, - RANDOM_MEALY_OUTPUTS)); + RANDOM_MEALY_OUTPUTS), + ExampleTinyMealy.createExample()); } } diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/dfa/ExampleTinyDFA.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/dfa/ExampleTinyDFA.java new file mode 100644 index 0000000000..b67d84f945 --- /dev/null +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/dfa/ExampleTinyDFA.java @@ -0,0 +1,59 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.dfa; + +import de.learnlib.examples.DefaultLearningExample.DefaultDFALearningExample; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.impl.Alphabets; + +/** + * Tiny DFA with language (ab)*. + * + * @author Jeroen Meijer + */ +public class ExampleTinyDFA extends DefaultDFALearningExample { + + + public ExampleTinyDFA() { + super(constructMachine()); + } + + /** + * Construct and return a machine representation of this example. + * + * @return machine instance of the example + */ + public static CompactDFA constructMachine() { + // @formatter:off + return AutomatonBuilders.newDFA(Alphabets.characters('a', 'b')). + withInitial("q0").withAccepting("q0").withAccepting("q1"). + from("q0").on('a').to("q1"). + from("q1").on('b').to("q0"). + + from("q0").on('b').to("TRAP"). + from("q1").on('a').to("TRAP"). + from("TRAP"). + on('a').loop(). + on('b').loop(). + create(); + // @formatter:on + } + + public static ExampleTinyDFA createExample() { + return new ExampleTinyDFA(); + } +} diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleTinyMealy.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleTinyMealy.java new file mode 100644 index 0000000000..44e4eb7399 --- /dev/null +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleTinyMealy.java @@ -0,0 +1,56 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.mealy; + +import de.learnlib.examples.DefaultLearningExample.DefaultMealyLearningExample; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.impl.Alphabets; + +/** + * Tiny machine with the language (a1a2)^*. + * + * @author Jeroen Meijer + */ +public class ExampleTinyMealy extends DefaultMealyLearningExample { + + public ExampleTinyMealy() { + super(constructMachine()); + } + + /** + * Construct and return a machine representation of this example. + * + * @return machine instance of the example + */ + public static CompactMealy constructMachine() { + // @formatter:off + final CompactMealy cm = new CompactMealy<>(Alphabets.characters('a', 'a')); + return AutomatonBuilders.forMealy(cm). + withInitial("q0"). + from("q0"). + on('a').withOutput('1').to("q1"). + from("q1"). + on('a').withOutput('2').to("q0"). + create(); + // @formatter:on + } + + public static ExampleTinyMealy createExample() { + return new ExampleTinyMealy(); + } + +} diff --git a/test-support/learnlib-oracles-support/pom.xml b/test-support/learnlib-oracles-support/pom.xml new file mode 100644 index 0000000000..44284f2e03 --- /dev/null +++ b/test-support/learnlib-oracles-support/pom.xml @@ -0,0 +1,36 @@ + + + + learnlib-test-support-parent + de.learnlib.testsupport + 0.14.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + learnlib-oracle-support + LearnLib :: Test Support :: Oracles + Support classes for writing tests for oracles + + + de.learnlib + learnlib-util + + + junit + junit + + + net.automatalib + automata-api + + + de.learnlib + learnlib-api + + + jar + + \ No newline at end of file diff --git a/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AbstractBreadthFirstOracleTest.java b/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AbstractBreadthFirstOracleTest.java new file mode 100644 index 0000000000..d3d5b36005 --- /dev/null +++ b/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AbstractBreadthFirstOracleTest.java @@ -0,0 +1,78 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.util; + +import java.util.NoSuchElementException; + +import de.learnlib.api.query.Query; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Word; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Class to test any {@link AbstractBreadthFirstOracle}. + * + * @author Jeroen Meijer + */ +public abstract class AbstractBreadthFirstOracleTest { + + public static final int MAX_WORDS = 1; + + private AbstractBreadthFirstOracle, Character, D, ? extends Query> + bfo; + + protected abstract AbstractBreadthFirstOracle, Character, D, ? extends Query> + createBreadthFirstOracle(int maxWords); + + @Before + public void setUp() { + bfo = createBreadthFirstOracle(MAX_WORDS); + } + + @Test + public void testGetMaxWords() throws Exception { + Assert.assertEquals(bfo.getMaxWords(), MAX_WORDS); + } + + /** + * Tests breadth-first order. + */ + @Test + public void testNextInput() { + bfo.pre(); + bfo.addWord(Word.fromLetter('a')); + bfo.addWord(Word.fromLetter('b')); + Assert.assertEquals(bfo.nextInput(), Word.fromLetter('a')); + Assert.assertEquals(bfo.nextInput(), Word.fromLetter('b')); + } + + @Test + public void testAddWord() throws Exception { + bfo.pre(); + bfo.addWord(Word.epsilon()); + Assert.assertEquals(bfo.nextInput(), Word.epsilon()); + } + + @Test(expected = NoSuchElementException.class) + public void testPre() { + bfo.pre(); + bfo.addWord(Word.epsilon()); + bfo.pre(); + bfo.nextInput(); + } +} \ No newline at end of file diff --git a/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AutomatonOracleTest.java b/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AutomatonOracleTest.java new file mode 100644 index 0000000000..d885c4cc2a --- /dev/null +++ b/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AutomatonOracleTest.java @@ -0,0 +1,24 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.util; + +import de.learnlib.api.oracle.AutomatonOracle; +import net.automatalib.ts.simple.SimpleDTS; + +public interface AutomatonOracleTest, I> { + + AutomatonOracle createAutomatonOracle(int maxWords); +} diff --git a/test-support/pom.xml b/test-support/pom.xml index 9b06f82d68..4fe8fbe33f 100644 --- a/test-support/pom.xml +++ b/test-support/pom.xml @@ -34,6 +34,7 @@ limitations under the License. learning-examples learner-it-support + learnlib-oracles-support From 00700ad7bcc9372f82e249c8d6a6be3d004a3db2 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 26 Feb 2018 10:13:57 +0100 Subject: [PATCH 017/125] adjust to refactorings in AutomataLib --- api/src/main/java/de/learnlib/api/query/OmegaQuery.java | 2 +- .../de/learnlib/oracle/membership/AbstractSULOmegaOracle.java | 2 +- .../de/learnlib/oracle/membership/SimulatorOmegaOracle.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/de/learnlib/api/query/OmegaQuery.java b/api/src/main/java/de/learnlib/api/query/OmegaQuery.java index a8e76f0263..e169abfa82 100644 --- a/api/src/main/java/de/learnlib/api/query/OmegaQuery.java +++ b/api/src/main/java/de/learnlib/api/query/OmegaQuery.java @@ -78,7 +78,7 @@ public OmegaQuery(Query query, Set indices) { } public Pair> getOutputStates() { - return Pair.make(getOutput(), states); + return Pair.of(getOutput(), states); } @Override diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java index e7d4fda4c2..7a3d2a53cb 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java @@ -122,7 +122,7 @@ private Pair, List> answerQuery(ObservableSUL sul, } } - return Pair.make(wb.toWord(), states); + return Pair.of(wb.toWord(), states); } finally { sul.post(); } diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java index fe73ccebe5..55dec7bf75 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java @@ -113,7 +113,7 @@ public Pair> answerQuery(Word prefix, Word suffix, Set states.add(simpleDTS.getState(prefix.concat(suffix).prefix(i))); } - return Pair.make(simulatorOracle.answerQuery(prefix, suffix), states); + return Pair.of(simulatorOracle.answerQuery(prefix, suffix), states); } public static class DFASimulatorOmegaOracle From 33c0175f426bfdeda22ed6a8d6379eff3fd74cfd Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 26 Feb 2018 10:14:18 +0100 Subject: [PATCH 018/125] model-checker: do not fail tests, if LTSmin is not installed --- .../modelchecker/AbstractLTSminLTL.java | 32 +++++++++++++------ .../modelchecker/AbstractLTSminLTLTest.java | 2 ++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java index ff6b327913..a6d7534c82 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java @@ -31,6 +31,8 @@ import net.automatalib.serialization.fsm.parser.AbstractFSMParser; import net.automatalib.serialization.fsm.parser.FSMParseException; import net.automatalib.ts.simple.SimpleDTS; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * An LTL model checker using LTSmin. @@ -63,6 +65,8 @@ public abstract class AbstractLTSminLTL> extends AbstractUnfoldingModelChecker implements ModelChecker { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLTSminLTL.class); + public static final String LTSMIN_PATH; public static final String LTSMIN_PATH_PROPERTY = "de.learnlib.external.ltsmin.path"; @@ -131,8 +135,9 @@ protected AbstractLTSminLTL(boolean keepFiles, this.inheritIO = inheritIO; if (!binariesChecked) { - checkBinary(ETF2LTS_MC); - checkBinary(LTSMIN_CONVERT); + if (!checkUsable()) { + throw new ModelCheckingException("LTSmin binary could not be executed correctly"); + } binariesChecked = true; } } @@ -326,6 +331,15 @@ public final L findCounterExample(A hypothesis, Collection inputs, return result; } + /** + * Checks whether the given binary can be executed, by performing a version check. + * + * @throws ModelCheckingException when the given binary can not be run successfully. + */ + public static boolean checkUsable() { + return checkUsable(ETF2LTS_MC) && checkUsable(LTSMIN_CONVERT); + } + /** * Checks whether the given binary can be executed, by performing a version check. * @@ -333,7 +347,7 @@ public final L findCounterExample(A hypothesis, Collection inputs, * * @throws ModelCheckingException when the given binary can not be run successfully. */ - private void checkBinary(String bin) throws ModelCheckingException { + private static boolean checkUsable(String bin) { // the command lines for the ProcessBuilder final List commandLines = new ArrayList<>(); @@ -347,19 +361,19 @@ private void checkBinary(String bin) throws ModelCheckingException { final Process check; try { ProcessBuilder processBuilder = new ProcessBuilder(commandLines); - if (inheritIO) { - processBuilder = processBuilder.inheritIO(); - } check = processBuilder.start(); check.waitFor(); } catch (IOException | InterruptedException e) { - throw new ModelCheckingException(String.format(CHECK, bin, e.toString())); + LOGGER.error(String.format(CHECK, bin, e.toString()), e); + return false; } if (check.exitValue() != VERSION_EXIT) { - throw new ModelCheckingException( - String.format(CHECK, bin, String.format("Command '%s --version' did not exit with 255", bin))); + LOGGER.error(String.format(CHECK, bin, String.format("Command '%s --version' did not exit with 255", bin))); + return false; } + + return true; } public static class BuilderDefaults { diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java index ed400f8046..d9252e6e0f 100644 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java @@ -22,6 +22,7 @@ import net.automatalib.words.impl.Alphabets; import org.junit.After; import org.junit.Assert; +import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -58,6 +59,7 @@ public Alphabet getAlphabet() { @BeforeClass public static void setUpBeforeClass() { + Assume.assumeTrue(AbstractLTSminLTL.checkUsable()); ltsminPathPropertyDefault = System.getProperty(AbstractLTSminLTL.LTSMIN_PATH_PROPERTY); } From d6116ffd188be3cbc157d604e1df078bdc68a3c2 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 26 Feb 2018 13:18:08 +0100 Subject: [PATCH 019/125] post-PR-merge cleanup - update developer/contributor information - drop jUnit dependency - merge blackbox-, emptiness- and inclusion oracles to bbc-oracles artifact - as a result, drop learnlib-oracles-support module --- algorithms/active/ttt-vpda/pom.xml | 2 +- api/pom.xml | 7 +- api/src/main/java/de/learnlib/api/SUL.java | 1 - .../counterexample/AbstractLassoTest.java | 95 +++++++ .../counterexample/DFALassoTest.java | 92 +++++++ .../counterexample/LassoTest.java | 240 ------------------ .../counterexample/MealyLassoTest.java | 100 ++++++++ .../learnlib-checkstyle-suppressions.xml | 2 +- distribution/pom.xml | 70 +---- examples/pom.xml | 49 ++-- model-checkers/pom.xml | 10 +- .../modelchecker/AbstractLTSminLTL.java | 113 +-------- .../modelchecker/AbstractLTSminLTLMealy.java | 16 +- .../modelchecker/LTSminLTLAlternating.java | 13 +- .../modelchecker/LTSminLTLDFA.java | 8 +- .../modelchecker/LTSminLTLIO.java | 26 +- .../modelchecker/LTSminUtil.java | 122 +++++++++ .../AbstractLTSminLTLMealyTest.java | 4 +- .../modelchecker/AbstractLTSminLTLTest.java | 29 +-- .../AbstractUnfoldingModelCheckerTest.java | 20 +- .../modelchecker/LTSminLTLDFATest.java | 6 +- .../pom.xml | 44 ++-- .../oracle}/AbstractBreadthFirstOracle.java | 2 +- .../blackbox/AbstractBlackBoxOracle.java | 0 .../oracle/blackbox/CExFirstBBOracle.java | 0 .../blackbox/DisproveFirstBBOracle.java | 0 .../blackbox/ModelCheckingBBProperty.java | 0 .../AbstractBreadthFirstEmptinessOracle.java | 2 +- ...AbstractLassoAutomatonEmptinessOracle.java | 2 +- .../AbstractBreadthFirstInclusionOracle.java | 2 +- .../AbstractBreadthFirstOracleTest.java | 22 +- .../blackbox/AbstractBlackBoxOracleTest.java | 14 +- .../oracle/blackbox/CExFirstBBOracleTest.java | 13 +- .../blackbox/DisproveFirstBBOracleTest.java | 13 +- .../blackbox/ModelCheckingBBPropertyTest.java | 19 +- ...stractBreadthFirstEmptinessOracleTest.java | 60 ++--- .../AbstractLassoAutomatonEmptinessTest.java | 84 +++--- ...stractBreadthFirstInclusionOracleTest.java | 60 ++--- oracles/black-box-oracles/pom.xml | 60 ----- oracles/filters/cache/pom.xml | 4 - oracles/inclusion-oracles/pom.xml | 66 ----- .../membership/SimulatorOmegaOracleTest.java | 16 +- oracles/pom.xml | 4 +- pom.xml | 67 ++--- test-support/learnlib-oracles-support/pom.xml | 36 --- .../de/learnlib/util/AutomatonOracleTest.java | 24 -- test-support/pom.xml | 1 - 47 files changed, 689 insertions(+), 951 deletions(-) create mode 100644 api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java create mode 100644 api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java delete mode 100644 api/src/test/java/de/learnlib/api/modelchecking/counterexample/LassoTest.java create mode 100644 api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java create mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java rename oracles/{emptiness-oracles => bbc-oracles}/pom.xml (77%) rename {commons/util/src/main/java/de/learnlib/util => oracles/bbc-oracles/src/main/java/de/learnlib/oracle}/AbstractBreadthFirstOracle.java (99%) rename oracles/{black-box-oracles => bbc-oracles}/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java (100%) rename oracles/{black-box-oracles => bbc-oracles}/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java (100%) rename oracles/{black-box-oracles => bbc-oracles}/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java (100%) rename oracles/{black-box-oracles => bbc-oracles}/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java (100%) rename oracles/{emptiness-oracles => bbc-oracles}/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java (97%) rename oracles/{emptiness-oracles => bbc-oracles}/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java (98%) rename oracles/{inclusion-oracles => bbc-oracles}/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java (97%) rename {test-support/learnlib-oracles-support/src/main/java/de/learnlib/util => oracles/bbc-oracles/src/test/java/de/learnlib/oracle}/AbstractBreadthFirstOracleTest.java (83%) rename oracles/{black-box-oracles => bbc-oracles}/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java (87%) rename oracles/{black-box-oracles => bbc-oracles}/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java (94%) rename oracles/{black-box-oracles => bbc-oracles}/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java (93%) rename oracles/{black-box-oracles => bbc-oracles}/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java (92%) rename oracles/{emptiness-oracles => bbc-oracles}/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java (79%) rename oracles/{emptiness-oracles => bbc-oracles}/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java (77%) rename oracles/{inclusion-oracles => bbc-oracles}/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java (79%) delete mode 100644 oracles/black-box-oracles/pom.xml delete mode 100644 oracles/inclusion-oracles/pom.xml delete mode 100644 test-support/learnlib-oracles-support/pom.xml delete mode 100644 test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AutomatonOracleTest.java diff --git a/algorithms/active/ttt-vpda/pom.xml b/algorithms/active/ttt-vpda/pom.xml index 47adf94b0c..7fd4d97cf1 100644 --- a/algorithms/active/ttt-vpda/pom.xml +++ b/algorithms/active/ttt-vpda/pom.xml @@ -1,6 +1,6 @@ diff --git a/api/src/main/java/de/learnlib/api/SUL.java b/api/src/main/java/de/learnlib/api/SUL.java index 1f734846c8..658ab5392b 100644 --- a/api/src/main/java/de/learnlib/api/SUL.java +++ b/api/src/main/java/de/learnlib/api/SUL.java @@ -30,7 +30,6 @@ * * @author falkhowar * @author Malte Isberner - * @author Jeroen Meijer */ public interface SUL { diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java new file mode 100644 index 0000000000..89e7f603c5 --- /dev/null +++ b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java @@ -0,0 +1,95 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api.modelchecking.counterexample; + +import java.util.SortedSet; +import java.util.TreeSet; + +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * Tests whether lassos are constructed correctly for any automaton. + * + * @param the {@link Lasso} type to test. + * + * @author Jeroen Meijer + */ +public abstract class AbstractLassoTest> { + + private Alphabet alphabet = Alphabets.fromArray("a"); + + private L lasso1; + private L lasso2; + private L lasso3; + + protected abstract L getLasso(Word prefix, Word loop, int unfoldTimes); + + public Alphabet getAlphabet() { + return alphabet; + } + + @BeforeClass + public void setUp() { + lasso1 = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); + lasso2 = getLasso(Word.fromSymbols("a"), Word.fromSymbols("a"), 1); + lasso3 = getLasso(Word.fromSymbols("a"), Word.fromSymbols("a", "a"), 1); + } + + @Test + public void testGetWord() { + Assert.assertEquals(lasso1.getWord(), Word.fromSymbols("a")); + Assert.assertEquals(lasso2.getWord(), Word.fromSymbols("a", "a")); + Assert.assertEquals(lasso3.getWord(), Word.fromSymbols("a", "a", "a")); + } + + @Test + public void testGetLoop() { + Assert.assertEquals(lasso1.getLoop(), Word.fromSymbols("a")); + Assert.assertEquals(lasso2.getLoop(), Word.fromSymbols("a")); + Assert.assertEquals(lasso3.getLoop(), Word.fromSymbols("a", "a")); + } + + @Test + public void testGetPrefix() { + Assert.assertEquals(lasso1.getPrefix(), Word.epsilon()); + Assert.assertEquals(lasso2.getPrefix(), Word.fromSymbols("a")); + Assert.assertEquals(lasso3.getPrefix(), Word.fromSymbols("a")); + } + + @Test + public void testGetLoopBeginIndices() { + final SortedSet indices = new TreeSet<>(); + indices.add(0); + indices.add(1); + Assert.assertEquals(lasso1.getLoopBeginIndices(), indices); + + indices.clear(); + indices.add(1); + indices.add(2); + Assert.assertEquals(lasso2.getLoopBeginIndices(), indices); + + indices.clear(); + indices.add(1); + indices.add(3); + Assert.assertEquals(lasso3.getLoopBeginIndices(), indices); + } + +} diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java new file mode 100644 index 0000000000..0d963e9639 --- /dev/null +++ b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java @@ -0,0 +1,92 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api.modelchecking.counterexample; + +import java.util.Collection; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.commons.util.collections.CollectionsUtil; +import net.automatalib.words.Word; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author Jeroen Meijer + */ +public class DFALassoTest extends AbstractLassoTest> { + + @Override + protected DFALasso getLasso(Word prefix, Word loop, int unfoldTimes) { + return new DFALasso<>(new DFAMock(prefix, loop), getAlphabet(), unfoldTimes); + } + + @Test + public void testGetOutput() { + final DFALasso lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); + Assert.assertTrue(lasso.getOutput()); + } + + private class DFAMock implements DFA { + + private Word prefix; + private Word word; + + DFAMock(Word prefix, Word loop) { + this.prefix = prefix; + word = prefix.concat(loop); + } + + @Nonnull + @Override + public Collection getStates() { + return CollectionsUtil.intRange(0, word.length()); + } + + @Nullable + @Override + public Integer getTransition(Integer state, @Nullable String input) { + final Integer result; + + if (word.getSymbol(state).equals(input)) { + if (state < word.length() - 1) { + result = state + 1; + } else { + result = prefix.length(); + } + } else { + result = null; + } + + return result; + } + + @Override + public boolean isAccepting(Integer state) { + // dfa is prefix-closed; always return true + return true; + } + + @Nullable + @Override + public Integer getInitialState() { + return 0; + } + } +} diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/LassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/LassoTest.java deleted file mode 100644 index fde5940292..0000000000 --- a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/LassoTest.java +++ /dev/null @@ -1,240 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.api.modelchecking.counterexample; - -import java.util.Collection; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealyTransition; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import net.automatalib.words.impl.Alphabets; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -/** - * Tests whether lassos are constructed correctly for any automaton. - * - * @param the {@link Lasso} type to test. - * - * @author Jeroen Meijer - */ -@Ignore -public abstract class LassoTest> { - - private Alphabet alphabet = Alphabets.fromArray("a"); - - private L lasso1; - private L lasso2; - private L lasso3; - - protected abstract L getLasso(Word prefix, Word loop, int unfoldTimes); - - public Alphabet getAlphabet() { - return alphabet; - } - - @Before - public void setUp() { - lasso1 = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); - lasso2 = getLasso(Word.fromSymbols("a"), Word.fromSymbols("a"), 1); - lasso3 = getLasso(Word.fromSymbols("a"), Word.fromSymbols("a", "a"), 1); - } - - @Test - public void testGetWord() throws Exception { - Assert.assertEquals(lasso1.getWord(), Word.fromSymbols("a")); - Assert.assertEquals(lasso2.getWord(), Word.fromSymbols("a", "a")); - Assert.assertEquals(lasso3.getWord(), Word.fromSymbols("a", "a", "a")); - } - - @Test - public void testGetLoop() throws Exception { - Assert.assertEquals(lasso1.getLoop(), Word.fromSymbols("a")); - Assert.assertEquals(lasso2.getLoop(), Word.fromSymbols("a")); - Assert.assertEquals(lasso3.getLoop(), Word.fromSymbols("a", "a")); - } - - @Test - public void testGetPrefix() throws Exception { - Assert.assertEquals(lasso1.getPrefix(), Word.epsilon()); - Assert.assertEquals(lasso2.getPrefix(), Word.fromSymbols("a")); - Assert.assertEquals(lasso3.getPrefix(), Word.fromSymbols("a")); - } - - @Test - public void testGetLoopBeginIndices() throws Exception { - final SortedSet indices = new TreeSet<>(); - indices.add(0); - indices.add(1); - Assert.assertEquals(lasso1.getLoopBeginIndices(), indices); - - indices.clear(); - indices.add(1); - indices.add(2); - Assert.assertEquals(lasso2.getLoopBeginIndices(), indices); - - indices.clear(); - indices.add(1); - indices.add(3); - Assert.assertEquals(lasso3.getLoopBeginIndices(), indices); - } - - public static class DFALassoTest extends LassoTest> { - - @Override - protected DFALasso getLasso(Word prefix, Word loop, int unfoldTimes) { - return new DFALasso<>(new DFAMock(prefix, loop), getAlphabet(), unfoldTimes); - } - - @Test - public void testGetOutput() throws Exception { - final DFALasso lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); - Assert.assertTrue(lasso.getOutput()); - } - - class DFAMock implements DFA { - - private Word prefix; - private Word word; - - DFAMock(Word prefix, Word loop) { - this.prefix = prefix; - word = prefix.concat(loop); - } - - @Nonnull - @Override - public Collection getStates() { - final Collection states = - IntStream.range(0, word.length()).boxed().collect(Collectors.toSet()); - return states; - } - - @Nullable - @Override - public Integer getTransition(Integer state, @Nullable String input) { - final Integer result; - - if (word.getSymbol(state).equals(input)) { - if (state < word.length() - 1) { - result = state + 1; - } else { - result = prefix.length(); - } - } else { - result = null; - } - - return result; - } - - @Override - public boolean isAccepting(Integer state) { - // dfa is prefix-closed; always return true - return true; - } - - @Nullable - @Override - public Integer getInitialState() { - return 0; - } - } - } - - public static class MealyLassoTest extends LassoTest> { - - @Override - protected MealyLasso getLasso(Word prefix, Word loop, int unfoldTimes) { - return new MealyLasso<>(new MealyMachineMock(prefix, loop), getAlphabet(), 1); - } - - @Test - public void testGetOutput() throws Exception { - final MealyLasso lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); - Assert.assertEquals(lasso.getOutput(), Word.fromSymbols(MealyMachineMock.OUTPUT)); - } - - class MealyMachineMock implements MealyMachine, String> { - - public static final String OUTPUT = "test"; - - private final Word prefix; - private final Word word; - - MealyMachineMock(Word prefix, Word loop) { - this.prefix = prefix; - word = prefix.concat(loop); - } - - @Nullable - @Override - public String getTransitionOutput(CompactMealyTransition transition) { - return OUTPUT; - } - - @Nonnull - @Override - public Collection getStates() { - final Collection states = - IntStream.range(0, word.length()).boxed().collect(Collectors.toSet()); - return states; - } - - @Nullable - @Override - public CompactMealyTransition getTransition(Integer state, @Nullable String input) { - final CompactMealyTransition result; - if (word.getSymbol(state).equals(input)) { - if (state < word.length() - 1) { - result = new CompactMealyTransition<>(state + 1, OUTPUT); - } else { - result = new CompactMealyTransition<>(prefix.length(), OUTPUT); - } - } else { - result = null; - } - - return result; - } - - @Nonnull - @Override - public Integer getSuccessor(CompactMealyTransition transition) { - return transition.getSuccId(); - } - - @Nullable - @Override - public Integer getInitialState() { - return 0; - } - } - } -} diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java new file mode 100644 index 0000000000..a1f5b9c048 --- /dev/null +++ b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java @@ -0,0 +1,100 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api.modelchecking.counterexample; + +import java.util.Collection; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealyTransition; +import net.automatalib.commons.util.collections.CollectionsUtil; +import net.automatalib.words.Word; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author Jeroen Meijer + */ +public class MealyLassoTest extends AbstractLassoTest> { + + @Override + protected MealyLasso getLasso(Word prefix, Word loop, int unfoldTimes) { + return new MealyLasso<>(new MealyMachineMock(prefix, loop), getAlphabet(), 1); + } + + @Test + public void testGetOutput() { + final MealyLasso lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); + Assert.assertEquals(lasso.getOutput(), Word.fromSymbols(MealyMachineMock.OUTPUT)); + } + + private class MealyMachineMock implements MealyMachine, String> { + + public static final String OUTPUT = "test"; + + private final Word prefix; + private final Word word; + + MealyMachineMock(Word prefix, Word loop) { + this.prefix = prefix; + word = prefix.concat(loop); + } + + @Nullable + @Override + public String getTransitionOutput(CompactMealyTransition transition) { + return OUTPUT; + } + + @Nonnull + @Override + public Collection getStates() { + return CollectionsUtil.intRange(0, word.length()); + } + + @Nullable + @Override + public CompactMealyTransition getTransition(Integer state, @Nullable String input) { + final CompactMealyTransition result; + if (word.getSymbol(state).equals(input)) { + if (state < word.length() - 1) { + result = new CompactMealyTransition<>(state + 1, OUTPUT); + } else { + result = new CompactMealyTransition<>(prefix.length(), OUTPUT); + } + } else { + result = null; + } + + return result; + } + + @Nonnull + @Override + public Integer getSuccessor(CompactMealyTransition transition) { + return transition.getSuccId(); + } + + @Nullable + @Override + public Integer getInitialState() { + return 0; + } + } +} diff --git a/build-tools/src/main/resources/learnlib-checkstyle-suppressions.xml b/build-tools/src/main/resources/learnlib-checkstyle-suppressions.xml index 84e6c06597..ac8e241275 100644 --- a/build-tools/src/main/resources/learnlib-checkstyle-suppressions.xml +++ b/build-tools/src/main/resources/learnlib-checkstyle-suppressions.xml @@ -19,7 +19,7 @@ limitations under the License. "http://www.puppycrawl.com/dtds/suppressions_1_0.dtd"> - + diff --git a/distribution/pom.xml b/distribution/pom.xml index e8e73cc8fa..607d19c99a 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -171,18 +171,18 @@ limitations under the License. learnlib-drivers-simulator - + de.learnlib - learnlib-examples + learnlib-model-checkers + - de.learnlib.testsupport - learnlib-learning-examples + de.learnlib + learnlib-bbc-oracles - de.learnlib learnlib-equivalence-oracles @@ -213,27 +213,6 @@ limitations under the License. learnlib-parallelism - - de.learnlib - learnlib-black-box-oracles - - - - de.learnlib - learnlib-emptiness-oracles - - - - de.learnlib - learnlib-inclusion-oracles - - - - - de.learnlib - learnlib-model-checkers - - net.automatalib.distribution @@ -450,22 +429,22 @@ limitations under the License. sources - + de.learnlib - learnlib-examples + learnlib-model-checkers ${project.version} sources + - de.learnlib.testsupport - learnlib-learning-examples + de.learnlib + learnlib-bbc-oracles ${project.version} sources - de.learnlib learnlib-equivalence-oracles @@ -507,35 +486,6 @@ limitations under the License. ${project.version} sources - - - de.learnlib - learnlib-black-box-oracles - ${project.version} - sources - - - - de.learnlib - learnlib-emptiness-oracles - ${project.version} - sources - - - - de.learnlib - learnlib-inclusion-oracles - ${project.version} - sources - - - - - de.learnlib - learnlib-model-checkers - ${project.version} - sources - diff --git a/examples/pom.xml b/examples/pom.xml index 1c0499e557..8800181212 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -62,6 +62,10 @@ limitations under the License. --> + + de.learnlib + learnlib-acex + de.learnlib learnlib-api @@ -78,6 +82,14 @@ limitations under the License. de.learnlib learnlib-lstar + + de.learnlib + learnlib-ttt + + + de.learnlib + learnlib-bbc-oracles + de.learnlib learnlib-equivalence-oracles @@ -102,6 +114,15 @@ limitations under the License. de.learnlib learnlib-util + + de.learnlib + learnlib-model-checkers + + + de.learnlib.testsupport + learnlib-learning-examples + compile + @@ -131,33 +152,5 @@ limitations under the License. logback-classic runtime - - de.learnlib - learnlib-model-checkers - - - de.learnlib - learnlib-black-box-oracles - - - de.learnlib - learnlib-emptiness-oracles - - - de.learnlib - learnlib-inclusion-oracles - - - de.learnlib - learnlib-ttt - - - de.learnlib.testsupport - learnlib-learning-examples - - - de.learnlib - learnlib-acex - diff --git a/model-checkers/pom.xml b/model-checkers/pom.xml index ee4ba361cd..99e89d85cd 100644 --- a/model-checkers/pom.xml +++ b/model-checkers/pom.xml @@ -61,14 +61,16 @@ limitations under the License. buildergen - junit - junit - test + org.slf4j + slf4j-api + + + org.testng + testng org.mockito mockito-core - test de.learnlib diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java index a6d7534c82..254a91f378 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java @@ -31,15 +31,13 @@ import net.automatalib.serialization.fsm.parser.AbstractFSMParser; import net.automatalib.serialization.fsm.parser.FSMParseException; import net.automatalib.ts.simple.SimpleDTS; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * An LTL model checker using LTSmin. * * The user must install LTSmin in order for {@link AbstractLTSminLTL} to run without exceptions. Once LTSmin is installed * the user may specify the path to the installed LTSmin binaries with the property - * de.learnlib.external.ltsmin.path. If this property is not set the binaries will be run as usual (e.g. simply + * learnlib.external.ltsmin.path. If this property is not set the binaries will be run as usual (e.g. simply * by invoking etf2lts-mc, and ltsmin-convert), which means the user can also specify the location of the binaries * in the PATH environment variable. * @@ -65,44 +63,11 @@ public abstract class AbstractLTSminLTL> extends AbstractUnfoldingModelChecker implements ModelChecker { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLTSminLTL.class); - - public static final String LTSMIN_PATH; - - public static final String LTSMIN_PATH_PROPERTY = "de.learnlib.external.ltsmin.path"; - - static { - LearnLibSettings settings = LearnLibSettings.getInstance(); - - LTSMIN_PATH = settings.getProperty(LTSMIN_PATH_PROPERTY, ""); - } - - public static final String ETF2LTS_MC = LTSMIN_PATH + "etf2lts-mc"; - - public static final String LTSMIN_CONVERT = LTSMIN_PATH + "ltsmin-convert"; - - public static final String CHECK = "An exception occurred while checking if LTSmin is installed. " + - "Could not run binary '%s', the following exception occurred: %s. " + - "LTSmin can be obtained at https://ltsmin.utwente.nl. If you installed LTSmin " + - "in a non standard location you can set the property: " + - "'de.learnlib.external.ltsmin.path', which must end with a '/'. Setting the " + - "PATH variable works too."; - - /** - * The exit code for running an LTSmin binary with --version. - */ - public static final int VERSION_EXIT = 255; - /** * @see #isKeepFiles() */ private final boolean keepFiles; - /** - * @see #isInheritIO() - */ - private final boolean inheritIO; - /** * @see #getString2Input() */ @@ -120,22 +85,18 @@ public abstract class AbstractLTSminLTL string2Input, int minimumUnfolds, - double multiplier, - boolean inheritIO) throws ModelCheckingException { + double multiplier) throws ModelCheckingException { super(minimumUnfolds, multiplier); this.keepFiles = keepFiles; this.string2Input = string2Input; - this.inheritIO = inheritIO; if (!binariesChecked) { - if (!checkUsable()) { + if (!LTSminUtil.checkUsable()) { throw new ModelCheckingException("LTSmin binary could not be executed correctly"); } binariesChecked = true; @@ -160,15 +121,6 @@ public Function getString2Input() { return string2Input; } - /** - * Returns whether all streams from standard-in, -out, and -error should be inherited. - * - * @return the boolean - */ - public boolean isInheritIO() { - return inheritIO; - } - /** * Writes the given {@code automaton} to the given {@code etf} file. * @@ -220,7 +172,7 @@ public final L findCounterExample(A hypothesis, Collection inputs, final List commandLines = new ArrayList<>(); // add the etf2lts-mc binary - commandLines.add(ETF2LTS_MC); + commandLines.add(LTSminUtil.ETF2LTS_MC); // add the ETF file that contains the LTS of the hypothesis commandLines.add(etf.getAbsolutePath()); @@ -250,9 +202,6 @@ public final L findCounterExample(A hypothesis, Collection inputs, try { // run the etf2lts-mc binary ProcessBuilder processBuilder = new ProcessBuilder(commandLines); - if (inheritIO) { - processBuilder = processBuilder.inheritIO(); - } ltsmin = processBuilder.start(); ltsmin.waitFor(); } catch (IOException | InterruptedException e) { @@ -279,7 +228,7 @@ public final L findCounterExample(A hypothesis, Collection inputs, } // add the ltsmin-convert binary - commandLines.add(LTSMIN_CONVERT); + commandLines.add(LTSminUtil.LTSMIN_CONVERT); // use the GCF as input commandLines.add(gcf.getAbsolutePath()); @@ -294,9 +243,6 @@ public final L findCounterExample(A hypothesis, Collection inputs, try { // convert the GCF to FSM ProcessBuilder processBuilder = new ProcessBuilder(commandLines); - if (inheritIO) { - processBuilder = processBuilder.inheritIO(); - } convert = processBuilder.start(); convert.waitFor(); } catch (IOException | InterruptedException e) { @@ -331,51 +277,6 @@ public final L findCounterExample(A hypothesis, Collection inputs, return result; } - /** - * Checks whether the given binary can be executed, by performing a version check. - * - * @throws ModelCheckingException when the given binary can not be run successfully. - */ - public static boolean checkUsable() { - return checkUsable(ETF2LTS_MC) && checkUsable(LTSMIN_CONVERT); - } - - /** - * Checks whether the given binary can be executed, by performing a version check. - * - * @param bin the binary to check. - * - * @throws ModelCheckingException when the given binary can not be run successfully. - */ - private static boolean checkUsable(String bin) { - - // the command lines for the ProcessBuilder - final List commandLines = new ArrayList<>(); - - // add the binary - commandLines.add(bin); - - // just run a version check - commandLines.add("--version"); - - final Process check; - try { - ProcessBuilder processBuilder = new ProcessBuilder(commandLines); - check = processBuilder.start(); - check.waitFor(); - } catch (IOException | InterruptedException e) { - LOGGER.error(String.format(CHECK, bin, e.toString()), e); - return false; - } - - if (check.exitValue() != VERSION_EXIT) { - LOGGER.error(String.format(CHECK, bin, String.format("Command '%s --version' did not exit with 255", bin))); - return false; - } - - return true; - } - public static class BuilderDefaults { public static boolean keepFiles() { @@ -389,9 +290,5 @@ public static int minimumUnfolds() { public static double multiplier() { return 1.0; // quite arbitrary too } - - public static boolean inheritIO() { - return false; - } } } diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java index 222b7f0588..d8733e01ae 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java @@ -68,15 +68,13 @@ public abstract class AbstractLTSminLTLMealy * * @see AbstractLTSminLTL */ - protected AbstractLTSminLTLMealy( - boolean keepFiles, - Function string2Input, - Function string2Output, - int minimumUnfolds, - double multiplier, - boolean inheritIO, - Collection skipOutputs) { - super(keepFiles, string2Input, minimumUnfolds, multiplier, inheritIO); + protected AbstractLTSminLTLMealy(boolean keepFiles, + Function string2Input, + Function string2Output, + int minimumUnfolds, + double multiplier, + Collection skipOutputs) { + super(keepFiles, string2Input, minimumUnfolds, multiplier); this.string2Output = string2Output; this.skipOutputs = skipOutputs == null ? Collections.emptyList() : skipOutputs; } diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java index 409c5545c9..bd5e2548f3 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java @@ -31,15 +31,17 @@ /** * An LTL model checker using LTSmin for Mealy machines using alternating edge semantics. - * + *

* The implementation uses {@link FSM2MealyParserAlternating}, and {@link Mealy2ETFWriterAlternating}, to read the * {@link de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso}, and write the {@link MealyMachine} * respectively. * - * @author Jeroen Meijer + * @param + * the input type + * @param + * the output type * - * @param the input type - * @param the output type + * @author Jeroen Meijer */ public class LTSminLTLAlternating extends AbstractLTSminLTLMealy { @@ -49,9 +51,8 @@ public LTSminLTLAlternating(boolean keepFiles, Function string2Output, int minimumUnfolds, double multiplier, - boolean inheritIO, Collection skipOutputs) { - super(keepFiles, string2Input, string2Output, minimumUnfolds, multiplier, inheritIO, skipOutputs); + super(keepFiles, string2Input, string2Output, minimumUnfolds, multiplier, skipOutputs); } @Override diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java index e83f72c771..02b874f808 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java @@ -67,12 +67,8 @@ public class LTSminLTLDFA public static final String LABEL_VALUE = "accept"; @GenerateBuilder(defaults = BuilderDefaults.class) - public LTSminLTLDFA(boolean keepFiles, - Function string2Input, - int minimumUnfolds, - double multiplier, - boolean inheritIO) { - super(keepFiles, string2Input, minimumUnfolds, multiplier, inheritIO); + public LTSminLTLDFA(boolean keepFiles, Function string2Input, int minimumUnfolds, double multiplier) { + super(keepFiles, string2Input, minimumUnfolds, multiplier); } diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java index 5ca6108437..e0013f910e 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java @@ -31,28 +31,28 @@ /** * An LTL model checker using LTSmin for Mealy machines using alternating edge semantics. - * + *

* The implementation uses {@link FSM2MealyParserIO}, and {@link Mealy2ETFWriterIO}, to read the * {@link de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso}, and write the {@link MealyMachine} * respectively. * - * @author Jeroen Meijer + * @param + * the input type + * @param + * the output type * - * @param the input type - * @param the output type + * @author Jeroen Meijer */ public class LTSminLTLIO extends AbstractLTSminLTLMealy { @GenerateBuilder(defaults = BuilderDefaults.class) - public LTSminLTLIO( - boolean keepFiles, - Function string2Input, - Function string2Output, - int minimumUnfolds, - double multiplier, - boolean inheritIO, - Collection skipOutputs) { - super(keepFiles, string2Input, string2Output, minimumUnfolds, multiplier, inheritIO, skipOutputs); + public LTSminLTLIO(boolean keepFiles, + Function string2Input, + Function string2Output, + int minimumUnfolds, + double multiplier, + Collection skipOutputs) { + super(keepFiles, string2Input, string2Output, minimumUnfolds, multiplier, skipOutputs); } @Override diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java new file mode 100644 index 0000000000..5a1b7892a3 --- /dev/null +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java @@ -0,0 +1,122 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.modelchecking.modelchecker; + +import java.io.IOException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.setting.LearnLibSettings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A utility class that encapsulates certain technical aspects of LTSmin (e.g. accessibility of the binary, etc.) + * + * @author Jeroen Meijer + * @author frohme + */ +public final class LTSminUtil { + + public static final String LTSMIN_PATH_PROPERTY_SUFFIX = "external.ltsmin.path"; + + /** + * Path to the "etf2lts-mc" binary. + */ + static final String ETF2LTS_MC; + + /** + * Path to the "ltsmin-convert" binary. + */ + static final String LTSMIN_CONVERT; + + private static final Logger LOGGER = LoggerFactory.getLogger(LTSminUtil.class); + + private static final String CHECK = "An exception occurred while checking if LTSmin is installed. " + + "Could not run binary '%s', the following exception occurred: %s. " + + "LTSmin can be obtained at https://ltsmin.utwente.nl. If you installed LTSmin " + + "in a non standard location you can set the property: " + + "'learnlib.external.ltsmin.path'. Setting the $PATH variable works too."; + + /** + * The exit code for running an LTSmin binary with --version. + */ + private static final int VERSION_EXIT = 255; + + static { + LearnLibSettings settings = LearnLibSettings.getInstance(); + + final String ltsMinPath = settings.getProperty(LTSMIN_PATH_PROPERTY_SUFFIX, ""); + + ETF2LTS_MC = Paths.get(ltsMinPath, "etf2lts-mc").toString(); + LTSMIN_CONVERT = Paths.get(ltsMinPath, "ltsmin-convert").toString(); + } + + private LTSminUtil() { + throw new AssertionError(); + } + + /** + * Checks whether the required binaries for the {@link AbstractLTSminLTL LTSmin modelchecker} can be executed, by + * performing a version check. + * + * @return {@code true} if the binary returned with the expected exit value, {@code false} otherwise. + * + * @see #ETF2LTS_MC + * @see #LTSMIN_CONVERT + */ + public static boolean checkUsable() { + return checkUsable(ETF2LTS_MC) && checkUsable(LTSMIN_CONVERT); + } + + /** + * Checks whether the given binary can be executed, by performing a version check. + * + * @param bin + * the binary to check. + * + * @return {@code true} if the binary returned with the expected exit value, {@code false} otherwise. + */ + private static boolean checkUsable(String bin) { + + // the command lines for the ProcessBuilder + final List commandLines = new ArrayList<>(); + + // add the binary + commandLines.add(bin); + + // just run a version check + commandLines.add("--version"); + + final Process check; + try { + ProcessBuilder processBuilder = new ProcessBuilder(commandLines); + check = processBuilder.start(); + check.waitFor(); + } catch (IOException | InterruptedException e) { + LOGGER.error(String.format(CHECK, bin, e.toString()), e); + return false; + } + + if (check.exitValue() != VERSION_EXIT) { + LOGGER.error(String.format(CHECK, bin, String.format("Command '%s --version' did not exit with 255", bin))); + return false; + } + + return true; + } +} diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java index 266e1c8770..122e399950 100644 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java @@ -25,10 +25,10 @@ import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import org.junit.Assert; -import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.Test; /** * @author Jeroen Meijer diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java index d9252e6e0f..42bf7a7a32 100644 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java @@ -20,12 +20,11 @@ import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; import net.automatalib.words.impl.Alphabets; -import org.junit.After; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; /** * Tests for AbstractLTSminLTL with arbitrary LTSs. @@ -37,8 +36,6 @@ public abstract class AbstractLTSminLTLTest & Out L extends Lasso> extends AbstractUnfoldingModelCheckerTest { - private static String ltsminPathPropertyDefault; - private final Alphabet alphabet = Alphabets.fromArray("a", "b"); private L lasso; @@ -58,12 +55,13 @@ public Alphabet getAlphabet() { protected abstract String createFalseProperty(); @BeforeClass - public static void setUpBeforeClass() { - Assume.assumeTrue(AbstractLTSminLTL.checkUsable()); - ltsminPathPropertyDefault = System.getProperty(AbstractLTSminLTL.LTSMIN_PATH_PROPERTY); + public void setupBeforeClass() { + if (!LTSminUtil.checkUsable()) { + throw new SkipException("LTSmin not installed"); + } } - @Before + @BeforeMethod public void setUp() throws Exception { super.setUp(); lasso = createLasso(); @@ -71,13 +69,6 @@ public void setUp() throws Exception { falseProperty = createFalseProperty(); } - @After - public void tearDown() { - if (ltsminPathPropertyDefault != null) { - System.setProperty(AbstractLTSminLTL.LTSMIN_PATH_PROPERTY, ltsminPathPropertyDefault); - } - } - /** * First test for the absence of a counterexample, then test for the presence. */ diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java index abaa917aa3..a2bb9989bc 100644 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java @@ -15,9 +15,9 @@ */ package de.learnlib.modelchecking.modelchecker; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; /** * @author Jeroen Meijer @@ -32,41 +32,41 @@ public M getModelChecker() { protected abstract M createModelChecker(); - @Before + @BeforeMethod public void setUp() throws Exception { modelChecker = createModelChecker(); } @Test - public void testComputeUnfolds() throws Exception { + public void testComputeUnfolds() { Assert.assertEquals(modelChecker.computeUnfolds(1), 3); modelChecker.setMultiplier(2.0); Assert.assertEquals(modelChecker.computeUnfolds(2), 4); } - @Test(expected = IllegalArgumentException.class) + @Test(expectedExceptions = IllegalArgumentException.class) public void testComputeUnfoldsExcept() { modelChecker.computeUnfolds(0); } @Test - public void testSetMinimumUnfolds() throws Exception { + public void testSetMinimumUnfolds() { modelChecker.setMinimumUnfolds(1337); Assert.assertEquals(modelChecker.getMinimumUnfolds(), 1337); } - @Test(expected = IllegalArgumentException.class) + @Test(expectedExceptions = IllegalArgumentException.class) public void testSetMinimumUnfoldsExcept() { modelChecker.setMinimumUnfolds(0); } @Test - public void testSetMultiplier() throws Exception { + public void testSetMultiplier() { modelChecker.setMultiplier(1337.0); Assert.assertEquals(modelChecker.getMultiplier(), 1337.0, 0.0); } - @Test(expected = IllegalArgumentException.class) + @Test(expectedExceptions = IllegalArgumentException.class) public void testSetMultiplierExcept() { modelChecker.setMultiplier(-1.0); } diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java index 19f7206b53..3be7a88d0b 100644 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java +++ b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java @@ -19,7 +19,7 @@ import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; import net.automatalib.automata.fsa.DFA; import net.automatalib.util.automata.builders.AutomatonBuilders; -import org.junit.Test; +import org.testng.annotations.Test; /** * @author Jeroen Meijer @@ -51,7 +51,7 @@ protected String createFalseProperty() { /** * Test that a {@link ModelCheckingException} is thrown when a {@link DFA} is not prefix-closed. */ - @Test(expected = ModelCheckingException.class) + @Test(expectedExceptions = ModelCheckingException.class) public void testPrefixClosed() { final DFA dfa = AutomatonBuilders.newDFA(getAlphabet()). withInitial("q0").withAccepting("q1"). @@ -63,7 +63,7 @@ public void testPrefixClosed() { /** * Test that a {@link ModelCheckingException} is thrown when a {@link DFA} accepts the empty language. */ - @Test(expected = ModelCheckingException.class) + @Test(expectedExceptions = ModelCheckingException.class) public void testEmptyLanguage() { final DFA dfa = AutomatonBuilders.newDFA(getAlphabet()). withInitial("q0").from("q0").on("a").loop().from("q0").on("b").loop().create(); diff --git a/oracles/emptiness-oracles/pom.xml b/oracles/bbc-oracles/pom.xml similarity index 77% rename from oracles/emptiness-oracles/pom.xml rename to oracles/bbc-oracles/pom.xml index 4bde283311..251ed5890f 100644 --- a/oracles/emptiness-oracles/pom.xml +++ b/oracles/bbc-oracles/pom.xml @@ -26,52 +26,44 @@ limitations under the License. 4.0.0 - learnlib-emptiness-oracles - LearnLib :: Oracles :: Emptiness Oracles - A collection of emptiness oracles + learnlib-bbc-oracles + LearnLib :: Oracles :: BBC Oracles + + A collection of oracles required for block-box checking. Includes black-box, emptiness and language inclusion + oracles + de.learnlib learnlib-api - junit - junit - test - - - org.mockito - mockito-core - test + net.automatalib + automata-core - de.learnlib.testsupport - learnlib-oracle-support + net.automatalib + automata-util - de.learnlib.testsupport - learnlib-learning-examples - test + net.automatalib + automata-api com.google.code.findbugs jsr305 - net.automatalib - automata-api - - - net.automatalib - automata-core + de.learnlib.testsupport + learnlib-learning-examples - net.automatalib - automata-util + org.mockito + mockito-core - de.learnlib - learnlib-util + org.testng + testng \ No newline at end of file diff --git a/commons/util/src/main/java/de/learnlib/util/AbstractBreadthFirstOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java similarity index 99% rename from commons/util/src/main/java/de/learnlib/util/AbstractBreadthFirstOracle.java rename to oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java index 1ae733b96c..d8647f6204 100644 --- a/commons/util/src/main/java/de/learnlib/util/AbstractBreadthFirstOracle.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.util; +package de.learnlib.oracle; import java.util.LinkedList; import java.util.Queue; diff --git a/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java similarity index 100% rename from oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java rename to oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java diff --git a/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java similarity index 100% rename from oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java rename to oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java diff --git a/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java similarity index 100% rename from oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java rename to oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java diff --git a/oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java similarity index 100% rename from oracles/black-box-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java rename to oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java similarity index 97% rename from oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java rename to oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java index 6888b57258..3922ed8209 100644 --- a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java @@ -20,7 +20,7 @@ import de.learnlib.api.oracle.EmptinessOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.util.AbstractBreadthFirstOracle; +import de.learnlib.oracle.AbstractBreadthFirstOracle; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java similarity index 98% rename from oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java rename to oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java index b872b39c6f..2d59590c3e 100644 --- a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java @@ -26,7 +26,7 @@ import de.learnlib.api.oracle.OmegaMembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; -import de.learnlib.util.AbstractBreadthFirstOracle; +import de.learnlib.oracle.AbstractBreadthFirstOracle; import net.automatalib.automata.concepts.Output; import net.automatalib.words.Word; diff --git a/oracles/inclusion-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java similarity index 97% rename from oracles/inclusion-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java rename to oracles/bbc-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java index f2d7063ce1..654c13cebb 100644 --- a/oracles/inclusion-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java @@ -18,7 +18,7 @@ import de.learnlib.api.oracle.InclusionOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.util.AbstractBreadthFirstOracle; +import de.learnlib.oracle.AbstractBreadthFirstOracle; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; diff --git a/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AbstractBreadthFirstOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/AbstractBreadthFirstOracleTest.java similarity index 83% rename from test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AbstractBreadthFirstOracleTest.java rename to oracles/bbc-oracles/src/test/java/de/learnlib/oracle/AbstractBreadthFirstOracleTest.java index d3d5b36005..a2f4e801cd 100644 --- a/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AbstractBreadthFirstOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/AbstractBreadthFirstOracleTest.java @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.util; +package de.learnlib.oracle; import java.util.NoSuchElementException; import de.learnlib.api.query.Query; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Word; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; /** * Class to test any {@link AbstractBreadthFirstOracle}. @@ -36,16 +37,17 @@ public abstract class AbstractBreadthFirstOracleTest { private AbstractBreadthFirstOracle, Character, D, ? extends Query> bfo; - protected abstract AbstractBreadthFirstOracle, Character, D, ? extends Query> - createBreadthFirstOracle(int maxWords); + protected abstract AbstractBreadthFirstOracle, Character, D, ? extends Query> createBreadthFirstOracle( + int maxWords); - @Before + @BeforeMethod public void setUp() { + MockitoAnnotations.initMocks(this); bfo = createBreadthFirstOracle(MAX_WORDS); } @Test - public void testGetMaxWords() throws Exception { + public void testGetMaxWords() { Assert.assertEquals(bfo.getMaxWords(), MAX_WORDS); } @@ -62,13 +64,13 @@ public void testNextInput() { } @Test - public void testAddWord() throws Exception { + public void testAddWord() { bfo.pre(); bfo.addWord(Word.epsilon()); Assert.assertEquals(bfo.nextInput(), Word.epsilon()); } - @Test(expected = NoSuchElementException.class) + @Test(expectedExceptions = NoSuchElementException.class) public void testPre() { bfo.pre(); bfo.addWord(Word.epsilon()); diff --git a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java similarity index 87% rename from oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java rename to oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java index a9fb148f07..14a4504837 100644 --- a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java @@ -20,21 +20,25 @@ import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; import net.automatalib.automata.concepts.Output; import net.automatalib.ts.simple.SimpleDTS; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; /** * @author Jeroen Meijer */ -@RunWith(MockitoJUnitRunner.class) public abstract class AbstractBlackBoxOracleTest { public abstract AbstractBlackBoxOracle> getBaseBlackBoxOracle(); + @BeforeMethod + public void setUp() { + MockitoAnnotations.initMocks(this); + } + @Test public void testAmount() { final Set> bbps = getBaseBlackBoxOracle().getProperties(); diff --git a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java similarity index 94% rename from oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java rename to oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java index a80a5dcf38..2d40425aa0 100644 --- a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java @@ -23,18 +23,15 @@ import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; import de.learnlib.api.query.DefaultQuery; import net.automatalib.words.Alphabet; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; /** * @author Jeroen Meijer */ -@RunWith(MockitoJUnitRunner.class) public class CExFirstBBOracleTest extends AbstractBlackBoxOracleTest { private CExFirstBBOracle> oracle; @@ -54,9 +51,9 @@ public class CExFirstBBOracleTest extends AbstractBlackBoxOracleTest { @Mock private Alphabet alphabet; - @Before + @BeforeMethod public void setUp() { - + super.setUp(); Mockito.when(blackBoxProperty1.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); Mockito.when(blackBoxProperty2.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); diff --git a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java similarity index 93% rename from oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java rename to oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java index c5da2b2761..2bc6eb5401 100644 --- a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java @@ -22,18 +22,15 @@ import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; import de.learnlib.api.query.DefaultQuery; import net.automatalib.words.Alphabet; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; /** * @author Jeroen Meijer */ -@RunWith(MockitoJUnitRunner.class) public class DisproveFirstBBOracleTest extends AbstractBlackBoxOracleTest { private DisproveFirstBBOracle> oracle; @@ -53,9 +50,9 @@ public class DisproveFirstBBOracleTest extends AbstractBlackBoxOracleTest { @Mock private Alphabet alphabet; - @Before + @BeforeMethod public void setUp() { - + super.setUp(); Mockito.when(blackBoxProperty1.findCounterExample(automaton, alphabet)).thenReturn(null); Mockito.when(blackBoxProperty2.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); diff --git a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java similarity index 92% rename from oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java rename to oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java index ee862f8267..78159c5de5 100644 --- a/oracles/black-box-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java @@ -25,12 +25,11 @@ import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; import net.automatalib.words.impl.Alphabets; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; /** * Tests the cached, and uncached implementations of {@link ModelCheckingBBProperty#disprove(Output, Collection)}, and @@ -38,7 +37,6 @@ * * @author Jeroen Meijer */ -@RunWith(MockitoJUnitRunner.class) public class ModelCheckingBBPropertyTest { private Alphabet alphabet = Alphabets.fromArray("a"); @@ -60,14 +58,15 @@ public class ModelCheckingBBPropertyTest { private ModelCheckingBBProperty mcbbp; - @Before + @BeforeMethod public void setUp() { + MockitoAnnotations.initMocks(this); mcbbp = new ModelCheckingBBProperty<>(modelChecker, emptinessOracle, inclusionOracle, ""); Mockito.when(modelChecker.findCounterExample(automaton, alphabet, "")).thenReturn(result); } @Test - public void testDisproveUncached() throws Exception { + public void testDisproveUncached() { mcbbp.disprove(automaton, alphabet); Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); Mockito.verify(emptinessOracle, Mockito.times(1)).findCounterExample(result, alphabet); @@ -76,7 +75,7 @@ public void testDisproveUncached() throws Exception { } @Test - public void testDisproveCached() throws Exception { + public void testDisproveCached() { mcbbp.useCache(); mcbbp.disprove(automaton, alphabet); @@ -96,7 +95,7 @@ public void testDisproveCached() throws Exception { } @Test - public void testFindCounterExampleUncached() throws Exception { + public void testFindCounterExampleUncached() { mcbbp.findCounterExample(automaton, alphabet); Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); Mockito.verify(inclusionOracle, Mockito.times(1)).findCounterExample(result, alphabet); @@ -105,7 +104,7 @@ public void testFindCounterExampleUncached() throws Exception { } @Test - public void testFindCounterExampleCached() throws Exception { + public void testFindCounterExampleCached() { mcbbp.useCache(); mcbbp.findCounterExample(automaton, alphabet); diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java similarity index 79% rename from oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java rename to oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java index d0613aa404..a9ee061a5f 100644 --- a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java @@ -21,28 +21,26 @@ import de.learnlib.examples.dfa.ExampleAngluin; import de.learnlib.examples.mealy.ExampleCoffeeMachine; import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.AbstractBreadthFirstOracleTest; import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.DFABFEmptinessOracle; import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.MealyBreadthFirstEmptinessOracle; -import de.learnlib.util.AbstractBreadthFirstOracle; -import de.learnlib.util.AbstractBreadthFirstOracleTest; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; -@RunWith(MockitoJUnitRunner.class) +/** + * @author Jeroen Meijer + */ public abstract class AbstractBreadthFirstEmptinessOracleTest & Output, I, D> extends AbstractBreadthFirstOracleTest { @@ -62,7 +60,7 @@ public abstract class AbstractBreadthFirstEmptinessOracleTest createQuery(); - @Before + @BeforeMethod public void setUp() { super.setUp(); bfeo = createBreadthFirstEmptinessOracle(); @@ -72,7 +70,7 @@ public void setUp() { } @Test - public void testFindCounterExample() throws Exception { + public void testFindCounterExample() { final DefaultQuery cex = bfeo.findCounterExample(automaton, alphabet); Assert.assertEquals(query, cex); } @@ -86,20 +84,17 @@ public static class DFABFEmptinessOracleTest @Mock private DFAMembershipOracle dfaMembershipOracle2; - @Before + @BeforeMethod public void setUp() { super.setUp(); - Mockito.doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - final DefaultQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(0, 0))) { - q.answer(false); - } else { - q.answer(true); - } - return null; + Mockito.doAnswer(invocation -> { + final DefaultQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(0, 0))) { + q.answer(false); + } else { + q.answer(true); } + return null; }).when(dfaMembershipOracle).processQuery(Matchers.any()); } @@ -141,20 +136,17 @@ public static class MealyBFEmptinessOracleTest @Mock private MealyMembershipOracle mealyMembershipOracle2; - @Before + @BeforeMethod public void setUp() { super.setUp(); - Mockito.doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - final DefaultQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(Input.POD))) { - q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; + Mockito.doAnswer(invocation -> { + final DefaultQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(Input.POD))) { + q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); + } else { + q.answer(Word.fromSymbols("not-an-output")); } + return null; }).when(mealyMembershipOracle).processQuery(Matchers.any()); } diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java similarity index 77% rename from oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java rename to oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java index 9810a38340..bca0fd90c0 100644 --- a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java @@ -25,10 +25,10 @@ import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.AbstractBreadthFirstOracleTest; import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.DFALassoDFAEmptinessOracle; import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; -import de.learnlib.util.AbstractBreadthFirstOracle; -import de.learnlib.util.AbstractBreadthFirstOracleTest; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.fsa.impl.compact.CompactDFA; import net.automatalib.automata.transout.MealyMachine; @@ -38,18 +38,16 @@ import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; -@RunWith(MockitoJUnitRunner.class) +/** + * @author Jeroen Meijer + */ public abstract class AbstractLassoAutomatonEmptinessTest, D> extends AbstractBreadthFirstOracleTest { @@ -67,7 +65,7 @@ public abstract class AbstractLassoAutomatonEmptinessTest createQuery(); - @Before + @BeforeMethod public void setUp() { super.setUp(); laeo = createLassoAutomatonEmptinessOracle(); @@ -76,7 +74,7 @@ public void setUp() { } @Test - public void testFindCounterExample() throws Exception { + public void testFindCounterExample() { final DefaultQuery cex = laeo.findCounterExample(lasso, ALPHABET); Assert.assertEquals(query, cex); } @@ -90,26 +88,23 @@ public static class DFALassoDFAEmptinessOracleTest @Mock private DFAOmegaMembershipOracle dfaOmegaMembershipOracle2; - @Before + @BeforeMethod public void setUp() { super.setUp(); - Mockito.doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - final OmegaQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { - q.answer(true); - final List states = new ArrayList<>(); - states.add(0); - states.add(0); - states.add(0); - states.add(0); - q.setStates(states); - } else { - q.answer(false); - } - return null; + Mockito.doAnswer(invocation -> { + final OmegaQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { + q.answer(true); + final List states = new ArrayList<>(); + states.add(0); + states.add(0); + states.add(0); + states.add(0); + q.setStates(states); + } else { + q.answer(false); } + return null; }).when(dfaOmegaMembershipOracle).processQuery(Matchers.any()); Mockito.when(dfaOmegaMembershipOracle.isSameState(Matchers.any(), Matchers.any(), @@ -153,26 +148,23 @@ public static class MealyLassoMealyEmptinessOracleTest @Mock private MealyOmegaMembershipOracle mealyOmegaMembershipOracle2; - @Before + @BeforeMethod public void setUp() { super.setUp(); - Mockito.doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - final OmegaQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { - q.answer(Word.fromSymbols("1", "1", "1")); - final List states = new ArrayList<>(); - states.add(0); - states.add(0); - states.add(0); - states.add(0); - q.setStates(states); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; + Mockito.doAnswer(invocation -> { + final OmegaQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { + q.answer(Word.fromSymbols("1", "1", "1")); + final List states = new ArrayList<>(); + states.add(0); + states.add(0); + states.add(0); + states.add(0); + q.setStates(states); + } else { + q.answer(Word.fromSymbols("not-an-output")); } + return null; }).when(mealyOmegaMembershipOracle).processQuery(Matchers.any()); Mockito.when(mealyOmegaMembershipOracle.isSameState(Matchers.any(), Matchers.any(), diff --git a/oracles/inclusion-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java similarity index 79% rename from oracles/inclusion-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java rename to oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java index a3408ec05b..961a198eb6 100644 --- a/oracles/inclusion-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java @@ -21,28 +21,26 @@ import de.learnlib.examples.dfa.ExampleAngluin; import de.learnlib.examples.mealy.ExampleCoffeeMachine; import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.AbstractBreadthFirstOracleTest; import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.DFABreadthFirstInclusionOracle; import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; -import de.learnlib.util.AbstractBreadthFirstOracle; -import de.learnlib.util.AbstractBreadthFirstOracleTest; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; -@RunWith(MockitoJUnitRunner.class) +/** + * @author Jeroen Meijer + */ public abstract class AbstractBreadthFirstInclusionOracleTest & Output, I, D> extends AbstractBreadthFirstOracleTest { @@ -62,7 +60,7 @@ public abstract class AbstractBreadthFirstInclusionOracleTest createQuery(); - @Before + @BeforeMethod public void setUp() { super.setUp(); bfeo = createBreadthFirstInclusionOracle(); @@ -72,7 +70,7 @@ public void setUp() { } @Test - public void testFindCounterExample() throws Exception { + public void testFindCounterExample() { final DefaultQuery cex = bfeo.findCounterExample(automaton, alphabet); Assert.assertEquals(query, cex); } @@ -86,20 +84,17 @@ public static class DFABreadthFirstInclusionOracleTest @Mock private DFAMembershipOracle dfaMembershipOracle2; - @Before + @BeforeMethod public void setUp() { super.setUp(); - Mockito.doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - final DefaultQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(0, 0))) { - q.answer(true); - } else { - q.answer(false); - } - return null; + Mockito.doAnswer(invocation -> { + final DefaultQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(0, 0))) { + q.answer(true); + } else { + q.answer(false); } + return null; }).when(dfaMembershipOracle).processQuery(Matchers.any()); } @@ -139,20 +134,17 @@ public static class MealyBreadthFirstInclusionOracleTest @Mock private MealyMembershipOracle mealyMembershipOracle2; - @Before + @BeforeMethod public void setUp() { super.setUp(); - Mockito.doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - final DefaultQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(Input.WATER))) { - q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; + Mockito.doAnswer(invocation -> { + final DefaultQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(Input.WATER))) { + q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); + } else { + q.answer(Word.fromSymbols("not-an-output")); } + return null; }).when(mealyMembershipOracle).processQuery(Matchers.any()); } diff --git a/oracles/black-box-oracles/pom.xml b/oracles/black-box-oracles/pom.xml deleted file mode 100644 index fb597fe678..0000000000 --- a/oracles/black-box-oracles/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - learnlib-oracles-parent - de.learnlib - 0.14.0-SNAPSHOT - ../pom.xml - - 4.0.0 - - learnlib-black-box-oracles - LearnLib :: Oracles :: Black-Box Oracles - A collection of black-box oracles - - - de.learnlib - learnlib-api - - - org.mockito - mockito-core - test - - - com.google.code.findbugs - jsr305 - - - net.automatalib - automata-core - - - net.automatalib - automata-api - - - junit - junit - test - - - \ No newline at end of file diff --git a/oracles/filters/cache/pom.xml b/oracles/filters/cache/pom.xml index 09ebe3cc41..17a4b348ba 100644 --- a/oracles/filters/cache/pom.xml +++ b/oracles/filters/cache/pom.xml @@ -85,10 +85,6 @@ limitations under the License. - - de.learnlib.testsupport - learnlib-learning-examples - de.learnlib learnlib-statistics diff --git a/oracles/inclusion-oracles/pom.xml b/oracles/inclusion-oracles/pom.xml deleted file mode 100644 index 77e5ebcabc..0000000000 --- a/oracles/inclusion-oracles/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - learnlib-oracles-parent - de.learnlib - 0.14.0-SNAPSHOT - ../pom.xml - - 4.0.0 - - learnlib-inclusion-oracles - LearnLib :: Oracles :: Inclusion Oracles - A collection of language inclusion oracles - - - de.learnlib - learnlib-api - - - net.automatalib - automata-api - - - de.learnlib - learnlib-util - - - org.mockito - mockito-core - test - - - junit - junit - test - - - de.learnlib.testsupport - learnlib-oracle-support - test - - - de.learnlib.testsupport - learnlib-learning-examples - - - - \ No newline at end of file diff --git a/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java index 9e6b92c9b2..2e4b19a2da 100644 --- a/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java +++ b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java @@ -47,13 +47,13 @@ public void testDFASimulatorOmegaOracle() { List> queries = new ArrayList<>(); OmegaQuery q1 = new OmegaQuery<>(Word.fromSymbols(ExamplePaulAndMary.IN_PAUL, - ExamplePaulAndMary.IN_LOVES, - ExamplePaulAndMary.IN_MARY), - new HashSet<>(Arrays.asList(new Integer[] {0, 1, 2, 3}))); + ExamplePaulAndMary.IN_LOVES, + ExamplePaulAndMary.IN_MARY), + new HashSet<>(Arrays.asList(0, 1, 2, 3))); OmegaQuery q2 = new OmegaQuery<>(Word.fromSymbols(ExamplePaulAndMary.IN_MARY, - ExamplePaulAndMary.IN_LOVES, - ExamplePaulAndMary.IN_PAUL), - new HashSet<>(Arrays.asList(new Integer[] {0, 1, 2, 3}))); + ExamplePaulAndMary.IN_LOVES, + ExamplePaulAndMary.IN_PAUL), + new HashSet<>(Arrays.asList(0, 1, 2, 3))); queries.add(q1); queries.add(q2); @@ -66,10 +66,10 @@ public void testDFASimulatorOmegaOracle() { // Paul loves Mary... Assert.assertEquals(queries.get(0).getOutput(), Boolean.TRUE); - Assert.assertEquals(queries.get(0).getStates(), Arrays.asList(new Integer[] {0, 1, 3, 4})); + Assert.assertEquals(queries.get(0).getStates(), Arrays.asList(0, 1, 3, 4)); // ... but Mary does not love Paul :-( Assert.assertEquals(queries.get(1).getOutput(), Boolean.FALSE); - Assert.assertEquals(queries.get(1).getStates(), Arrays.asList(new Integer[] {0, 2, 2, 2})); + Assert.assertEquals(queries.get(1).getStates(), Arrays.asList(0, 2, 2, 2)); } } diff --git a/oracles/pom.xml b/oracles/pom.xml index 5d52321d45..8110774d47 100644 --- a/oracles/pom.xml +++ b/oracles/pom.xml @@ -33,13 +33,11 @@ limitations under the License. pom + bbc-oracles filters membership-oracles equivalence-oracles parallelism - emptiness-oracles - inclusion-oracles - black-box-oracles \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8615514da6..7395de3174 100644 --- a/pom.xml +++ b/pom.xml @@ -120,8 +120,9 @@ limitations under the License. Developer (inactive) - - meijuh + + + Jeroen Meijer j.j.g.meijer@utwente.nl University of Twente, Formal Methods and Tools @@ -129,8 +130,8 @@ limitations under the License. Developer - - + + - 3.6 0.8.0-SNAPSHOT 0.1 8.1 3.0.2 22.0 - 4.12 1.2.3 2.0.59-beta 1.7.25 @@ -1012,10 +1011,18 @@ limitations under the License. - + + + + + + de.learnlib + learnlib-model-checkers + ${project.version} @@ -1025,6 +1032,11 @@ limitations under the License. ${project.version} pom + + de.learnlib + learnlib-bbc-oracles + ${project.version} + de.learnlib learnlib-equivalence-oracles @@ -1060,28 +1072,6 @@ limitations under the License. learnlib-parallelism ${project.version} - - de.learnlib - learnlib-black-box-oracles - ${project.version} - - - de.learnlib - learnlib-emptiness-oracles - ${project.version} - - - de.learnlib - learnlib-inclusion-oracles - ${project.version} - - - - - de.learnlib - learnlib-model-checkers - ${project.version} - @@ -1094,16 +1084,11 @@ limitations under the License. de.learnlib.testsupport learnlib-learning-examples ${project.version} - - - de.learnlib.testsupport - learnlib-learner-it-support - ${project.version} test de.learnlib.testsupport - learnlib-oracle-support + learnlib-learner-it-support ${project.version} test @@ -1130,12 +1115,6 @@ limitations under the License. ${mockito.version} test - - junit - junit - ${junit.version} - - @@ -1144,12 +1123,6 @@ limitations under the License. ${guava.version} - - org.apache.commons - commons-lang3 - ${apache-commons.version} - - com.google.code.findbugs diff --git a/test-support/learnlib-oracles-support/pom.xml b/test-support/learnlib-oracles-support/pom.xml deleted file mode 100644 index 44284f2e03..0000000000 --- a/test-support/learnlib-oracles-support/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - learnlib-test-support-parent - de.learnlib.testsupport - 0.14.0-SNAPSHOT - ../pom.xml - - 4.0.0 - - learnlib-oracle-support - LearnLib :: Test Support :: Oracles - Support classes for writing tests for oracles - - - de.learnlib - learnlib-util - - - junit - junit - - - net.automatalib - automata-api - - - de.learnlib - learnlib-api - - - jar - - \ No newline at end of file diff --git a/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AutomatonOracleTest.java b/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AutomatonOracleTest.java deleted file mode 100644 index d885c4cc2a..0000000000 --- a/test-support/learnlib-oracles-support/src/main/java/de/learnlib/util/AutomatonOracleTest.java +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.util; - -import de.learnlib.api.oracle.AutomatonOracle; -import net.automatalib.ts.simple.SimpleDTS; - -public interface AutomatonOracleTest, I> { - - AutomatonOracle createAutomatonOracle(int maxWords); -} diff --git a/test-support/pom.xml b/test-support/pom.xml index 4fe8fbe33f..9b06f82d68 100644 --- a/test-support/pom.xml +++ b/test-support/pom.xml @@ -34,7 +34,6 @@ limitations under the License. learning-examples learner-it-support - learnlib-oracles-support From 85862c264645f43e43b8f0742e4c6551a8931389 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 26 Feb 2018 13:46:22 +0100 Subject: [PATCH 020/125] re-order pom.xmls in preparation for tidy-pom plugin --- algorithms/active/adt/pom.xml | 5 +- algorithms/active/dhc/pom.xml | 5 +- .../active/discrimination-tree-vpda/pom.xml | 4 +- algorithms/active/discrimination-tree/pom.xml | 4 +- algorithms/active/kearns-vazirani/pom.xml | 5 +- algorithms/active/lstar/pom.xml | 5 +- algorithms/active/nlstar/pom.xml | 7 +- algorithms/active/pom.xml | 10 +- algorithms/active/ttt-vpda/pom.xml | 5 +- algorithms/active/ttt/pom.xml | 5 +- algorithms/passive/pom.xml | 10 +- algorithms/passive/rpni-edsm/pom.xml | 5 +- algorithms/passive/rpni-mdl/pom.xml | 5 +- algorithms/passive/rpni/pom.xml | 5 +- algorithms/pom.xml | 10 +- api/pom.xml | 3 +- archetypes/basic/pom.xml | 14 +- archetypes/complete/pom.xml | 13 +- archetypes/pom.xml | 44 +- build-parent/pom.xml | 76 +- build-tools/pom.xml | 5 +- commons/acex/pom.xml | 4 +- commons/counterexamples/pom.xml | 4 +- commons/pom.xml | 9 +- commons/settings/pom.xml | 4 +- commons/util/pom.xml | 4 +- datastructures/discrimination-tree/pom.xml | 4 +- datastructures/list/pom.xml | 5 +- datastructures/observation-table/pom.xml | 5 +- datastructures/pom.xml | 10 +- datastructures/pta/pom.xml | 5 +- distribution/pom.xml | 6 +- drivers/basic/pom.xml | 5 +- drivers/mapper/pom.xml | 1 + drivers/pom.xml | 9 +- drivers/simulator/pom.xml | 5 +- examples/pom.xml | 50 +- model-checkers/pom.xml | 11 +- oracles/bbc-oracles/pom.xml | 13 +- oracles/equivalence-oracles/pom.xml | 4 +- oracles/filters/cache/pom.xml | 5 +- oracles/filters/pom.xml | 9 +- oracles/filters/reuse/pom.xml | 10 +- oracles/filters/statistics/pom.xml | 10 +- oracles/membership-oracles/pom.xml | 4 +- oracles/parallelism/pom.xml | 4 +- oracles/pom.xml | 10 +- pom.xml | 1486 ++++++++--------- test-support/learner-it-support/pom.xml | 12 +- test-support/learning-examples/pom.xml | 6 +- test-support/pom.xml | 6 +- 51 files changed, 966 insertions(+), 999 deletions(-) diff --git a/algorithms/active/adt/pom.xml b/algorithms/active/adt/pom.xml index 56dd91b1fc..bfa40acc2d 100644 --- a/algorithms/active/adt/pom.xml +++ b/algorithms/active/adt/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-active-parent de.learnlib + learnlib-algorithms-active-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-adt + LearnLib :: Algorithms :: ADT The ADT Algorithm. Uses adaptive distinguishing trees (a generalization of adaptive distinguishing sequences) to @@ -109,5 +109,4 @@ limitations under the License. test - diff --git a/algorithms/active/dhc/pom.xml b/algorithms/active/dhc/pom.xml index 71931ab90d..17fa04c7cb 100644 --- a/algorithms/active/dhc/pom.xml +++ b/algorithms/active/dhc/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-active-parent de.learnlib + learnlib-algorithms-active-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-dhc + LearnLib :: Algorithms :: DHC The Direct Hypothesis Construction algorithm for active learning of Mealy machines @@ -110,5 +110,4 @@ limitations under the License. buildergen - diff --git a/algorithms/active/discrimination-tree-vpda/pom.xml b/algorithms/active/discrimination-tree-vpda/pom.xml index d9dae35f3d..bf9149aabe 100644 --- a/algorithms/active/discrimination-tree-vpda/pom.xml +++ b/algorithms/active/discrimination-tree-vpda/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-active-parent de.learnlib + learnlib-algorithms-active-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-discrimination-tree-vpda + LearnLib :: Algorithms :: Discrimination Tree [VPDA] A learning algorithm, which distinguishes hypothesis states using a discrimination tree (visibly push-down diff --git a/algorithms/active/discrimination-tree/pom.xml b/algorithms/active/discrimination-tree/pom.xml index b52cbdbaea..9245ffcca4 100644 --- a/algorithms/active/discrimination-tree/pom.xml +++ b/algorithms/active/discrimination-tree/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-active-parent de.learnlib + learnlib-algorithms-active-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-discrimination-tree + LearnLib :: Algorithms :: Discrimination Tree A learning algorithm, which distinguishes hypothesis states using a discrimination tree. diff --git a/algorithms/active/kearns-vazirani/pom.xml b/algorithms/active/kearns-vazirani/pom.xml index 800b2ca51b..1550c01c39 100644 --- a/algorithms/active/kearns-vazirani/pom.xml +++ b/algorithms/active/kearns-vazirani/pom.xml @@ -17,13 +17,16 @@ limitations under the License. --> 4.0.0 + de.learnlib learnlib-algorithms-active-parent 0.14.0-SNAPSHOT ../pom.xml + learnlib-kearns-vazirani + LearnLib :: Algorithms :: Kearns/Vazirani The automata learning algorithm described by Kearns & Vazirani @@ -69,4 +72,4 @@ limitations under the License. buildergen - \ No newline at end of file + diff --git a/algorithms/active/lstar/pom.xml b/algorithms/active/lstar/pom.xml index 92d7a4c3be..23154428a2 100644 --- a/algorithms/active/lstar/pom.xml +++ b/algorithms/active/lstar/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-active-parent de.learnlib + learnlib-algorithms-active-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-lstar + LearnLib :: Algorithms :: L* A flexible, optimized version of Dana Angluin's L* algorithm. This module provides access to the original version of L*, extensions for Mealy machines, and variants with enhanced counterexample analysis (as @@ -110,5 +110,4 @@ limitations under the License. test - diff --git a/algorithms/active/nlstar/pom.xml b/algorithms/active/nlstar/pom.xml index 7eb5b0b6ac..769f65c82a 100644 --- a/algorithms/active/nlstar/pom.xml +++ b/algorithms/active/nlstar/pom.xml @@ -17,13 +17,16 @@ limitations under the License. --> 4.0.0 + de.learnlib learnlib-algorithms-active-parent 0.14.0-SNAPSHOT - LearnLib :: Algorithms :: NL* + learnlib-nlstar + + LearnLib :: Algorithms :: NL* A variant of the L* algorithm for inferring non-deterministic hypothesis automata. @@ -68,4 +71,4 @@ limitations under the License. test - \ No newline at end of file + diff --git a/algorithms/active/pom.xml b/algorithms/active/pom.xml index cf889b6310..a440c12b41 100644 --- a/algorithms/active/pom.xml +++ b/algorithms/active/pom.xml @@ -16,22 +16,21 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-parent de.learnlib + learnlib-algorithms-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-algorithms-active-parent + pom + LearnLib :: Algorithms :: Active Parent module for (active) automata learning algorithms shipped with LearnLib - pom - adt dhc @@ -43,5 +42,4 @@ limitations under the License. ttt ttt-vpda - - \ No newline at end of file + diff --git a/algorithms/active/ttt-vpda/pom.xml b/algorithms/active/ttt-vpda/pom.xml index 7fd4d97cf1..e16dcafc1f 100644 --- a/algorithms/active/ttt-vpda/pom.xml +++ b/algorithms/active/ttt-vpda/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-active-parent de.learnlib + learnlib-algorithms-active-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-ttt-vpda + LearnLib :: Algorithms :: TTT [VPDA] The TTT Algorithm (visibly push-down automata variant) @@ -93,5 +93,4 @@ limitations under the License. learnlib-learner-it-support - diff --git a/algorithms/active/ttt/pom.xml b/algorithms/active/ttt/pom.xml index 1fca80b87a..39a82feacb 100644 --- a/algorithms/active/ttt/pom.xml +++ b/algorithms/active/ttt/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-active-parent de.learnlib + learnlib-algorithms-active-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-ttt + LearnLib :: Algorithms :: TTT The TTT Algorithm @@ -112,5 +112,4 @@ limitations under the License. buildergen - diff --git a/algorithms/passive/pom.xml b/algorithms/passive/pom.xml index c78365241e..c8b71a70a3 100644 --- a/algorithms/passive/pom.xml +++ b/algorithms/passive/pom.xml @@ -16,26 +16,24 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-parent de.learnlib + learnlib-algorithms-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-algorithms-passive-parent + pom + LearnLib :: Algorithms :: Passive Parent module for (passive) automata learning algorithms shipped with LearnLib - pom - rpni rpni-edsm rpni-mdl - - \ No newline at end of file + diff --git a/algorithms/passive/rpni-edsm/pom.xml b/algorithms/passive/rpni-edsm/pom.xml index 02211093c5..6664a28e8c 100644 --- a/algorithms/passive/rpni-edsm/pom.xml +++ b/algorithms/passive/rpni-edsm/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-passive-parent de.learnlib + learnlib-algorithms-passive-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-rpni-edsm + LearnLib :: Algorithms :: EDSM The EDSM passive learning algorithm @@ -89,5 +89,4 @@ limitations under the License. test - diff --git a/algorithms/passive/rpni-mdl/pom.xml b/algorithms/passive/rpni-mdl/pom.xml index dbe0dabd22..0e19a2ee0a 100644 --- a/algorithms/passive/rpni-mdl/pom.xml +++ b/algorithms/passive/rpni-mdl/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-passive-parent de.learnlib + learnlib-algorithms-passive-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-rpni-mdl + LearnLib :: Algorithms :: MDL The MDL passive learning algorithm @@ -83,5 +83,4 @@ limitations under the License. test - diff --git a/algorithms/passive/rpni/pom.xml b/algorithms/passive/rpni/pom.xml index 2169872f7d..25f0380df5 100644 --- a/algorithms/passive/rpni/pom.xml +++ b/algorithms/passive/rpni/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-algorithms-passive-parent de.learnlib + learnlib-algorithms-passive-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-rpni + LearnLib :: Algorithms :: RPNI The RPNI passive learning algorithm @@ -88,5 +88,4 @@ limitations under the License. buildergen - diff --git a/algorithms/pom.xml b/algorithms/pom.xml index 4876fe6039..d0040deac1 100644 --- a/algorithms/pom.xml +++ b/algorithms/pom.xml @@ -16,25 +16,23 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-build-parent de.learnlib + learnlib-build-parent 0.14.0-SNAPSHOT ../build-parent/pom.xml learnlib-algorithms-parent + pom + LearnLib :: Algorithms Parent module for automata learning algorithms shipped with LearnLib - pom - active passive - - \ No newline at end of file + diff --git a/api/pom.xml b/api/pom.xml index efd128b987..94a424bfdf 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -26,10 +26,10 @@ limitations under the License. learnlib-api + LearnLib :: API Infrastructure and core interfaces of LearnLib - @@ -41,6 +41,4 @@ limitations under the License. test - - diff --git a/archetypes/complete/pom.xml b/archetypes/complete/pom.xml index b508dca3a2..ce6bdbb3e7 100644 --- a/archetypes/complete/pom.xml +++ b/archetypes/complete/pom.xml @@ -18,12 +18,6 @@ limitations under the License. 4.0.0 - complete - maven-archetype - - LearnLib :: Archetypes :: Complete - Archetype which includes all LearnLib dependencies - de.learnlib.archetypes learnlib-archetypes-parent @@ -31,6 +25,12 @@ limitations under the License. ../pom.xml + complete + maven-archetype + + LearnLib :: Archetypes :: Complete + Archetype which includes all LearnLib dependencies + @@ -42,4 +42,3 @@ limitations under the License. - diff --git a/archetypes/pom.xml b/archetypes/pom.xml index b26a55119d..0924c6966e 100644 --- a/archetypes/pom.xml +++ b/archetypes/pom.xml @@ -18,13 +18,6 @@ limitations under the License. 4.0.0 - de.learnlib.archetypes - learnlib-archetypes-parent - pom - - LearnLib :: Archetypes - Parent metaproject for archetypes that facilitate getting started with LearnLib. - de.learnlib learnlib-build-parent @@ -32,28 +25,26 @@ limitations under the License. ../build-parent/pom.xml + de.learnlib.archetypes + learnlib-archetypes-parent + pom + + LearnLib :: Archetypes + Parent metaproject for archetypes that facilitate getting started with LearnLib. + basic complete - - - org.apache.maven.archetype - archetype-packaging - ${archetype-plugin.version} - - - - - + src/main/resources false @@ -73,7 +64,6 @@ limitations under the License. true - @@ -82,6 +72,12 @@ limitations under the License. + + + org.apache.maven.archetype + archetype-packaging + ${archetype-plugin.version} + + - diff --git a/build-parent/pom.xml b/build-parent/pom.xml index f8b12b7a66..cf924da1e9 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -18,6 +18,13 @@ limitations under the License. 4.0.0 + + de.learnlib + learnlib-parent + 0.14.0-SNAPSHOT + ../pom.xml + + learnlib-build-parent pom @@ -27,12 +34,37 @@ limitations under the License. dependencies on the "build-tools" artifact without introducing cyclic dependencies with the general parent. - - de.learnlib - learnlib-parent - 0.14.0-SNAPSHOT - ../pom.xml - + + + + + + org.jacoco + jacoco-maven-plugin + + + + **/ADTLearnerBuilder.class + **/MealyDHCBuilder.class + **/DTLearner*Builder.class + **/DTLearnerVPDABuilder.class + **/KearnsVazirani*Builder.class + **/ClassicLStar*Builder.class + **/ExtensibleLStar*Builder.class + **/MalerPnueli*Builder.class + **/RivestSchapire*Builder.class + **/NLStarLearnerBuilder.class + **/TTTLearner*Builder.class + **/TTTLearnerVPDABuilder.class + **/LTSminLTLAlternatingBuilder.class + **/LTSminLTLDFABuilder.class + **/LTSminLTLIOBuilder.class + + + + + + @@ -165,36 +197,4 @@ limitations under the License. - - - - - - - org.jacoco - jacoco-maven-plugin - - - - **/ADTLearnerBuilder.class - **/MealyDHCBuilder.class - **/DTLearner*Builder.class - **/DTLearnerVPDABuilder.class - **/KearnsVazirani*Builder.class - **/ClassicLStar*Builder.class - **/ExtensibleLStar*Builder.class - **/MalerPnueli*Builder.class - **/RivestSchapire*Builder.class - **/NLStarLearnerBuilder.class - **/TTTLearner*Builder.class - **/TTTLearnerVPDABuilder.class - **/LTSminLTLAlternatingBuilder.class - **/LTSminLTLDFABuilder.class - **/LTSminLTLIOBuilder.class - - - - - - diff --git a/build-tools/pom.xml b/build-tools/pom.xml index 6a4abd3d22..8518fb2e41 100644 --- a/build-tools/pom.xml +++ b/build-tools/pom.xml @@ -16,18 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-parent de.learnlib + learnlib-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-build-tools + LearnLib :: Build Tools Tools and resources required for building LearnLib - diff --git a/commons/acex/pom.xml b/commons/acex/pom.xml index 8df9b6e957..fa39f4a219 100644 --- a/commons/acex/pom.xml +++ b/commons/acex/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-commons-parent de.learnlib + learnlib-commons-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-acex + LearnLib :: Commons :: Abstract Counterexamples An abstract counterexample analysis framework diff --git a/commons/counterexamples/pom.xml b/commons/counterexamples/pom.xml index 3be4ee4653..cd4492a200 100644 --- a/commons/counterexamples/pom.xml +++ b/commons/counterexamples/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-commons-parent de.learnlib + learnlib-commons-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-counterexamples + LearnLib :: Commons :: Counterexamples A collection of standard algorithms for handling counterexamples in automata learning diff --git a/commons/pom.xml b/commons/pom.xml index bd3f3d4ece..047ea6c184 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -16,26 +16,25 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-build-parent de.learnlib + learnlib-build-parent 0.14.0-SNAPSHOT ../build-parent/pom.xml learnlib-commons-parent + pom + LearnLib :: Commons Parent module for common LearnLib utilities - pom - acex counterexamples settings util - \ No newline at end of file + diff --git a/commons/settings/pom.xml b/commons/settings/pom.xml index 53c392787d..d0e41bbd78 100644 --- a/commons/settings/pom.xml +++ b/commons/settings/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-commons-parent de.learnlib + learnlib-commons-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-settings + LearnLib :: Commons :: Settings A collection of utility methods to parse LearnLib specific settings diff --git a/commons/util/pom.xml b/commons/util/pom.xml index 426612dede..a7f6895304 100644 --- a/commons/util/pom.xml +++ b/commons/util/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-commons-parent de.learnlib + learnlib-commons-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-util + LearnLib :: Commons :: Util A collection of utility methods for learning setups (oracle wrappers, etc.) diff --git a/datastructures/discrimination-tree/pom.xml b/datastructures/discrimination-tree/pom.xml index 0b8205a47d..a85340eb63 100644 --- a/datastructures/discrimination-tree/pom.xml +++ b/datastructures/discrimination-tree/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-datastructures-parent de.learnlib + learnlib-datastructures-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-datastructure-dt + LearnLib :: Datastructures :: Discrimination Tree Data- and utility classes for Discrimination Trees diff --git a/datastructures/list/pom.xml b/datastructures/list/pom.xml index a1d29de12c..134cf577b7 100644 --- a/datastructures/list/pom.xml +++ b/datastructures/list/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-datastructures-parent de.learnlib + learnlib-datastructures-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-datastructure-list + LearnLib :: Datastructures :: List Data- and utility classes for Lists @@ -40,5 +40,4 @@ limitations under the License. guava - diff --git a/datastructures/observation-table/pom.xml b/datastructures/observation-table/pom.xml index 1d4f61986f..12d46e4756 100644 --- a/datastructures/observation-table/pom.xml +++ b/datastructures/observation-table/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-datastructures-parent de.learnlib + learnlib-datastructures-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-datastructure-ot + LearnLib :: Datastructures :: Observationtable Data- and utility classes for Observation Tables @@ -74,5 +74,4 @@ limitations under the License. testng - diff --git a/datastructures/pom.xml b/datastructures/pom.xml index 145fd35bd2..5d9b2c201f 100644 --- a/datastructures/pom.xml +++ b/datastructures/pom.xml @@ -16,27 +16,25 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-build-parent de.learnlib + learnlib-build-parent 0.14.0-SNAPSHOT ../build-parent/pom.xml learnlib-datastructures-parent + pom + LearnLib :: Datastructures Parent module for data structures shared across multiple modules of LearnLib - pom - discrimination-tree list observation-table pta - - \ No newline at end of file + diff --git a/datastructures/pta/pom.xml b/datastructures/pta/pom.xml index 7ef320714d..b5be740f69 100644 --- a/datastructures/pta/pom.xml +++ b/datastructures/pta/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-datastructures-parent de.learnlib + learnlib-datastructures-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-datastructure-pta + LearnLib :: Datastructures :: PTA Data- and utility classes for Prefix-Tree-Acceptors @@ -70,5 +70,4 @@ limitations under the License. testng - diff --git a/distribution/pom.xml b/distribution/pom.xml index 607d19c99a..a743397388 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -17,6 +17,7 @@ limitations under the License. --> 4.0.0 + de.learnlib learnlib-build-parent @@ -27,15 +28,14 @@ limitations under the License. de.learnlib.distribution learnlib-distribution pom - LearnLib :: Distribution + LearnLib :: Distribution An artifact that aggregates all other artifacts of LearnLib to produce an Uber-JAR that can be used in non-maven environments. Likewise, this single artifact may be used in maven-aware environments to declare a dependency on all LearnLib artifacts. - - 4.0.0 - learnlib-drivers-parent de.learnlib + learnlib-drivers-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-drivers-basic + LearnLib :: Drivers :: Basic Basic Test Driver Generation Support @@ -75,5 +75,4 @@ limitations under the License. learnlib-mapper - diff --git a/drivers/mapper/pom.xml b/drivers/mapper/pom.xml index 63cc459828..4f50085642 100644 --- a/drivers/mapper/pom.xml +++ b/drivers/mapper/pom.xml @@ -17,6 +17,7 @@ limitations under the License. --> 4.0.0 + de.learnlib learnlib-drivers-parent diff --git a/drivers/pom.xml b/drivers/pom.xml index 2fb03abdfa..846a52d11f 100644 --- a/drivers/pom.xml +++ b/drivers/pom.xml @@ -16,25 +16,24 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-build-parent de.learnlib + learnlib-build-parent 0.14.0-SNAPSHOT ../build-parent/pom.xml learnlib-drivers-parent + pom + LearnLib :: Drivers Parent module for test drivers - pom - basic mapper simulator - \ No newline at end of file + diff --git a/drivers/simulator/pom.xml b/drivers/simulator/pom.xml index 7c0774298e..8878b1cb21 100644 --- a/drivers/simulator/pom.xml +++ b/drivers/simulator/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-drivers-parent de.learnlib + learnlib-drivers-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-drivers-simulator + LearnLib :: Drivers :: Simulator Utilities for simulating SULs @@ -46,5 +46,4 @@ limitations under the License. automata-api - diff --git a/examples/pom.xml b/examples/pom.xml index 8800181212..465bc30715 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-build-parent de.learnlib + learnlib-build-parent 0.14.0-SNAPSHOT ../build-parent/pom.xml learnlib-examples + LearnLib :: Examples A collection of various small example applications that illustrate several use cases of LearnLib. @@ -34,28 +34,6 @@ limitations under the License. deployed for this module. - - - - - org.jacoco - jacoco-maven-plugin - - true - - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - - - + compile + @@ -153,4 +132,25 @@ limitations under the License. runtime + + + + + + org.jacoco + jacoco-maven-plugin + + true + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + diff --git a/model-checkers/pom.xml b/model-checkers/pom.xml index 99e89d85cd..1457c70378 100644 --- a/model-checkers/pom.xml +++ b/model-checkers/pom.xml @@ -15,22 +15,21 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> - - + 4.0.0 - learnlib-build-parent de.learnlib + learnlib-build-parent 0.14.0-SNAPSHOT ../build-parent/pom.xml learnlib-model-checkers + LearnLib :: Model Checkers Module for model checkers + de.learnlib @@ -77,4 +76,4 @@ limitations under the License. learnlib-settings - \ No newline at end of file + diff --git a/oracles/bbc-oracles/pom.xml b/oracles/bbc-oracles/pom.xml index 251ed5890f..28b2d017aa 100644 --- a/oracles/bbc-oracles/pom.xml +++ b/oracles/bbc-oracles/pom.xml @@ -15,23 +15,24 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> - + + 4.0.0 + - learnlib-oracles-parent de.learnlib + learnlib-oracles-parent 0.14.0-SNAPSHOT ../pom.xml - 4.0.0 learnlib-bbc-oracles + LearnLib :: Oracles :: BBC Oracles A collection of oracles required for block-box checking. Includes black-box, emptiness and language inclusion oracles + de.learnlib @@ -66,4 +67,4 @@ limitations under the License. testng - \ No newline at end of file + diff --git a/oracles/equivalence-oracles/pom.xml b/oracles/equivalence-oracles/pom.xml index 8505a4d7b7..f3397f5977 100644 --- a/oracles/equivalence-oracles/pom.xml +++ b/oracles/equivalence-oracles/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-oracles-parent de.learnlib + learnlib-oracles-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-equivalence-oracles + LearnLib :: Oracles :: Equivalence Oracles A collection of equivalence oracles diff --git a/oracles/filters/cache/pom.xml b/oracles/filters/cache/pom.xml index 17a4b348ba..d3a6318b63 100644 --- a/oracles/filters/cache/pom.xml +++ b/oracles/filters/cache/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-filters-parent de.learnlib + learnlib-filters-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-cache + LearnLib :: Filters :: Cache Caches to avoid posing duplicate membership queries @@ -96,5 +96,4 @@ limitations under the License. test - diff --git a/oracles/filters/pom.xml b/oracles/filters/pom.xml index 1807460dad..85d8038d12 100644 --- a/oracles/filters/pom.xml +++ b/oracles/filters/pom.xml @@ -16,25 +16,24 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-oracles-parent de.learnlib + learnlib-oracles-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-filters-parent + pom + LearnLib :: Filters Parent module for components that can be inserted in a chain of oracles - pom - cache reuse statistics - \ No newline at end of file + diff --git a/oracles/filters/reuse/pom.xml b/oracles/filters/reuse/pom.xml index e90cfac27b..164c32fb65 100644 --- a/oracles/filters/reuse/pom.xml +++ b/oracles/filters/reuse/pom.xml @@ -16,19 +16,20 @@ See the License for the specific language governing permissions and limitations under the License. --> + 4.0.0 + - learnlib-filters-parent de.learnlib + learnlib-filters-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-reuse + LearnLib :: Filters :: Reuse Reuse Tree for (intelligently) caching membership queries - 4.0.0 - ${project.groupId} @@ -64,5 +65,4 @@ limitations under the License. test - - \ No newline at end of file + diff --git a/oracles/filters/statistics/pom.xml b/oracles/filters/statistics/pom.xml index 6105c37d0a..4232e04d7b 100644 --- a/oracles/filters/statistics/pom.xml +++ b/oracles/filters/statistics/pom.xml @@ -16,19 +16,20 @@ See the License for the specific language governing permissions and limitations under the License. --> + 4.0.0 + - learnlib-filters-parent de.learnlib + learnlib-filters-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-statistics + LearnLib :: Filters :: Statistics Filters for collecting statistical data - 4.0.0 - ${project.groupId} @@ -51,5 +52,4 @@ limitations under the License. test - - \ No newline at end of file + diff --git a/oracles/membership-oracles/pom.xml b/oracles/membership-oracles/pom.xml index b60f2bb1e9..75d649fc15 100644 --- a/oracles/membership-oracles/pom.xml +++ b/oracles/membership-oracles/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-oracles-parent de.learnlib + learnlib-oracles-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-membership-oracles + LearnLib :: Oracles :: Membership Oracles A collection of membership oracles diff --git a/oracles/parallelism/pom.xml b/oracles/parallelism/pom.xml index 26ba5dce9d..37665a6557 100644 --- a/oracles/parallelism/pom.xml +++ b/oracles/parallelism/pom.xml @@ -16,17 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-oracles-parent de.learnlib + learnlib-oracles-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-parallelism + LearnLib :: Oracles :: Parallelism Support for parallelizing membership queries diff --git a/oracles/pom.xml b/oracles/pom.xml index 8110774d47..18f0316f39 100644 --- a/oracles/pom.xml +++ b/oracles/pom.xml @@ -16,22 +16,21 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - learnlib-build-parent de.learnlib + learnlib-build-parent 0.14.0-SNAPSHOT ../build-parent/pom.xml learnlib-oracles-parent + pom + LearnLib :: Oracles Parent module for oracles and oracle-related modules - pom - bbc-oracles filters @@ -39,5 +38,4 @@ limitations under the License. equivalence-oracles parallelism - - \ No newline at end of file + diff --git a/pom.xml b/pom.xml index 7395de3174..e6efbe90da 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - 4.0.0 - - scm:git:git@github.com:LearnLib/learnlib.git - scm:git:git@github.com:LearnLib/learnlib.git - https://github.com/LearnLib/learnlib/tree/develop - HEAD - + + + Q&A List + learnlib-qa+subscribe@googlegroups.com + learnlib-qa+unsubscribe@googlegroups.com + learnlib-qa@googlegroups.com + https://groups.google.com/d/forum/learnlib-qa + + + Discussion List + learnlib-discussion+subscribe@googlegroups.com + learnlib-discussion+unsubscribe@googlegroups.com + learnlib-discussion@googlegroups.com + https://groups.google.com/d/forum/learnlib-discussion + + + Developers List + learnlib-internal+subscribe@googlegroups.com + learnlib-internal+unsubscribe@googlegroups.com + learnlib-internal@googlegroups.com + https://groups.google.com/d/forum/learnlib-internal + + + + scm:git:git@github.com:LearnLib/learnlib.git + scm:git:git@github.com:LearnLib/learnlib.git + https://github.com/LearnLib/learnlib/tree/develop + HEAD + + + https://github.com/LearnLib/learnlib/issues + GitHub Issues + + + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + + + local + file://${user.home}/learnlib-site + + + @@ -216,697 +233,118 @@ limitations under the License. http://google.github.io/guava/releases/${guava.version}/api/docs/ - - - - - - org.apache.maven.plugins - maven-dependency-plugin - ${dependency-plugin.version} - - - org.apache.maven.plugins - maven-checkstyle-plugin - ${checkstyle-plugin.version} - - - org.apache.maven.plugins - maven-pmd-plugin - ${pmd-plugin.version} - - true - false - - target/generated-sources - - - - - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs-plugin.version} - - - org.apache.maven.plugins - maven-site-plugin - ${site-plugin.version} - - - true - - - - org.codehaus.mojo - exec-maven-plugin - ${exec-plugin.version} - - - org.apache.maven.plugins - maven-surefire-plugin - ${surefire-plugin.version} - - true - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${failsafe-plugin.version} - - true - - - - - integration-test - verify - - - - - - org.jacoco - jacoco-maven-plugin - ${jacoco-plugin.version} - - - prepare-report - - prepare-agent - - - - report - test - - report - - - - - report-integration - integration-test - - report - - - - - - org.apache.maven.plugins - maven-assembly-plugin - ${assembly-plugin.version} - - - org.codehaus.mojo - build-helper-maven-plugin - ${buildhelper-plugin.version} - - - org.apache.maven.plugins - maven-release-plugin - ${release-plugin.version} - - - -Dlearnlib.release=true - deploy site site:stage scm-publish:publish-scm - - true - - learnlib-@{version} - - clean install - - - - org.apache.maven.plugins - maven-source-plugin - ${source-plugin.version} - - - org.apache.maven.plugins - maven-javadoc-plugin - ${javadoc-plugin.version} - - true - 1.8 - true - false - - ${java.apidocs} - ${guava.apidocs} - ${automatalib.apidocs} - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - ${info-reports-plugin.version} - - - org.eluder.coveralls - coveralls-maven-plugin - ${coveralls-plugin.version} - - - ${basedir}/distribution/target/site/jacoco-aggregate/jacoco.xml - - - - - org.apache.maven.plugins - maven-antrun-plugin - ${antrun-plugin.version} - - - org.eclipse.m2e - lifecycle-mapping - ${lifecycle-mapping.version} - - - org.apache.maven.plugins - maven-gpg-plugin - ${gpg-plugin.version} - - - org.apache.maven.plugins - maven-enforcer-plugin - ${enforcer-plugin.version} - - - org.apache.maven.plugins - maven-scm-publish-plugin - ${scm-publish-plugin.version} - - - org.apache.maven.plugins - maven-compiler-plugin - ${compiler-plugin.version} - - - -Xlint:all,-options,-path - - - - - + + + + - - - org.apache.maven.plugins - maven-site-plugin - - - attach-descriptor - false - - attach-descriptor - - - - - + + + de.learnlib + learnlib-algorithms-parent + ${project.version} + pom + + + de.learnlib + learnlib-algorithms-active-parent + ${project.version} + pom + + + de.learnlib + learnlib-adt + ${project.version} + + + de.learnlib + learnlib-dhc + ${project.version} + + + de.learnlib + learnlib-discrimination-tree + ${project.version} + + + de.learnlib + learnlib-discrimination-tree-vpda + ${project.version} + + + de.learnlib + learnlib-kearns-vazirani + ${project.version} + + + de.learnlib + learnlib-lstar + ${project.version} + + + de.learnlib + learnlib-nlstar + ${project.version} + + + de.learnlib + learnlib-ttt + ${project.version} + + + de.learnlib + learnlib-ttt-vpda + ${project.version} + + + de.learnlib + learnlib-algorithms-passive-parent + ${project.version} + pom + + + de.learnlib + learnlib-rpni + ${project.version} + + + de.learnlib + learnlib-rpni-edsm + ${project.version} + + + de.learnlib + learnlib-rpni-mdl + ${project.version} + - - - org.apache.maven.wagon - wagon-ssh - 2.6 - - - + + + de.learnlib + learnlib-api + ${project.version} + - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - - - - index - license - project-team - mailing-list - issue-tracking - scm - dependencies - dependency-info - modules - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - true - 1.8 - true - false - - ${java.apidocs} - ${guava.apidocs} - ${automatalib.apidocs} - - - - - non-aggregate - - javadoc - - - - aggregate - false - - aggregate - - - - - - - - - - - - integration-tests - - - learnlib.release - true - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - - - - code-analysis - - - learnlib.release - true - - - - - - org.codehaus.mojo - findbugs-maven-plugin - - - verify - - check - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - analyze - - - analyze-only - - - true - - true - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - verify - - check - - - - - - - - - - code-coverage - - - - org.apache.maven.plugins - maven-antrun-plugin - - - touch-jacoco - generate-test-resources - - run - - - - - - - - - - - org.jacoco - jacoco-maven-plugin - - - - - - netbeans-private-testng - - - netbeans.testng.action - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - target/nb-private/testng-suite.xml - - - - - - - - - eclipse-m2e-configs - - - - m2e.version - - - - - - - - org.eclipse.m2e - lifecycle-mapping - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - [1.0.0,) - - enforce - - - - - - - - - - - - - - - - - bundles - - - learnlib.release - true - - - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - - - - - - sign-artifacts - - - learnlib.release - true - - - - - - org.apache.maven.plugins - maven-gpg-plugin - - - sign-artifacts - verify - - sign - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - - - enforce-maven - - enforce - - - - - (,2.1.0),(2.1.0,2.2.0),(2.2.0,) - Maven 2.1.0 and 2.2.0 produce incorrect GPG signatures and checksums respectively. - - - - - - - - - - - - release - - - learnlib.release - true - - - - - - org.apache.maven.plugins - maven-site-plugin - - - ${session.executionRootDirectory}/target/staging/maven-site/${project.version} - - - - org.apache.maven.plugins - maven-scm-publish-plugin - - ${project.scm.connection} - gh-pages - true - - true - true - true - - - - - - - - - - - - - - - - de.learnlib - learnlib-algorithms-parent - ${project.version} - pom - - - de.learnlib - learnlib-algorithms-active-parent - ${project.version} - pom - - - de.learnlib - learnlib-adt - ${project.version} - - - de.learnlib - learnlib-dhc - ${project.version} - - - de.learnlib - learnlib-discrimination-tree - ${project.version} - - - de.learnlib - learnlib-discrimination-tree-vpda - ${project.version} - - - de.learnlib - learnlib-kearns-vazirani - ${project.version} - - - de.learnlib - learnlib-lstar - ${project.version} - - - de.learnlib - learnlib-nlstar - ${project.version} - - - de.learnlib - learnlib-ttt - ${project.version} - - - de.learnlib - learnlib-ttt-vpda - ${project.version} - - - de.learnlib - learnlib-algorithms-passive-parent - ${project.version} - pom - - - de.learnlib - learnlib-rpni - ${project.version} - - - de.learnlib - learnlib-rpni-edsm - ${project.version} - - - de.learnlib - learnlib-rpni-mdl - ${project.version} - - - - - de.learnlib - learnlib-api - ${project.version} - - - - - de.learnlib.archetypes - learnlib-archetypes-parent - ${project.version} - pom - - - de.learnlib.archetypes - basic - ${project.version} - - - de.learnlib.archetypes - complete - ${project.version} - + + + de.learnlib.archetypes + learnlib-archetypes-parent + ${project.version} + pom + + + de.learnlib.archetypes + basic + ${project.version} + + + de.learnlib.archetypes + complete + ${project.version} + @@ -1157,26 +595,582 @@ limitations under the License. ${logback.version} - - + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${dependency-plugin.version} + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle-plugin.version} + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd-plugin.version} + + true + false + + target/generated-sources + + + + + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs-plugin.version} + + + org.apache.maven.plugins + maven-site-plugin + ${site-plugin.version} + + + true + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-plugin.version} + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire-plugin.version} + + true + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${failsafe-plugin.version} + + true + + + + + integration-test + verify + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-plugin.version} + + + prepare-report + + prepare-agent + + + + report + test + + report + + + + + report-integration + integration-test + + report + + + + + + org.apache.maven.plugins + maven-assembly-plugin + ${assembly-plugin.version} + + + org.codehaus.mojo + build-helper-maven-plugin + ${buildhelper-plugin.version} + + + org.apache.maven.plugins + maven-release-plugin + ${release-plugin.version} + + + -Dlearnlib.release=true + deploy site site:stage scm-publish:publish-scm + + true + + learnlib-@{version} + + clean install + + + + org.apache.maven.plugins + maven-source-plugin + ${source-plugin.version} + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc-plugin.version} + + true + 1.8 + true + false + + ${java.apidocs} + ${guava.apidocs} + ${automatalib.apidocs} + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + ${info-reports-plugin.version} + + + org.eluder.coveralls + coveralls-maven-plugin + ${coveralls-plugin.version} + + + ${basedir}/distribution/target/site/jacoco-aggregate/jacoco.xml + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${antrun-plugin.version} + + + org.eclipse.m2e + lifecycle-mapping + ${lifecycle-mapping.version} + + + org.apache.maven.plugins + maven-gpg-plugin + ${gpg-plugin.version} + + + org.apache.maven.plugins + maven-enforcer-plugin + ${enforcer-plugin.version} + + + org.apache.maven.plugins + maven-scm-publish-plugin + ${scm-publish-plugin.version} + + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler-plugin.version} + + + -Xlint:all,-options,-path + + + + + + + + org.apache.maven.plugins + maven-site-plugin + + + attach-descriptor + false + + attach-descriptor + + + + + + + + org.apache.maven.wagon + wagon-ssh + 2.6 + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + + index + license + project-team + mailing-list + issue-tracking + scm + dependencies + dependency-info + modules + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + true + 1.8 + true + false + + ${java.apidocs} + ${guava.apidocs} + ${automatalib.apidocs} + + + + + non-aggregate + + javadoc + + + + aggregate + false + + aggregate + + + + + + - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - - - local - file://${user.home}/learnlib-site - - + + + + integration-tests + + + learnlib.release + true + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + code-analysis + + + learnlib.release + true + + + + + + org.codehaus.mojo + findbugs-maven-plugin + + + verify + + check + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + analyze + + + analyze-only + + + true + + true + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + verify + + check + + + + + + + + + + code-coverage + + + + org.apache.maven.plugins + maven-antrun-plugin + + + touch-jacoco + generate-test-resources + + run + + + + + + + + + + + org.jacoco + jacoco-maven-plugin + + + + + + netbeans-private-testng + + + netbeans.testng.action + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + target/nb-private/testng-suite.xml + + + + + + + + + eclipse-m2e-configs + + + + m2e.version + + + + + + + + org.eclipse.m2e + lifecycle-mapping + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + [1.0.0,) + + enforce + + + + + + + + + + + + + + + + + bundles + + + learnlib.release + true + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + + + sign-artifacts + + + learnlib.release + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-maven + + enforce + + + + + (,2.1.0),(2.1.0,2.2.0),(2.2.0,) + Maven 2.1.0 and 2.2.0 produce incorrect GPG signatures and checksums respectively. + + + + + + + + + + + + release + + + learnlib.release + true + + + + + + org.apache.maven.plugins + maven-site-plugin + + + ${session.executionRootDirectory}/target/staging/maven-site/${project.version} + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + ${project.scm.connection} + gh-pages + true + + true + true + true + + + + + + diff --git a/test-support/learner-it-support/pom.xml b/test-support/learner-it-support/pom.xml index 441e55b2e6..1473b8d6dc 100644 --- a/test-support/learner-it-support/pom.xml +++ b/test-support/learner-it-support/pom.xml @@ -19,16 +19,17 @@ limitations under the License. 4.0.0 - learnlib-test-support-parent de.learnlib.testsupport + learnlib-test-support-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-learner-it-support + jar + LearnLib :: Test Support :: Learner IT Support Support classes for easily writing integration test cases for learning algorithms - jar @@ -46,7 +47,8 @@ limitations under the License. de.learnlib.testsupport learnlib-learning-examples - compile + compile + de.learnlib @@ -74,8 +76,8 @@ limitations under the License. org.testng testng - compile + compile + - diff --git a/test-support/learning-examples/pom.xml b/test-support/learning-examples/pom.xml index a00cff1f5a..0c64685fcb 100644 --- a/test-support/learning-examples/pom.xml +++ b/test-support/learning-examples/pom.xml @@ -19,16 +19,17 @@ limitations under the License. 4.0.0 - learnlib-test-support-parent de.learnlib.testsupport + learnlib-test-support-parent 0.14.0-SNAPSHOT ../pom.xml learnlib-learning-examples + jar + LearnLib :: Test Support :: Learning Examples Example learning setups, to be used for integration testing - jar 0.8.0-SNAPSHOT From 98c0dd1f11f63758fad04b3860fb15609b9e164b Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 26 Feb 2018 13:52:56 +0100 Subject: [PATCH 022/125] setup tidy-pom plugin --- pom.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pom.xml b/pom.xml index 6ae004e9fd..8efd7c6978 100644 --- a/pom.xml +++ b/pom.xml @@ -214,6 +214,7 @@ limitations under the License. 3.6 3.0.1 2.20 + 1.1.0 0.8.0-SNAPSHOT @@ -796,6 +797,11 @@ limitations under the License. + + org.codehaus.mojo + tidy-maven-plugin + ${tidy-pom.version} + @@ -942,6 +948,19 @@ limitations under the License. + + org.codehaus.mojo + tidy-maven-plugin + + + validate + verify + + check + + + + org.apache.maven.plugins maven-checkstyle-plugin From 9b494d190ac2963950d16584063797ffa5a55daa Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 26 Feb 2018 13:54:57 +0100 Subject: [PATCH 023/125] remove (redundant) plugin executions --- pom.xml | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/pom.xml b/pom.xml index 8efd7c6978..63dca41c42 100644 --- a/pom.xml +++ b/pom.xml @@ -920,9 +920,10 @@ limitations under the License. org.codehaus.mojo - findbugs-maven-plugin + tidy-maven-plugin + validate verify check @@ -948,31 +949,6 @@ limitations under the License. - - org.codehaus.mojo - tidy-maven-plugin - - - validate - verify - - check - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - verify - - check - - - - From 9ff7d40c2ea63ff8bd98e98c392a0c4aeb6241ab Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 26 Feb 2018 17:09:46 +0100 Subject: [PATCH 024/125] fix some code smells --- .../de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java | 2 +- .../de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java | 3 +-- .../java/de/learnlib/oracle/AbstractBreadthFirstOracle.java | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java index 02b874f808..02f94e61d2 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java @@ -103,7 +103,7 @@ private void dfa2ETF(DFA dfa, Collection inputs, File etf // remove all rejecting states final MutableDFA copy = new CompactDFA<>(alphabet, dfa.size()); - AutomatonLowLevelCopy.copy(AutomatonCopyMethod.STATE_BY_STATE, dfa, inputs, copy, s -> dfa.isAccepting(s), (s, i, t) -> true); + AutomatonLowLevelCopy.copy(AutomatonCopyMethod.STATE_BY_STATE, dfa, inputs, copy, dfa::isAccepting, (s, i, t) -> true); DFA2ETFWriter.write(etf, copy, alphabet); } diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java index e0013f910e..72cef64ad8 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java @@ -57,8 +57,7 @@ public LTSminLTLIO(boolean keepFiles, @Override protected CompactMealy fsm2Mealy(File fsm) throws IOException, FSMParseException { - final CompactMealy mealy = FSM2MealyParserIO.parse(fsm, getString2Input(), getString2Output()); - return mealy; + return FSM2MealyParserIO.parse(fsm, getString2Input(), getString2Output()); } @Override diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java index d8647f6204..7710bdc2f0 100644 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java @@ -77,8 +77,7 @@ public int getMaxWords() { */ @Override public Word nextInput() { - final Word input = queue.remove(); - return input; + return queue.remove(); } /** From a8aa240cce17e85df0d1ffa06ec37160e0f1b1c6 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 27 Feb 2018 11:30:36 +0100 Subject: [PATCH 025/125] add ciManagement information to pom --- pom.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 63dca41c42..6105ca08ac 100644 --- a/pom.xml +++ b/pom.xml @@ -159,9 +159,10 @@ limitations under the License. https://github.com/LearnLib/learnlib/issues GitHub Issues - + + Travis + https://travis-ci.org/LearnLib/automatalib + ossrh @@ -843,8 +844,9 @@ limitations under the License. license project-team mailing-list - issue-tracking scm + issue-tracking + cim dependencies dependency-info modules From b73aec8b38467cb94dc5961fac2835e6f45c8eb9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 1 Mar 2018 15:06:57 +0100 Subject: [PATCH 026/125] Rework settings implementation - Aggregate currently used system properties in an enum, which allows to have a central place for managing supported properties (also as a reference for end-users) and to prevent typos in future code. The getProperties() methods have been reworked to only accept keys from this new enum. - Unified/refactored some properties (e.g. the pool_policy has been renamed, pool_size has been unified) - Added a test for correctly parsing file and system properties - Switched to MetaInfServices annotation processor, instead of manually declaring services --- commons/settings/pom.xml | 10 +++ .../de/learnlib/setting/LearnLibProperty.java | 84 +++++++++++++++++++ .../de/learnlib/setting/LearnLibSettings.java | 34 ++++---- ...alPropertiesAutomataLibSettingsSource.java | 2 + .../LearnLibLocalPropertiesSource.java | 2 + ...ibPropertiesAutomataLibSettingsSource.java | 2 + .../sources/LearnLibPropertiesSource.java | 2 + .../LearnLibSystemPropertiesSource.java | 2 + ...earnlib.api.setting.LearnLibSettingsSource | 3 - .../net.automatalib.AutomataLibSettingsSource | 2 - .../setting/LearnLibSettingsTest.java | 65 ++++++++++++++ .../src/test/resources/learnlib.properties | 6 ++ .../main/java/de/learnlib/util/MQUtil.java | 3 +- .../modelchecker/LTSminUtil.java | 10 +-- .../parallelism/DynamicParallelOracle.java | 8 +- .../parallelism/StaticParallelOracle.java | 8 +- 16 files changed, 207 insertions(+), 36 deletions(-) create mode 100644 commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.java delete mode 100644 commons/settings/src/main/resources/META-INF/services/de.learnlib.api.setting.LearnLibSettingsSource delete mode 100644 commons/settings/src/main/resources/META-INF/services/net.automatalib.AutomataLibSettingsSource create mode 100644 commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.java create mode 100644 commons/settings/src/test/resources/learnlib.properties diff --git a/commons/settings/pom.xml b/commons/settings/pom.xml index d0e41bbd78..6ccbc1dcf9 100644 --- a/commons/settings/pom.xml +++ b/commons/settings/pom.xml @@ -56,5 +56,15 @@ limitations under the License. slf4j-api + + org.kohsuke.metainf-services + metainf-services + + + + org.testng + testng + + diff --git a/commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.java b/commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.java new file mode 100644 index 0000000000..7977500901 --- /dev/null +++ b/commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.java @@ -0,0 +1,84 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.setting; + +/** + * An enum of all the system properties currently used by LearnLib. + * + * @author frohme + */ +public enum LearnLibProperty { + + /** + * {@code learnlib.external.ltsmin.path}. + *

+ * Path to the binary folder of the LTSmin installation. + */ + LTSMIN_PATH("external.ltsmin.path"), + + /** + * {@code learnlib.parallel.batch_size.dynamic}. + *

+ * Size of query batches for dynamic parallel oracles. + */ + PARALLEL_BATCH_SIZE_DYNAMIC("parallel.batch_size.dynamic"), + + /** + * {@code learnlib.parallel.batch_size.static}. + *

+ * Minimum size of query batches for static parallel oracles. + */ + PARALLEL_BATCH_SIZE_STATIC("parallel.batch_size.static"), + + /** + * {@code learnlib.parallel.pool_policy}. + *

+ * Pool policy for threads of parallel oracles. + *

+ * See de.learnlib.oracle.parallelism.ParallelOracle#PoolPolicy + */ + PARALLEL_POOL_POLICY("parallel.pool_policy"), + + /** + * {@code learnlib.parallel.pool_size}. + *

+ * Size of thread pools for parallel oracles. + */ + PARALLEL_POOL_SIZE("parallel.pool_size"), + + /** + * {@code learnlib.queries.parallel.threshold}. + *

+ * If batch sizes exceed the specified threshold, they will be processed in parallel. + * (Note: This only covers processing of batches. They are still answered sequentially.) + */ + PARALLEL_QUERIES_THRESHOLD("queries.parallel.threshold"); + + private final String key; + + LearnLibProperty(String key) { + this.key = "learnlib." + key; + } + + /** + * Returns the actual system property key of the property. + * + * @return the system property key of the property. + */ + public String getPropertyKey() { + return this.key; + } +} diff --git a/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java b/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java index 74b803ed52..c9967b9ad0 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java +++ b/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java @@ -37,24 +37,24 @@ public static LearnLibSettings getInstance() { return INSTANCE; } - public String getProperty(String propName, String defaultValue) { - return properties.getProperty("learnlib." + propName, defaultValue); + public String getProperty(LearnLibProperty property, String defaultValue) { + return properties.getProperty(property.getPropertyKey(), defaultValue); } - public String getProperty(String propName) { - return properties.getProperty("learnlib." + propName); + public String getProperty(LearnLibProperty property) { + return properties.getProperty(property.getPropertyKey()); } - public > E getEnumValue(String propName, Class enumClazz, E defaultValue) { - E value = getEnumValue(propName, enumClazz); + public > E getEnumValue(LearnLibProperty property, Class enumClazz, E defaultValue) { + E value = getEnumValue(property, enumClazz); if (value != null) { return value; } return defaultValue; } - public > E getEnumValue(String propName, Class enumClazz) { - String prop = getProperty(propName); + public > E getEnumValue(LearnLibProperty property, Class enumClazz) { + String prop = getProperty(property); if (prop == null) { return null; } @@ -63,37 +63,37 @@ public > E getEnumValue(String propName, Class enumClazz) { return Enum.valueOf(enumClazz, prop.toUpperCase()); } - public boolean getBool(String propName, boolean defaultValue) { - Boolean b = getBoolean(propName); + public boolean getBool(LearnLibProperty property, boolean defaultValue) { + Boolean b = getBoolean(property); if (b != null) { return b; } return defaultValue; } - public Boolean getBoolean(String propName) { - String prop = getProperty(propName); + public Boolean getBoolean(LearnLibProperty property) { + String prop = getProperty(property); if (prop != null) { return Boolean.parseBoolean(prop); } return null; } - public int getInt(String propName, int defaultValue) { - Integer prop = getInteger(propName); + public int getInt(LearnLibProperty property, int defaultValue) { + Integer prop = getInteger(property); if (prop != null) { return prop; } return defaultValue; } - public Integer getInteger(String propName) { - String prop = getProperty(propName); + public Integer getInteger(LearnLibProperty property) { + String prop = getProperty(property); if (prop != null) { try { return Integer.parseInt(prop); } catch (NumberFormatException ex) { - LOG.warn("Could not parse LearnLib integer property '" + propName + "'.", ex); + LOG.warn("Could not parse LearnLib integer property '" + property + "'.", ex); } } return null; diff --git a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibLocalPropertiesAutomataLibSettingsSource.java b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibLocalPropertiesAutomataLibSettingsSource.java index 374ea3f543..3d634bf668 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibLocalPropertiesAutomataLibSettingsSource.java +++ b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibLocalPropertiesAutomataLibSettingsSource.java @@ -17,7 +17,9 @@ import net.automatalib.AutomataLibSettingsSource; import net.automatalib.commons.util.settings.LocalFileSource; +import org.kohsuke.MetaInfServices; +@MetaInfServices(AutomataLibSettingsSource.class) public class LearnLibLocalPropertiesAutomataLibSettingsSource extends LocalFileSource implements AutomataLibSettingsSource { diff --git a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibLocalPropertiesSource.java b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibLocalPropertiesSource.java index a82155e063..10ae5af618 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibLocalPropertiesSource.java +++ b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibLocalPropertiesSource.java @@ -17,7 +17,9 @@ import de.learnlib.api.setting.LearnLibSettingsSource; import net.automatalib.commons.util.settings.LocalFileSource; +import org.kohsuke.MetaInfServices; +@MetaInfServices(LearnLibSettingsSource.class) public class LearnLibLocalPropertiesSource extends LocalFileSource implements LearnLibSettingsSource { public LearnLibLocalPropertiesSource() { diff --git a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibPropertiesAutomataLibSettingsSource.java b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibPropertiesAutomataLibSettingsSource.java index 4f5fb08847..b8f44ed844 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibPropertiesAutomataLibSettingsSource.java +++ b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibPropertiesAutomataLibSettingsSource.java @@ -17,7 +17,9 @@ import net.automatalib.AutomataLibSettingsSource; import net.automatalib.commons.util.settings.AbstractClassPathFileSource; +import org.kohsuke.MetaInfServices; +@MetaInfServices(AutomataLibSettingsSource.class) public class LearnLibPropertiesAutomataLibSettingsSource extends AbstractClassPathFileSource implements AutomataLibSettingsSource { diff --git a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibPropertiesSource.java b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibPropertiesSource.java index 1a5f0529e2..501ca5440d 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibPropertiesSource.java +++ b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibPropertiesSource.java @@ -17,7 +17,9 @@ import de.learnlib.api.setting.LearnLibSettingsSource; import net.automatalib.commons.util.settings.AbstractClassPathFileSource; +import org.kohsuke.MetaInfServices; +@MetaInfServices(LearnLibSettingsSource.class) public class LearnLibPropertiesSource extends AbstractClassPathFileSource implements LearnLibSettingsSource { public LearnLibPropertiesSource() { diff --git a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibSystemPropertiesSource.java b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibSystemPropertiesSource.java index 6b6fc88bf2..b52e2a9896 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibSystemPropertiesSource.java +++ b/commons/settings/src/main/java/de/learnlib/setting/sources/LearnLibSystemPropertiesSource.java @@ -17,7 +17,9 @@ import de.learnlib.api.setting.LearnLibSettingsSource; import net.automatalib.commons.util.settings.AbstractSystemPropertiesSource; +import org.kohsuke.MetaInfServices; +@MetaInfServices(LearnLibSettingsSource.class) public class LearnLibSystemPropertiesSource extends AbstractSystemPropertiesSource implements LearnLibSettingsSource { } diff --git a/commons/settings/src/main/resources/META-INF/services/de.learnlib.api.setting.LearnLibSettingsSource b/commons/settings/src/main/resources/META-INF/services/de.learnlib.api.setting.LearnLibSettingsSource deleted file mode 100644 index 1789de47f8..0000000000 --- a/commons/settings/src/main/resources/META-INF/services/de.learnlib.api.setting.LearnLibSettingsSource +++ /dev/null @@ -1,3 +0,0 @@ -de.learnlib.setting.sources.LearnLibPropertiesSource -de.learnlib.setting.sources.LearnLibSystemPropertiesSource -de.learnlib.setting.sources.LearnLibLocalPropertiesSource diff --git a/commons/settings/src/main/resources/META-INF/services/net.automatalib.AutomataLibSettingsSource b/commons/settings/src/main/resources/META-INF/services/net.automatalib.AutomataLibSettingsSource deleted file mode 100644 index 191681b61b..0000000000 --- a/commons/settings/src/main/resources/META-INF/services/net.automatalib.AutomataLibSettingsSource +++ /dev/null @@ -1,2 +0,0 @@ -de.learnlib.setting.sources.LearnLibPropertiesAutomataLibSettingsSource -de.learnlib.setting.sources.LearnLibLocalPropertiesAutomataLibSettingsSource diff --git a/commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.java b/commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.java new file mode 100644 index 0000000000..aa39c46038 --- /dev/null +++ b/commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.java @@ -0,0 +1,65 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.setting; + +import java.io.File; + +import org.testng.Assert; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class LearnLibSettingsTest { + + @BeforeSuite + public void setUp() { + final File properties = new File(LearnLibSettingsTest.class.getResource("/learnlib.properties").getFile()); + System.setProperty("learnlib.properties", properties.getAbsolutePath()); + System.setProperty(LearnLibProperty.LTSMIN_PATH.getPropertyKey(), "OVERRIDDEN"); + } + + @Test + public void testProperties() { + LearnLibSettings settings = LearnLibSettings.getInstance(); + + for (LearnLibProperty p : LearnLibProperty.values()) { + switch (p) { + case LTSMIN_PATH: + Assert.assertEquals("OVERRIDDEN", settings.getProperty(LearnLibProperty.LTSMIN_PATH)); + break; + case PARALLEL_BATCH_SIZE_DYNAMIC: + Assert.assertEquals(1, settings.getInt(LearnLibProperty.PARALLEL_BATCH_SIZE_DYNAMIC, 0)); + break; + case PARALLEL_BATCH_SIZE_STATIC: + Assert.assertEquals(2, settings.getInt(LearnLibProperty.PARALLEL_BATCH_SIZE_STATIC, 0)); + break; + case PARALLEL_POOL_POLICY: + Assert.assertEquals("CACHED", settings.getProperty(LearnLibProperty.PARALLEL_POOL_POLICY)); + break; + case PARALLEL_POOL_SIZE: + Assert.assertEquals(3, settings.getInt(LearnLibProperty.PARALLEL_POOL_SIZE, 0)); + break; + case PARALLEL_QUERIES_THRESHOLD: + Assert.assertEquals(100, settings.getInt(LearnLibProperty.PARALLEL_QUERIES_THRESHOLD, 0)); + break; + default: + throw new IllegalStateException("Unhandled property " + p); + } + } + } +} diff --git a/commons/settings/src/test/resources/learnlib.properties b/commons/settings/src/test/resources/learnlib.properties new file mode 100644 index 0000000000..0428e8b409 --- /dev/null +++ b/commons/settings/src/test/resources/learnlib.properties @@ -0,0 +1,6 @@ +learnlib.external.ltsmin.path=ltsmin +learnlib.parallel.batch_size.dynamic=1 +learnlib.parallel.batch_size.static=2 +learnlib.parallel.pool_policy=CACHED +learnlib.parallel.pool_size=3 +learnlib.queries.parallel.threshold=100 \ No newline at end of file diff --git a/commons/util/src/main/java/de/learnlib/util/MQUtil.java b/commons/util/src/main/java/de/learnlib/util/MQUtil.java index e0ed4aba52..a36514089b 100644 --- a/commons/util/src/main/java/de/learnlib/util/MQUtil.java +++ b/commons/util/src/main/java/de/learnlib/util/MQUtil.java @@ -30,6 +30,7 @@ import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; import de.learnlib.api.query.Query; +import de.learnlib.setting.LearnLibProperty; import de.learnlib.setting.LearnLibSettings; import net.automatalib.automata.concepts.SuffixOutput; import net.automatalib.commons.util.Pair; @@ -42,7 +43,7 @@ public final class MQUtil { static { LearnLibSettings settings = LearnLibSettings.getInstance(); - PARALLEL_THRESHOLD = settings.getInt("queries.parallel.threshold", -1); + PARALLEL_THRESHOLD = settings.getInt(LearnLibProperty.PARALLEL_QUERIES_THRESHOLD, -1); } private MQUtil() { diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java index 5a1b7892a3..a64f98c03b 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; +import de.learnlib.setting.LearnLibProperty; import de.learnlib.setting.LearnLibSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,8 +33,6 @@ */ public final class LTSminUtil { - public static final String LTSMIN_PATH_PROPERTY_SUFFIX = "external.ltsmin.path"; - /** * Path to the "etf2lts-mc" binary. */ @@ -49,8 +48,9 @@ public final class LTSminUtil { private static final String CHECK = "An exception occurred while checking if LTSmin is installed. " + "Could not run binary '%s', the following exception occurred: %s. " + "LTSmin can be obtained at https://ltsmin.utwente.nl. If you installed LTSmin " + - "in a non standard location you can set the property: " + - "'learnlib.external.ltsmin.path'. Setting the $PATH variable works too."; + "in a non standard location you can set the property: '" + + LearnLibProperty.LTSMIN_PATH.getPropertyKey() + + "'. Setting the $PATH variable works too."; /** * The exit code for running an LTSmin binary with --version. @@ -60,7 +60,7 @@ public final class LTSminUtil { static { LearnLibSettings settings = LearnLibSettings.getInstance(); - final String ltsMinPath = settings.getProperty(LTSMIN_PATH_PROPERTY_SUFFIX, ""); + final String ltsMinPath = settings.getProperty(LearnLibProperty.LTSMIN_PATH, ""); ETF2LTS_MC = Paths.get(ltsMinPath, "etf2lts-mc").toString(); LTSMIN_CONVERT = Paths.get(ltsMinPath, "ltsmin-convert").toString(); diff --git a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracle.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracle.java index aa08ba1858..d1a766a7a8 100644 --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracle.java +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracle.java @@ -30,6 +30,7 @@ import com.google.common.base.Throwables; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; +import de.learnlib.setting.LearnLibProperty; import de.learnlib.setting.LearnLibSettings; /** @@ -52,12 +53,11 @@ public class DynamicParallelOracle implements ParallelOracle { static { LearnLibSettings settings = LearnLibSettings.getInstance(); - BATCH_SIZE = settings.getInt("parallel.dynamic.batch_size", 1); - int numProcessors = Runtime.getRuntime().availableProcessors(); - POOL_SIZE = settings.getInt("parallel.dynamic.pool_size", numProcessors); - POOL_POLICY = settings.getEnumValue("parallel.static.pool_policy", PoolPolicy.class, PoolPolicy.CACHED); + BATCH_SIZE = settings.getInt(LearnLibProperty.PARALLEL_BATCH_SIZE_DYNAMIC, 1); + POOL_SIZE = settings.getInt(LearnLibProperty.PARALLEL_POOL_SIZE, numProcessors); + POOL_POLICY = settings.getEnumValue(LearnLibProperty.PARALLEL_POOL_POLICY, PoolPolicy.class, PoolPolicy.CACHED); } @Nonnull diff --git a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracle.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracle.java index 4bad90db47..8837dce983 100644 --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracle.java +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracle.java @@ -31,6 +31,7 @@ import com.google.common.base.Throwables; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; +import de.learnlib.setting.LearnLibProperty; import de.learnlib.setting.LearnLibSettings; /** @@ -58,12 +59,11 @@ public class StaticParallelOracle implements ParallelOracle { static { LearnLibSettings settings = LearnLibSettings.getInstance(); - MIN_BATCH_SIZE = settings.getInt("parallel.static.min_batch_size", DEFAULT_MIN_BATCH_SIZE); - int numCores = Runtime.getRuntime().availableProcessors(); - NUM_INSTANCES = settings.getInt("parallel.static.num_instances", numCores); - POOL_POLICY = settings.getEnumValue("parallel.static.pool_policy", PoolPolicy.class, PoolPolicy.CACHED); + MIN_BATCH_SIZE = settings.getInt(LearnLibProperty.PARALLEL_BATCH_SIZE_STATIC, DEFAULT_MIN_BATCH_SIZE); + NUM_INSTANCES = settings.getInt(LearnLibProperty.PARALLEL_POOL_SIZE, numCores); + POOL_POLICY = settings.getEnumValue(LearnLibProperty.PARALLEL_POOL_SIZE, PoolPolicy.class, PoolPolicy.CACHED); } @Nonnegative From 81dcf4391a7d1d478fa86d35464466836364dbc8 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 6 Mar 2018 10:34:11 +0100 Subject: [PATCH 027/125] util: cleanup SimpleProfiler - remove redundant PROFILE flag - add method for explicitly querying single (cumulated) profiles - improve JavaDoc --- .../util/statistics/SimpleProfiler.java | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/commons/util/src/main/java/de/learnlib/util/statistics/SimpleProfiler.java b/commons/util/src/main/java/de/learnlib/util/statistics/SimpleProfiler.java index f923235981..1b914671d6 100644 --- a/commons/util/src/main/java/de/learnlib/util/statistics/SimpleProfiler.java +++ b/commons/util/src/main/java/de/learnlib/util/statistics/SimpleProfiler.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package de.learnlib.util.statistics; import java.util.Map; @@ -34,7 +33,6 @@ public final class SimpleProfiler { private static final Map CUMULATED = new ConcurrentHashMap<>(); private static final Map PENDING = new ConcurrentHashMap<>(); - private static final boolean PROFILE = true; private static final LearnLogger LOGGER = LearnLogger.getLogger(SimpleProfiler.class.getName()); private static final double MILLISECONDS_PER_SECOND = 1000.0; @@ -43,7 +41,7 @@ private SimpleProfiler() { } /** - * reset internal data. + * Reset internal data. */ public static void reset() { CUMULATED.clear(); @@ -51,40 +49,46 @@ public static void reset() { } /** - * start activity. + * Start the timer identified by the given key. + * + * @param name + * The name of the timer to be started. */ public static void start(String name) { - if (!PROFILE) { - return; - } - long start = System.currentTimeMillis(); - - PENDING.put(name, start); - + PENDING.put(name, System.currentTimeMillis()); } /** - * stop activity. + * Stop the timer identified by the given key. After stopping a timer, the time passed from its + * {@link #start(String) initialization} will be added to the cumulated time of the specific timer. + * + * @param name + * The name of the timer to be stopped. */ public static void stop(String name) { - if (!PROFILE) { - return; - } Long start = PENDING.remove(name); if (start == null) { return; } long duration = System.currentTimeMillis() - start; - Counter sum = CUMULATED.get(name); - if (sum == null) { - sum = new Counter(name, "ms"); - } + Counter sum = CUMULATED.computeIfAbsent(name, k -> new Counter(k, "ms")); sum.increment(duration); - CUMULATED.put(name, sum); } /** - * get profiling results as string. + * Return the counter for the cumulated (passed) time of the given timer. + * + * @param name + * The name of the timer to be returned. + * + * @return The counter for tracking the passed milliseconds of the timer + */ + public static Counter cumulated(String name) { + return CUMULATED.get(name); + } + + /** + * Get profiling results as string. */ @Nonnull public static String getResults() { @@ -100,7 +104,7 @@ public static String getResults() { } /** - * log results in category PROFILING. + * Log results in category PROFILING. */ public static void logResults() { for (Entry e : CUMULATED.entrySet()) { From b27845d52d3e0ec3d38128707fd4271c8c57edf3 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 6 Mar 2018 13:34:58 +0100 Subject: [PATCH 028/125] util: Cleanup Experiments - Make profile keys public to prevent typos in the future - Added state checks to prevent duplicate execution - Added Test-Case --- commons/util/pom.xml | 5 + .../java/de/learnlib/util/BBCExperiment.java | 16 ++- .../java/de/learnlib/util/Experiment.java | 53 ++++--- .../java/de/learnlib/util/ExperimentTest.java | 132 ++++++++++++++++++ 4 files changed, 186 insertions(+), 20 deletions(-) create mode 100644 commons/util/src/test/java/de/learnlib/util/ExperimentTest.java diff --git a/commons/util/pom.xml b/commons/util/pom.xml index a7f6895304..7f936b98e6 100644 --- a/commons/util/pom.xml +++ b/commons/util/pom.xml @@ -71,5 +71,10 @@ limitations under the License. com.google.code.findbugs jsr305 + + + org.testng + testng + diff --git a/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java b/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java index edff14b10d..5745a950cc 100644 --- a/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java +++ b/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java @@ -40,6 +40,8 @@ */ public class BBCExperiment extends Experiment { + public static final String PROPERTY_VIOLATION_PROFILE_KEY = "Searching for property violation"; + private static final LearnLogger LOGGER = LearnLogger.getLogger(BBCExperiment.class); /** @@ -117,6 +119,10 @@ public Counter getRoundsPropertyViolation() { @Nonnull @Override public A run() { + if (isRun()) { + throw new IllegalStateException("Experiment has already been run"); + } + init(); do { @@ -125,16 +131,18 @@ public A run() { do { roundsPropertyViolation.increment(); LOGGER.logPhase("Searching for property violation"); - profileStart("Searching for property violation"); + + profileStart(PROPERTY_VIOLATION_PROFILE_KEY); ce = blackBoxOracle.findCounterExample(getLearningAlgorithm().getHypothesisModel(), getInputs()); - profileStop("Searching for property violation"); + profileStop(PROPERTY_VIOLATION_PROFILE_KEY); assert blackBoxOracle.allPropertiesViolated() == (ce == null); } while (!blackBoxOracle.allPropertiesViolated() && ce != null && getLearningAlgorithm().refineHypothesis(ce)); } while ((keepLearning || !blackBoxOracle.allPropertiesViolated()) && refineHypothesis()); - setFinalHypothesis(getLearningAlgorithm().getHypothesisModel()); + final A finalHyp = getLearningAlgorithm().getHypothesisModel(); + setFinalHypothesis(finalHyp); - return getLearningAlgorithm().getHypothesisModel(); + return finalHyp; } public static class DFABBCExperiment extends BBCExperiment, I, Boolean> { diff --git a/commons/util/src/main/java/de/learnlib/util/Experiment.java b/commons/util/src/main/java/de/learnlib/util/Experiment.java index 085dc77f3d..7b320f9052 100644 --- a/commons/util/src/main/java/de/learnlib/util/Experiment.java +++ b/commons/util/src/main/java/de/learnlib/util/Experiment.java @@ -42,6 +42,9 @@ @ParametersAreNonnullByDefault public class Experiment { + public static final String LEARNING_PROFILE_KEY = "Learning"; + public static final String COUNTEREXAMPLE_PROFILE_KEY = "Searching for counterexample"; + private static final LearnLogger LOGGER = LearnLogger.getLogger(Experiment.class); private boolean logModels; @@ -94,51 +97,69 @@ public void setProfile(boolean profile) { this.profile = profile; } + /** + * Returns whether this experiment has already been run. + * + * @return {@code true} if this experiment has been run, {@code false} otherwise. + */ + public boolean isRun() { + return this.finalHypothesis != null; + } + protected void init() { - getRounds().increment(); - LOGGER.logPhase("Starting round " + getRounds().getCount()); + rounds.increment(); + LOGGER.logPhase("Starting round " + rounds.getCount()); LOGGER.logPhase("Learning"); - profileStart("Learning"); - getLearningAlgorithm().startLearning(); - profileStop("Learning"); + + profileStart(LEARNING_PROFILE_KEY); + learningAlgorithm.startLearning(); + profileStop(LEARNING_PROFILE_KEY); } protected boolean refineHypothesis() { A hyp = getLearningAlgorithm().getHypothesisModel(); - if (isLogModels()) { + if (logModels) { LOGGER.logModel(hyp); } LOGGER.logPhase("Searching for counterexample"); - profileStart("Searching for counterexample"); - DefaultQuery ce = getEquivalenceAlgorithm().findCounterExample(hyp, getInputs()); - profileStop("Searching for counterexample"); + + profileStart(COUNTEREXAMPLE_PROFILE_KEY); + DefaultQuery ce = equivalenceAlgorithm.findCounterExample(hyp, getInputs()); + profileStop(COUNTEREXAMPLE_PROFILE_KEY); + if (ce != null) { LOGGER.logCounterexample(ce.toString()); // next round ... - getRounds().increment(); + rounds.increment(); LOGGER.logPhase("Starting round " + getRounds().getCount()); LOGGER.logPhase("Learning"); - profileStart("Learning"); - getLearningAlgorithm().refineHypothesis(ce); - profileStop("Learning"); + + profileStart(LEARNING_PROFILE_KEY); + final boolean refined = learningAlgorithm.refineHypothesis(ce); + profileStop(LEARNING_PROFILE_KEY); + + assert refined; } + return ce != null; } @Nonnull public A run() { + if (isRun()) { + throw new IllegalStateException("Experiment has already been run"); + } init(); while (refineHypothesis()) { } - finalHypothesis = getLearningAlgorithm().getHypothesisModel(); + finalHypothesis = learningAlgorithm.getHypothesisModel(); return finalHypothesis; - } protected void setFinalHypothesis(A hyp) { @@ -147,7 +168,7 @@ protected void setFinalHypothesis(A hyp) { @Nonnull public A getFinalHypothesis() { - if (finalHypothesis == null) { + if (!isRun()) { throw new IllegalStateException("Experiment has not yet been run"); } return finalHypothesis; diff --git a/commons/util/src/test/java/de/learnlib/util/ExperimentTest.java b/commons/util/src/test/java/de/learnlib/util/ExperimentTest.java new file mode 100644 index 0000000000..e47c9c6217 --- /dev/null +++ b/commons/util/src/test/java/de/learnlib/util/ExperimentTest.java @@ -0,0 +1,132 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.util; + +import java.util.Collection; +import java.util.Random; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; +import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.util.Experiment.DFAExperiment; +import de.learnlib.util.statistics.SimpleProfiler; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class ExperimentTest { + + private static final Random RANDOM = new Random(42); + private static final int REFINEMENT_STEPS = 3; + + @Test + public void testExperiment() { + + final Alphabet alphabet = Alphabets.characters('a', 'c'); + final CompactDFA target = RandomAutomata.randomDFA(RANDOM, 5, alphabet); + final CompactDFA intermediateTarget = RandomAutomata.randomDFA(RANDOM, target.size() - 1, alphabet); + + final MockUpLearner learner = new MockUpLearner<>(target, intermediateTarget); + final DFAEquivalenceOracle eq = new MockUpOracle<>(intermediateTarget); + + DFAExperiment experiment = new DFAExperiment<>(learner, eq, alphabet); + experiment.setProfile(true); + + Assert.assertThrows(experiment::getFinalHypothesis); + + experiment.run(); + + Assert.assertThrows(experiment::run); + + DFA finalModel = experiment.getFinalHypothesis(); + + Assert.assertNotNull(experiment.getFinalHypothesis()); + Assert.assertTrue(finalModel == target); + + Assert.assertTrue(learner.startLearningCalled); + Assert.assertEquals(learner.refinementSteps, REFINEMENT_STEPS); + + Assert.assertNotNull(SimpleProfiler.cumulated(Experiment.LEARNING_PROFILE_KEY)); + Assert.assertNotNull(SimpleProfiler.cumulated(Experiment.COUNTEREXAMPLE_PROFILE_KEY)); + } + + private static final class MockUpLearner implements DFALearner { + + private final DFA targetModel; + private final DFA intermediateModel; + private boolean startLearningCalled; + private int refinementSteps; + + MockUpLearner(CompactDFA target, CompactDFA intermediateTarget) { + targetModel = target; + intermediateModel = intermediateTarget; + } + + @Override + public void startLearning() { + startLearningCalled = true; + } + + @Override + public boolean refineHypothesis(@Nonnull DefaultQuery ceQuery) { + return refinementSteps++ < REFINEMENT_STEPS; + } + + @Nonnull + @Override + public DFA getHypothesisModel() { + if (refinementSteps < REFINEMENT_STEPS) { + return intermediateModel; + } + + return targetModel; + } + } + + private static final class MockUpOracle implements DFAEquivalenceOracle { + + private final DFA intermediateTarget; + private int counterexamples; + + MockUpOracle(DFA intermediateTarget) { + this.intermediateTarget = intermediateTarget; + } + + @Nullable + @Override + public DefaultQuery findCounterExample(DFA hypothesis, Collection inputs) { + if (counterexamples < REFINEMENT_STEPS) { + Assert.assertTrue(hypothesis == intermediateTarget); + + counterexamples++; + return new DefaultQuery<>(Word.epsilon(), true); + } + return null; + } + } + +} From 55dcb276f4b2c5e0f009c462fa77971e719a318a Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 13 Mar 2018 16:21:28 +0100 Subject: [PATCH 029/125] switch from FindBugs to SpotBugs FindBugs is no longer maintained and creates problems on Java9 --- build-parent/pom.xml | 6 +++--- ...gs-exclusions.xml => learnlib-spotbugs-exclusions.xml} | 0 pom.xml | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) rename build-tools/src/main/resources/{learnlib-findbugs-exclusions.xml => learnlib-spotbugs-exclusions.xml} (100%) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index cf924da1e9..ca8d37d2fd 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -78,10 +78,10 @@ limitations under the License. - org.codehaus.mojo - findbugs-maven-plugin + com.github.spotbugs + spotbugs-maven-plugin - /learnlib-findbugs-exclusions.xml + /learnlib-spotbugs-exclusions.xml Max diff --git a/build-tools/src/main/resources/learnlib-findbugs-exclusions.xml b/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml similarity index 100% rename from build-tools/src/main/resources/learnlib-findbugs-exclusions.xml rename to build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml diff --git a/pom.xml b/pom.xml index 6105ca08ac..dc48b4e342 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,6 @@ limitations under the License. 1.4.1 1.6.0 2.20 - 3.0.5 1.6 2.9 0.8.0 @@ -214,6 +213,7 @@ limitations under the License. 1.1 3.6 3.0.1 + 3.1.2 2.20 1.1.0 @@ -628,9 +628,9 @@ limitations under the License. - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs-plugin.version} + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-plugin.version} org.apache.maven.plugins From 20fb00ba3d1508ef098f43a61f1aa8af6014acd9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 13 Mar 2018 16:22:46 +0100 Subject: [PATCH 030/125] bump dependency version - update guava to 24.0-jre for the SpotBugs plugin to correctly ignore ignored return values - explicitly declare metainf-services (previously only imported from automatalib) and add additional dependencies to javaDoc plugin of distribution artifact --- distribution/pom.xml | 12 ++++++++++++ pom.xml | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/distribution/pom.xml b/distribution/pom.xml index a743397388..9c11303cae 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -549,6 +549,18 @@ limitations under the License. de.learnlib:* + + + com.github.misberner.buildergen + buildergen + ${buildergen.version} + + + org.kohsuke.metainf-services + metainf-services + ${metainf-services.version} + + de.learnlib learnlib-parent - 0.13.1 + 0.14.0-SNAPSHOT pom LearnLib http://learnlib.github.io/learnlib/maven-site/${project.version} @@ -129,7 +129,7 @@ limitations under the License. scm:git:git@github.com:LearnLib/learnlib.git scm:git:git@github.com:LearnLib/learnlib.git https://github.com/LearnLib/learnlib/tree/develop - learnlib-0.13.1 + HEAD - + diff --git a/pom.xml b/pom.xml index 76c273d8ed..40368c1e6b 100644 --- a/pom.xml +++ b/pom.xml @@ -198,16 +198,16 @@ limitations under the License. 2.17 3.7.0 4.3.0 - 3.0.1 + 3.1.1 1.4.1 1.6.0 2.21.0 1.6 2.9 0.8.0 - 2.10.4 + 3.0.0 1.0.0 - 3.8 + 3.9.0 2.5.3 3.0.2 1.1 @@ -628,6 +628,7 @@ limitations under the License. maven-pmd-plugin ${pmd-plugin.version} + true true false @@ -746,7 +747,7 @@ limitations under the License. ${javadoc-plugin.version} true - 1.8 + ${maven.compiler.source} true false @@ -860,7 +861,7 @@ limitations under the License. maven-javadoc-plugin true - 1.8 + ${maven.compiler.source} true false From 87a65ae4f97fa97fdbb9484e65cf7ac10cf8cee2 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 29 May 2018 08:40:55 +0200 Subject: [PATCH 042/125] travis: use correct Java 9 language version --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ca9256118b..831b0139fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,13 +40,13 @@ jobs: fast_finish: true allow_failures: - jdk: oraclejdk9 - env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=1.9 -Dmaven.compiler.target=1.9" + env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=9 -Dmaven.compiler.target=9" include: - jdk: openjdk8 - jdk: oraclejdk8 - jdk: oraclejdk9 - jdk: oraclejdk9 - env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=1.9 -Dmaven.compiler.target=1.9" + env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=9 -Dmaven.compiler.target=9" - stage: coverage jdk: openjdk8 # use openjdk8 build script: From 8a05242bec847fb6400fd3ba16648fa9d50d5982 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 29 May 2018 10:06:23 +0200 Subject: [PATCH 043/125] oracles: fix deprecated code usage --- ...stractBreadthFirstEmptinessOracleTest.java | 6 ++--- .../AbstractLassoAutomatonEmptinessTest.java | 22 +++++++++---------- ...stractBreadthFirstInclusionOracleTest.java | 6 ++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java index a9ee061a5f..f6036f6d4b 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java @@ -31,7 +31,7 @@ import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.Mockito; import org.testng.Assert; @@ -95,7 +95,7 @@ public void setUp() { q.answer(true); } return null; - }).when(dfaMembershipOracle).processQuery(Matchers.any()); + }).when(dfaMembershipOracle).processQuery(ArgumentMatchers.any()); } @Override @@ -147,7 +147,7 @@ public void setUp() { q.answer(Word.fromSymbols("not-an-output")); } return null; - }).when(mealyMembershipOracle).processQuery(Matchers.any()); + }).when(mealyMembershipOracle).processQuery(ArgumentMatchers.any()); } @Override diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java index bca0fd90c0..e39a03bbbb 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java @@ -38,7 +38,7 @@ import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.Mockito; import org.testng.Assert; @@ -105,11 +105,11 @@ public void setUp() { q.answer(false); } return null; - }).when(dfaOmegaMembershipOracle).processQuery(Matchers.any()); - Mockito.when(dfaOmegaMembershipOracle.isSameState(Matchers.any(), - Matchers.any(), - Matchers.any(), - Matchers.any())).thenReturn(true); + }).when(dfaOmegaMembershipOracle).processQuery(ArgumentMatchers.any()); + Mockito.when(dfaOmegaMembershipOracle.isSameState(ArgumentMatchers.any(), + ArgumentMatchers.any(), + ArgumentMatchers.any(), + ArgumentMatchers.any())).thenReturn(true); } @Override @@ -165,11 +165,11 @@ public void setUp() { q.answer(Word.fromSymbols("not-an-output")); } return null; - }).when(mealyOmegaMembershipOracle).processQuery(Matchers.any()); - Mockito.when(mealyOmegaMembershipOracle.isSameState(Matchers.any(), - Matchers.any(), - Matchers.any(), - Matchers.any())).thenReturn(true); + }).when(mealyOmegaMembershipOracle).processQuery(ArgumentMatchers.any()); + Mockito.when(mealyOmegaMembershipOracle.isSameState(ArgumentMatchers.any(), + ArgumentMatchers.any(), + ArgumentMatchers.any(), + ArgumentMatchers.any())).thenReturn(true); } @Override diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java index 961a198eb6..2d5738c96f 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java @@ -31,7 +31,7 @@ import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.Mockito; import org.testng.Assert; @@ -95,7 +95,7 @@ public void setUp() { q.answer(false); } return null; - }).when(dfaMembershipOracle).processQuery(Matchers.any()); + }).when(dfaMembershipOracle).processQuery(ArgumentMatchers.any()); } @Override @@ -145,7 +145,7 @@ public void setUp() { q.answer(Word.fromSymbols("not-an-output")); } return null; - }).when(mealyMembershipOracle).processQuery(Matchers.any()); + }).when(mealyMembershipOracle).processQuery(ArgumentMatchers.any()); } From 60f8fcf8734a01e92fe0329281160af7b0ca3612 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 31 May 2018 14:09:33 +0200 Subject: [PATCH 044/125] bump depedency versions for Java 10 compatibility --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 40368c1e6b..f98fc18552 100644 --- a/pom.xml +++ b/pom.xml @@ -213,7 +213,7 @@ limitations under the License. 1.1 3.6 3.0.1 - 3.1.2 + 3.1.3.1 2.20 1.1.0 From ad33fba01d43e1d31109015b218fa1a7323e1504 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 31 May 2018 14:12:36 +0200 Subject: [PATCH 045/125] travis: add config for JDK 9 & 10 see travis-ci/travis-build#1347 --- .travis.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 831b0139fb..8cf0d508e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,14 +39,21 @@ script: jobs: fast_finish: true allow_failures: - - jdk: oraclejdk9 + - jdk: openjdk9 env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=9 -Dmaven.compiler.target=9" + - jdk: openjdk10 + env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=10 -Dmaven.compiler.target=10" include: - jdk: openjdk8 - jdk: oraclejdk8 + - jdk: openjdk9 - jdk: oraclejdk9 - - jdk: oraclejdk9 + - jdk: openjdk10 + - jdk: oraclejdk10 + - jdk: openjdk9 env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=9 -Dmaven.compiler.target=9" + - jdk: openjdk10 + env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=10 -Dmaven.compiler.target=10" - stage: coverage jdk: openjdk8 # use openjdk8 build script: From 0ed3b2150da5b145c4249a57c32b7f6ddfbcb02e Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 6 Jun 2018 14:20:26 +0200 Subject: [PATCH 046/125] algorithms/kv: add getters for discrimination tree --- .../de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java | 4 ++++ .../learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java | 6 +++++- .../algorithms/kv/mealy/KearnsVaziraniMealyState.java | 8 ++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java index fcb51cf787..8503875068 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java @@ -110,6 +110,10 @@ public DFA getHypothesisModel() { return hypothesis; } + public BinaryDTree> getDiscriminationTree() { + return discriminationTree; + } + private boolean refineHypothesisSingle(Word input, boolean output) { int inputLen = input.length(); diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java index 74e0902b43..2b438abf2e 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java @@ -59,7 +59,7 @@ public class KearnsVaziraniMealy private final MembershipOracle> oracle; private final boolean repeatedCounterexampleEvaluation; private final AcexAnalyzer ceAnalyzer; - protected AbstractWordBasedDiscriminationTree, StateInfo>> discriminationTree; + protected MultiDTree, StateInfo>> discriminationTree; protected List>> stateInfos = new ArrayList<>(); private CompactMealy hypothesis; @@ -106,6 +106,10 @@ public boolean refineHypothesis(DefaultQuery> ceQuery) { return hypothesis; } + public MultiDTree, StateInfo>> getDiscriminationTree() { + return discriminationTree; + } + private boolean refineHypothesisSingle(Word input, Word output) { int inputLen = input.length(); diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyState.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyState.java index 8b59a4cc01..41ae70ee6e 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyState.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyState.java @@ -19,7 +19,7 @@ import java.util.List; import de.learnlib.algorithms.kv.StateInfo; -import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree; +import de.learnlib.datastructure.discriminationtree.MultiDTree; import net.automatalib.automata.transout.impl.compact.CompactMealy; import net.automatalib.words.Word; @@ -36,11 +36,11 @@ public class KearnsVaziraniMealyState implements Serializable { private final CompactMealy hypothesis; - private final AbstractWordBasedDiscriminationTree, StateInfo>> discriminationTree; + private final MultiDTree, StateInfo>> discriminationTree; private final List>> stateInfos; KearnsVaziraniMealyState(final CompactMealy hypothesis, - final AbstractWordBasedDiscriminationTree, StateInfo>> discriminationTree, + final MultiDTree, StateInfo>> discriminationTree, final List>> stateInfos) { this.hypothesis = hypothesis; this.discriminationTree = discriminationTree; @@ -51,7 +51,7 @@ CompactMealy getHypothesis() { return hypothesis; } - AbstractWordBasedDiscriminationTree, StateInfo>> getDiscriminationTree() { + MultiDTree, StateInfo>> getDiscriminationTree() { return discriminationTree; } From 9ad8983cf3e4f2414d688dcd16479fc6dcb7371e Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 6 Jun 2018 14:53:05 +0200 Subject: [PATCH 047/125] checkstyle: fix unused import --- .../de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java | 1 - 1 file changed, 1 deletion(-) diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java index 2b438abf2e..d692ff2548 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java @@ -33,7 +33,6 @@ import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.discriminationtree.MultiDTree; import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; -import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree; import de.learnlib.datastructure.discriminationtree.model.LCAInfo; import de.learnlib.util.mealy.MealyUtil; import net.automatalib.automata.transout.MealyMachine; From 07e9d2ae79f88d2e21eda345fadac3916c03bb44 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 7 Jun 2018 09:29:50 +0200 Subject: [PATCH 048/125] bump PMD plugin version for JDK10 compatibility --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f98fc18552..0971b83bce 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ limitations under the License. 0.8.0 3.0.0 1.0.0 - 3.9.0 + 3.10.0 2.5.3 3.0.2 1.1 From 7f53483a9232362f3b001689664ac1fcf4114fd5 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 9 Jun 2018 22:21:59 +0200 Subject: [PATCH 049/125] refactorings and clean-ups in preparation for new configs of PMD 6.4.0 --- .../learnlib/algorithms/adt/adt/ADTNode.java | 1 + .../algorithms/adt/learner/ADTLearner.java | 6 +- .../algorithms/dhc/mealy/MealyDHC.java | 6 +- .../hypothesis/vpda/AbstractHypTrans.java | 1 + .../hypothesis/vpda/HypLoc.java | 1 + .../discriminationtree/AbstractDTLearner.java | 6 +- .../discriminationtree/dfa/DTLearnerDFA.java | 6 +- .../algorithms/kv/dfa/KearnsVaziraniDFA.java | 6 +- .../kv/mealy/KearnsVaziraniMealy.java | 6 +- .../AbstractExtensibleAutomatonLStar.java | 4 ++ .../algorithms/ttt/vpda/TTTLearnerVPDA.java | 1 + .../ttt/base/AbstractBaseDTNode.java | 1 + .../ttt/base/AbstractTTTLearner.java | 6 +- .../ttt/mealy/TTTTransitionMealy.java | 1 + .../learnlib/algorithms/rpni/it/MdlDfaIT.java | 3 +- .../learnlib/api/oracle/EmptinessOracle.java | 1 + .../learnlib/api/oracle/InclusionOracle.java | 1 + .../acex/impl/AbstractBaseCounterexample.java | 1 + .../de/learnlib/setting/LearnLibSettings.java | 48 +++++++--------- .../AbstractWordBasedDiscriminationTree.java | 1 + .../GenericObservationTable.java | 18 +++++- .../observationtable/RowImpl.java | 4 ++ .../writer/ObservationTableWriter.java | 4 +- .../de/learnlib/drivers/reflect/Error.java | 2 +- ...actMethodOutput.java => MethodOutput.java} | 5 +- .../learnlib/drivers/reflect/ReturnValue.java | 2 +- .../drivers/reflect/SimplePOJODataMapper.java | 8 +-- .../drivers/reflect/SimplePOJOTestDriver.java | 2 +- .../learnlib/drivers/reflect/Unobserved.java | 2 +- .../learnlib/drivers/reflect/ObjectTest.java | 26 ++++----- .../learnlib/examples/example2/Example.java | 24 ++++---- .../modelchecker/AbstractLTSminLTL.java | 31 ++++++---- .../statistic/AbstractStatisticData.java | 4 ++ .../parallelism/StaticParallelOracle.java | 2 +- .../it/learner/AbstractDFALearnerIT.java | 4 +- .../learner/AbstractDFAPassiveLearnerIT.java | 6 +- .../it/learner/AbstractLearnerIT.java | 56 ------------------- .../it/learner/AbstractMealyLearnerIT.java | 4 +- .../AbstractMealyPassiveLearnerIT.java | 6 +- .../it/learner/AbstractMealySymLearnerIT.java | 4 +- ...ssiveLearnerIT.java => LearnerITUtil.java} | 39 ++++++++++--- 41 files changed, 198 insertions(+), 162 deletions(-) rename drivers/basic/src/main/java/de/learnlib/drivers/reflect/{AbstractMethodOutput.java => MethodOutput.java} (87%) delete mode 100644 test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractLearnerIT.java rename test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/{AbstractPassiveLearnerIT.java => LearnerITUtil.java} (68%) diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTNode.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTNode.java index 314ccf2207..1358d659ed 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTNode.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTNode.java @@ -101,6 +101,7 @@ public boolean getEdgeProperties(final ADTNode src, }; } + @Override default boolean isLeaf() { return NodeType.LEAF_NODE == this.getNodeType(); } diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java index b13f2740cc..89a13bb1b0 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java @@ -809,7 +809,11 @@ private void resiftAffectedTransitions(final Set, I, O>> } } - public static class BuilderDefaults { + public static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } public static LeafSplitter leafSplitter() { return LeafSplitters.DEFAULT_SPLITTER; diff --git a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java index d11dce9417..eaec242bf5 100644 --- a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java +++ b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java @@ -301,7 +301,11 @@ public boolean isAccessSequence(Word word) { return canonical.equals(word); } - public static class BuilderDefaults { + public static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } public static GlobalSuffixFinder> suffixFinder() { return GlobalSuffixFinders.RIVEST_SCHAPIRE; diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/AbstractHypTrans.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/AbstractHypTrans.java index 93fbac5864..eb50a1cb76 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/AbstractHypTrans.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/AbstractHypTrans.java @@ -72,6 +72,7 @@ public DTNode getTargetNode() { return nonTreeTarget; } + @Override public Word getAccessSequence() { return aseq; } diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java index f848b4c04a..6b11784e06 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java @@ -85,6 +85,7 @@ public boolean isRoot() { return treeIncoming == null; } + @Override public Word getAccessSequence() { return aseq; } 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..e8329a3ae0 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 @@ -252,7 +252,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 suffixFinder() { return LocalSuffixFinders.RIVEST_SCHAPIRE; 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..107329fc52 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 @@ -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/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java index 8503875068..1dc75413cb 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java @@ -303,7 +303,11 @@ public void resume(final KearnsVaziraniDFAState state) { this.stateInfos = state.getStateInfos(); } - static final class BuilderDefaults { + public static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } public static boolean repeatedCounterexampleEvaluation() { return true; diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java index d692ff2548..aa728ab6f4 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java @@ -320,7 +320,11 @@ public void resume(final KearnsVaziraniMealyState state) { this.stateInfos = state.getStateInfos(); } - static final class BuilderDefaults { + public static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } public static boolean repeatedCounterexampleEvaluation() { return true; diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java index 20a91b8f58..ae9f2f173a 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java @@ -75,6 +75,10 @@ protected List> selectClosingRows(List>> unclosed) { public static final class BuilderDefaults { + private BuilderDefaults() { + // prevent instantiation + } + public static List> initialPrefixes() { return Collections.singletonList(Word.epsilon()); } diff --git a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java index 5ee336ad10..dbc80e1f72 100644 --- a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java +++ b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java @@ -63,6 +63,7 @@ public TTTLearnerVPDA(VPDAlphabet alphabet, MembershipOracle orac super(alphabet, oracle, analyzer); } + @Override protected State> getDefinitiveSuccessor(State> baseState, Word suffix) { NonDetState> curr = NonDetState.fromDet(baseState); int lastDet = 0; diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java index 5497e17c57..ff11a19b79 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java @@ -45,6 +45,7 @@ public TTTState anySubtreeState() { return curr.data; } + @Override public AbstractBaseDTNode anyChild() { assert isInner(); return children.values().iterator().next(); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java index e265e09a38..718a0c2a02 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java @@ -982,7 +982,11 @@ public void resume(final TTTLearnerState state) { this.dtree.setOracle(oracle); } - public static class BuilderDefaults { + public static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } public static AcexAnalyzer analyzer() { return AcexAnalyzers.BINARY_SEARCH_BWD; diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTTransitionMealy.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTTransitionMealy.java index c98a44314b..5a68028b97 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTTransitionMealy.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTTransitionMealy.java @@ -31,6 +31,7 @@ public O getOutput() { return this.output; } + @Override public Object getProperty() { return output; } diff --git a/algorithms/passive/rpni-mdl/src/test/java/de/learnlib/algorithms/rpni/it/MdlDfaIT.java b/algorithms/passive/rpni-mdl/src/test/java/de/learnlib/algorithms/rpni/it/MdlDfaIT.java index 90f02f0dbb..b006ef94d9 100644 --- a/algorithms/passive/rpni-mdl/src/test/java/de/learnlib/algorithms/rpni/it/MdlDfaIT.java +++ b/algorithms/passive/rpni-mdl/src/test/java/de/learnlib/algorithms/rpni/it/MdlDfaIT.java @@ -21,6 +21,7 @@ import de.learnlib.algorithms.rpni.BlueFringeMDLDFA; import de.learnlib.api.query.DefaultQuery; import de.learnlib.testsupport.it.learner.AbstractDFAPassiveLearnerIT; +import de.learnlib.testsupport.it.learner.LearnerITUtil; import de.learnlib.testsupport.it.learner.PassiveLearnerVariantList; import net.automatalib.automata.fsa.DFA; import net.automatalib.words.Alphabet; @@ -33,7 +34,7 @@ public class MdlDfaIT extends AbstractDFAPassiveLearnerIT { @Override protected Collection> generateSamplesInternal(Alphabet alphabet, DFA reference) { - final Collection> samples = super.generateSamples(alphabet, reference); + final Collection> samples = LearnerITUtil.generateSamples(alphabet, reference); // filter out negative examples return samples.stream().filter(DefaultQuery::getOutput).collect(Collectors.toList()); } diff --git a/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java index 817cad1e7b..50ba5c904a 100644 --- a/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java @@ -54,6 +54,7 @@ public interface EmptinessOracle & SimpleDTS, I, D, * * @see AutomatonOracle#isCounterExample(SimpleDTS, Query) */ + @Override default boolean isCounterExample(A hypothesis, Q query) { return query.getOutput().equals(hypothesis.computeOutput(query.getInput())); } diff --git a/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java b/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java index f69d54b3f2..16e9027cc4 100644 --- a/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java @@ -47,6 +47,7 @@ public interface InclusionOracle & SimpleDTS, I, D, * * @see AutomatonOracle#isCounterExample(SimpleDTS, Query) */ + @Override default boolean isCounterExample(A hypothesis, Q query) { return !query.getOutput().equals(hypothesis.computeOutput(query.getInput())); } diff --git a/commons/acex/src/main/java/de/learnlib/acex/impl/AbstractBaseCounterexample.java b/commons/acex/src/main/java/de/learnlib/acex/impl/AbstractBaseCounterexample.java index 2f81f55a44..892da91ee2 100644 --- a/commons/acex/src/main/java/de/learnlib/acex/impl/AbstractBaseCounterexample.java +++ b/commons/acex/src/main/java/de/learnlib/acex/impl/AbstractBaseCounterexample.java @@ -42,6 +42,7 @@ public int getLength() { return values.length; } + @Override public E effect(int index) { E eff = values.get(index); if (eff == null) { diff --git a/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java b/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java index c9967b9ad0..201b8f908e 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java +++ b/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java @@ -16,8 +16,10 @@ package de.learnlib.setting; import java.util.Properties; +import java.util.function.Function; import de.learnlib.api.setting.LearnLibSettingsSource; +import net.automatalib.commons.util.WrapperUtil; import net.automatalib.commons.util.settings.SettingsSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,49 +56,39 @@ public > E getEnumValue(LearnLibProperty property, Class en } public > E getEnumValue(LearnLibProperty property, Class enumClazz) { - String prop = getProperty(property); - if (prop == null) { - return null; - } - // TODO: the assumption that enum constants are all-uppercase does not *always* hold! - return Enum.valueOf(enumClazz, prop.toUpperCase()); + return getTypedValue(property, p -> Enum.valueOf(enumClazz, p.toUpperCase())); } public boolean getBool(LearnLibProperty property, boolean defaultValue) { - Boolean b = getBoolean(property); - if (b != null) { - return b; - } - return defaultValue; + return WrapperUtil.booleanValue(getBoolean(property), defaultValue); } public Boolean getBoolean(LearnLibProperty property) { - String prop = getProperty(property); - if (prop != null) { - return Boolean.parseBoolean(prop); - } - return null; + return getTypedValue(property, Boolean::parseBoolean); } public int getInt(LearnLibProperty property, int defaultValue) { - Integer prop = getInteger(property); - if (prop != null) { - return prop; - } - return defaultValue; + return WrapperUtil.intValue(getInteger(property), defaultValue); } public Integer getInteger(LearnLibProperty property) { + return getTypedValue(property, Integer::parseInt); + } + + private T getTypedValue(LearnLibProperty property, Function valueExtractor) { String prop = getProperty(property); - if (prop != null) { - try { - return Integer.parseInt(prop); - } catch (NumberFormatException ex) { - LOG.warn("Could not parse LearnLib integer property '" + property + "'.", ex); - } + + if (prop == null) { + return null; + } + + try { + return valueExtractor.apply(prop); + } catch (IllegalArgumentException ex) { + LOG.warn("Could not parse LearnLib property '" + property + "'.", ex); + return null; } - return null; } } diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDiscriminationTree.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDiscriminationTree.java index 60d9f9511a..b083b618b3 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDiscriminationTree.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDiscriminationTree.java @@ -37,6 +37,7 @@ public AbstractWordBasedDiscriminationTree(AbstractWordBasedDTNode root super(root, oracle); } + @Override public AbstractWordBasedDTNode sift(AbstractWordBasedDTNode start, Word prefix) { AbstractWordBasedDTNode curr = start; diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java index be57aa6c1c..1f8324676b 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java @@ -98,10 +98,11 @@ private static void buildQueries(List> queryList, } } + @Override public List>> initialize(List> initialShortPrefixes, List> initialSuffixes, MembershipOracle oracle) { - if (allRows.size() > 0) { + if (!allRows.isEmpty()) { throw new IllegalStateException("Called initialize, but there are already rows present"); } @@ -254,14 +255,17 @@ private boolean processContents(RowImpl row, List rowContents, boolean mak return added; } + @Override public int numberOfDistinctRows() { return allRowContents.size(); } + @Override public List>> addSuffix(Word suffix, MembershipOracle oracle) { return addSuffixes(Collections.singletonList(suffix), oracle); } + @Override public List>> addSuffixes(Collection> newSuffixes, MembershipOracle oracle) { int oldSuffixCount = suffixes.size(); // we need a stable iteration order, and only List guarantees this @@ -338,10 +342,12 @@ public List>> addSuffixes(Collection> newSuffixes, return unclosed; } + @Override public boolean isInitialConsistencyCheckRequired() { return initialConsistencyCheckRequired; } + @Override public List>> addShortPrefixes(List> shortPrefixes, MembershipOracle oracle) { List> toSpRows = new ArrayList<>(); @@ -360,6 +366,7 @@ public List>> addShortPrefixes(List> shortPrefixes return toShortPrefixes(toSpRows, oracle); } + @Override public List>> toShortPrefixes(List> lpRows, MembershipOracle oracle) { List> freshSpRows = new ArrayList<>(); List> freshLpRows = new ArrayList<>(); @@ -461,31 +468,38 @@ private static void buildRowQueries(List> queryList, } } + @Override public D cellContents(Row row, int columnId) { List contents = rowContents(row); return contents.get(columnId); } + @Override public List rowContents(Row row) { return allRowContents.get(row.getRowContentId()); } + @Override public RowImpl getRow(int rowId) { return allRows.get(rowId); } + @Override public int numberOfRows() { return shortPrefixRows.size() + longPrefixRows.size(); } + @Override public List> getSuffixes() { return suffixes; } + @Override public boolean isInitialized() { - return (allRows.size() > 0); + return !allRows.isEmpty(); } + @Override public Alphabet getInputAlphabet() { return alphabet; } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/RowImpl.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/RowImpl.java index 0cba0a4d52..02636f57e9 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/RowImpl.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/RowImpl.java @@ -73,6 +73,7 @@ void makeShort(int initialAlphabetSize) { this.successors = new ResizingObjectArray(initialAlphabetSize); } + @Override @SuppressWarnings("unchecked") public RowImpl getSuccessor(int inputIdx) { return (RowImpl) successors.array[inputIdx]; @@ -91,14 +92,17 @@ void setSuccessor(int inputIdx, Row succ) { successors.array[inputIdx] = succ; } + @Override public Word getLabel() { return label; } + @Override public int getRowId() { return rowId; } + @Override public int getRowContentId() { return rowContentId; } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableWriter.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableWriter.java index c982fd71fd..0766acaa64 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableWriter.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableWriter.java @@ -35,7 +35,7 @@ default void write(ObservationTable table, @WillNotClo try { write(table, (Appendable) out); } catch (IOException ex) { - throw new AssertionError("Writing to PrintStream must not throw"); + throw new AssertionError("Writing to PrintStream must not throw", ex); } } @@ -43,7 +43,7 @@ default void write(ObservationTable table, @WillNotClo try { write(table, (Appendable) out); } catch (IOException ex) { - throw new AssertionError("Writing to StringBuilder must not throw"); + throw new AssertionError("Writing to StringBuilder must not throw", ex); } } diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Error.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Error.java index 76a0654f61..66218d9160 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Error.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Error.java @@ -22,7 +22,7 @@ * * @author falkhowar */ -public class Error extends AbstractMethodOutput { +public class Error extends MethodOutput { private final Throwable cause; diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/AbstractMethodOutput.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/MethodOutput.java similarity index 87% rename from drivers/basic/src/main/java/de/learnlib/drivers/reflect/AbstractMethodOutput.java rename to drivers/basic/src/main/java/de/learnlib/drivers/reflect/MethodOutput.java index 05f5653f27..59b3eb8098 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/AbstractMethodOutput.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/MethodOutput.java @@ -20,6 +20,9 @@ * * @author falk */ -public abstract class AbstractMethodOutput { +public class MethodOutput { + protected MethodOutput() { + // prevent public instantiation + } } diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ReturnValue.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ReturnValue.java index 6778337f9d..f1eff98179 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ReturnValue.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ReturnValue.java @@ -22,7 +22,7 @@ * * @author falkhowar */ -public class ReturnValue extends AbstractMethodOutput { +public class ReturnValue extends MethodOutput { private final Object ret; diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/SimplePOJODataMapper.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/SimplePOJODataMapper.java index c8df265dd7..059a90b19e 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/SimplePOJODataMapper.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/SimplePOJODataMapper.java @@ -28,7 +28,7 @@ * * @author falkhowar */ -public class SimplePOJODataMapper implements SULMapper { +public class SimplePOJODataMapper implements SULMapper { private final Constructor initMethod; private final Object[] initParams; @@ -57,7 +57,7 @@ public void post() { } @Override - public MappedException mapUnwrappedException(RuntimeException exception) + public MappedException mapUnwrappedException(RuntimeException exception) throws RuntimeException { return MappedException.repeatOutput(new Error(exception.getCause()), Unobserved.INSTANCE); } @@ -70,7 +70,7 @@ public ConcreteMethodInput mapInput(MethodInput abstractInput) { } @Override - public AbstractMethodOutput mapOutput(Object concreteOutput) { + public MethodOutput mapOutput(Object concreteOutput) { return new ReturnValue(concreteOutput); } @@ -80,7 +80,7 @@ public boolean canFork() { } @Override - public SULMapper fork() { + public SULMapper fork() { return new SimplePOJODataMapper(initMethod, initParams); } diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/SimplePOJOTestDriver.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/SimplePOJOTestDriver.java index b3bdd39126..fff7293668 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/SimplePOJOTestDriver.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/SimplePOJOTestDriver.java @@ -32,7 +32,7 @@ * @author falkhowar */ public final class SimplePOJOTestDriver - extends TestDriver { + extends TestDriver { private final GrowingAlphabet inputs = new SimpleAlphabet<>(); diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Unobserved.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Unobserved.java index 09edc5ea42..1d83a79755 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Unobserved.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Unobserved.java @@ -21,7 +21,7 @@ * * @author falkhowar */ -public final class Unobserved extends AbstractMethodOutput { +public final class Unobserved extends MethodOutput { public static final Unobserved INSTANCE = new Unobserved(); diff --git a/drivers/basic/src/test/java/de/learnlib/drivers/reflect/ObjectTest.java b/drivers/basic/src/test/java/de/learnlib/drivers/reflect/ObjectTest.java index 342d675205..73000f7cb9 100644 --- a/drivers/basic/src/test/java/de/learnlib/drivers/reflect/ObjectTest.java +++ b/drivers/basic/src/test/java/de/learnlib/drivers/reflect/ObjectTest.java @@ -37,9 +37,9 @@ public void testDriver() throws Exception { final StackData testCase = buildStackData(StackWithException.class); // push1, push2, pop, pop, pop, pop - final Word output1 = answerFirstQuery(testCase); + final Word output1 = answerFirstQuery(testCase); // push1, push2, push1, pop - final Word output2 = answerSecondQuery(testCase); + final Word output2 = answerSecondQuery(testCase); Assert.assertTrue(output1.getSymbol(0) instanceof ReturnValue); Assert.assertTrue(output1.getSymbol(1) instanceof ReturnValue); @@ -60,35 +60,35 @@ public void testDriver2() throws Exception { final StackData testCase = buildStackData(StackWithNull.class); // push1, push2, pop, pop, pop, pop - final Word output1 = answerFirstQuery(testCase); + final Word output1 = answerFirstQuery(testCase); // push1, push2, push1, pop - final Word output2 = answerSecondQuery(testCase); + final Word output2 = answerSecondQuery(testCase); - for (AbstractMethodOutput out : output1) { + for (MethodOutput out : output1) { Assert.assertTrue(out instanceof ReturnValue); } - for (AbstractMethodOutput out : output2) { + for (MethodOutput out : output2) { Assert.assertTrue(out instanceof ReturnValue); } } - private Word answerFirstQuery(StackData stackData) { + private Word answerFirstQuery(StackData stackData) { // push1, push2, pop, pop, pop, pop return answerQuery(stackData, 0, 1, 2, 2, 2, 2); } - private Word answerSecondQuery(StackData stackData) { + private Word answerSecondQuery(StackData stackData) { // push1, push2, push1, pop return answerQuery(stackData, 0, 1, 0, 2); } - private Word answerQuery(StackData stackData, int... inputIndexes) { + private Word answerQuery(StackData stackData, int... inputIndexes) { final Alphabet alphabet = stackData.driver.getInputs(); - SULOracle oracle = stackData.oracle; + SULOracle oracle = stackData.oracle; final WordBuilder wb = new WordBuilder<>(inputIndexes.length); @@ -102,7 +102,7 @@ private Word answerQuery(StackData stackData, int... input private StackData buildStackData(final Class stackClass) throws NoSuchMethodException { Constructor c = stackClass.getConstructor(int.class); SimplePOJOTestDriver driver = new SimplePOJOTestDriver(c, 2); - SULOracle oracle = new SULOracle<>(driver); + SULOracle oracle = new SULOracle<>(driver); Method push = stackClass.getMethod("push", Object.class); driver.addInput("push_1", push, 1); @@ -117,9 +117,9 @@ private StackData buildStackData(final Class stackClass) throws NoSuchMethodE private static class StackData { private final SimplePOJOTestDriver driver; - private final SULOracle oracle; + private final SULOracle oracle; - StackData(SimplePOJOTestDriver driver, SULOracle oracle) { + StackData(SimplePOJOTestDriver driver, SULOracle oracle) { this.driver = driver; this.oracle = oracle; } diff --git a/examples/src/main/java/de/learnlib/examples/example2/Example.java b/examples/src/main/java/de/learnlib/examples/example2/Example.java index 511af226ba..28bf6ef190 100644 --- a/examples/src/main/java/de/learnlib/examples/example2/Example.java +++ b/examples/src/main/java/de/learnlib/examples/example2/Example.java @@ -28,8 +28,8 @@ import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; import de.learnlib.api.statistic.StatisticSUL; -import de.learnlib.drivers.reflect.AbstractMethodOutput; import de.learnlib.drivers.reflect.MethodInput; +import de.learnlib.drivers.reflect.MethodOutput; import de.learnlib.drivers.reflect.SimplePOJOTestDriver; import de.learnlib.filter.cache.sul.SULCaches; import de.learnlib.filter.statistic.sul.ResetCounterSUL; @@ -75,14 +75,14 @@ public static void main(String[] args) throws NoSuchMethodException, IOException MethodInput poll = driver.addInput("poll", mPoll); // oracle for counting queries wraps sul - StatisticSUL statisticSul = + StatisticSUL statisticSul = new ResetCounterSUL<>("membership queries", driver); - SUL effectiveSul = statisticSul; + SUL effectiveSul = statisticSul; // use caching in order to avoid duplicate queries effectiveSul = SULCaches.createCache(driver.getInputs(), effectiveSul); - SULOracle mqOracle = new SULOracle<>(effectiveSul); + SULOracle mqOracle = new SULOracle<>(effectiveSul); // create initial set of suffixes List> suffixes = new ArrayList<>(); @@ -93,14 +93,14 @@ public static void main(String[] args) throws NoSuchMethodException, IOException // construct L* instance (almost classic Mealy version) // almost: we use words (Word) in cells of the table // instead of single outputs. - MealyLearner lstar = - new ExtensibleLStarMealyBuilder().withAlphabet(driver.getInputs()) // input alphabet - .withOracle(mqOracle) // membership oracle - .withInitialSuffixes(suffixes) // initial suffixes - .create(); + MealyLearner lstar = + new ExtensibleLStarMealyBuilder().withAlphabet(driver.getInputs()) // input alphabet + .withOracle(mqOracle) // membership oracle + .withInitialSuffixes(suffixes) // initial suffixes + .create(); // create random walks equivalence test - MealyEquivalenceOracle randomWalks = + MealyEquivalenceOracle randomWalks = new RandomWalkEQOracle<>(driver, // system under learning RESET_PROBABILITY, // reset SUL w/ this probability before a step MAX_STEPS, // max steps (overall) @@ -112,7 +112,7 @@ public static void main(String[] args) throws NoSuchMethodException, IOException // the learning algorithm and the random walks test. // The experiment will execute the main loop of // active learning - MealyExperiment experiment = + MealyExperiment experiment = new MealyExperiment<>(lstar, randomWalks, driver.getInputs()); // turn on time profiling @@ -125,7 +125,7 @@ public static void main(String[] args) throws NoSuchMethodException, IOException experiment.run(); // get learned model - MealyMachine result = experiment.getFinalHypothesis(); + MealyMachine result = experiment.getFinalHypothesis(); // report results System.out.println("-------------------------------------------------------"); diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java index 254a91f378..132afde5af 100644 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java +++ b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java @@ -73,11 +73,6 @@ public abstract class AbstractLTSminLTL string2Input; - /** - * Whether or not we made sure the LTSmin binaries can be run. - */ - private static boolean binariesChecked; - /** * Constructs a new AbstractLTSminLTL. * @@ -95,11 +90,8 @@ protected AbstractLTSminLTL(boolean keepFiles, this.keepFiles = keepFiles; this.string2Input = string2Input; - if (!binariesChecked) { - if (!LTSminUtil.checkUsable()) { - throw new ModelCheckingException("LTSmin binary could not be executed correctly"); - } - binariesChecked = true; + if (!LazyBinaryChecker.AVAILABLE) { + throw new ModelCheckingException("LTSmin binary could not be executed correctly"); } } @@ -277,7 +269,24 @@ public final L findCounterExample(A hypothesis, Collection inputs, return result; } - public static class BuilderDefaults { + /** + * Lazy holder for checking availability of LTSMin binary. See + * + * Initialization-on-demand holder idiom + */ + private static class LazyBinaryChecker { + + /** + * Whether or not we made sure the LTSmin binaries can be run. + */ + private static boolean AVAILABLE = LTSminUtil.checkUsable(); + } + + public static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } public static boolean keepFiles() { return false; diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/AbstractStatisticData.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/AbstractStatisticData.java index b7471fbf1a..29397f7568 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/AbstractStatisticData.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/AbstractStatisticData.java @@ -38,18 +38,22 @@ protected AbstractStatisticData(String name, String unit) { } @Nonnull + @Override public String getName() { return name; } @Nonnull + @Override public String getUnit() { return unit; } @Nonnull + @Override public abstract String getSummary(); @Nonnull + @Override public abstract String getDetails(); } diff --git a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracle.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracle.java index 8837dce983..c661cf239c 100644 --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracle.java +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracle.java @@ -78,7 +78,7 @@ public StaticParallelOracle(Collection> oracles @Nonnegative int minBatchSize, PoolPolicy policy) { - this.oracles = oracles.toArray(new MembershipOracle[oracles.size()]); + this.oracles = oracles.toArray(new MembershipOracle[0]); switch (policy) { case FIXED: diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFALearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFALearnerIT.java index 80e6e39dc4..15d6780449 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFALearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFALearnerIT.java @@ -37,7 +37,7 @@ * * @author Malte Isberner */ -public abstract class AbstractDFALearnerIT extends AbstractLearnerIT { +public abstract class AbstractDFALearnerIT { @Factory public Object[] createExampleITCases() { @@ -58,7 +58,7 @@ private List>> createAllVariantsI final DFALearnerVariantListImpl variants = new DFALearnerVariantListImpl<>(); addLearnerVariants(alphabet, example.getReferenceAutomaton().size(), mqOracle, variants); - return super.createExampleITCases(example, variants); + return LearnerITUtil.createExampleITCases(example, variants); } /** diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFAPassiveLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFAPassiveLearnerIT.java index 2c5b0ed0b0..bcdfcf9d96 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFAPassiveLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFAPassiveLearnerIT.java @@ -40,7 +40,7 @@ * * @author frohme */ -public abstract class AbstractDFAPassiveLearnerIT extends AbstractPassiveLearnerIT { +public abstract class AbstractDFAPassiveLearnerIT { @Factory public Object[] createExampleITCases() { @@ -67,7 +67,7 @@ private List>> createAllVa final PassiveLearningExample effectiveExample = new DefaultPassiveLearningExample<>(queries, alphabet); - return super.createPassiveExampleITCases(effectiveExample, variants); + return LearnerITUtil.createPassiveExampleITCases(effectiveExample, variants); } /** @@ -84,7 +84,7 @@ private List>> createAllVa */ protected Collection> generateSamplesInternal(Alphabet alphabet, DFA reference) { - return super.generateSamples(alphabet, reference); + return LearnerITUtil.generateSamples(alphabet, reference); } /** diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractLearnerIT.java deleted file mode 100644 index 85fe3d65f1..0000000000 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractLearnerIT.java +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.testsupport.it.learner; - -import java.util.ArrayList; -import java.util.List; - -import de.learnlib.examples.LearningExample; -import net.automatalib.automata.UniversalDeterministicAutomaton; -import net.automatalib.automata.concepts.SuffixOutput; - -/** - * Abstract integration test for a learning algorithm (or "learner"). - *

- * A learner integration test tests the functionality of a learning algorithm against a well-defined set of example - * setups. - *

- * This class most probably does not need to be subclassed directly. Instead, extend one of the existing subclasses. - * - * @author Malte Isberner - */ -public abstract class AbstractLearnerIT { - - /** - * Creates a list of per-example test cases for all learner variants. - * - * @return the list of test cases, one for each example - */ - protected & SuffixOutput> List> createExampleITCases( - LearningExample example, - LearnerVariantListImpl variants) { - - final List> variantList = variants.getLearnerVariants(); - final List> result = new ArrayList<>(variantList.size()); - - for (LearnerVariant variant : variantList) { - result.add(new LearnerVariantITCase<>(variant, example)); - } - - return result; - } - -} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java index fb612c205c..3cd3bc7333 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java @@ -38,7 +38,7 @@ * * @author Malte Isberner */ -public abstract class AbstractMealyLearnerIT extends AbstractLearnerIT { +public abstract class AbstractMealyLearnerIT { @Factory public Object[] createExampleITCases() { @@ -60,7 +60,7 @@ public Object[] createExampleITCases() { final MealyLearnerVariantListImpl variants = new MealyLearnerVariantListImpl<>(); addLearnerVariants(alphabet, mqOracle, variants); - return super.createExampleITCases(example, variants); + return LearnerITUtil.createExampleITCases(example, variants); } /** diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyPassiveLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyPassiveLearnerIT.java index b47833d922..3b8fa301da 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyPassiveLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyPassiveLearnerIT.java @@ -37,7 +37,7 @@ * * @author frohme */ -public abstract class AbstractMealyPassiveLearnerIT extends AbstractPassiveLearnerIT { +public abstract class AbstractMealyPassiveLearnerIT { @Factory public Object[] createExampleITCases() { @@ -57,7 +57,7 @@ public Object[] createExampleITCases() { final Alphabet alphabet = example.getAlphabet(); final MealyMachine reference = example.getReferenceAutomaton(); - Collection>> queries = super.generateSamples(alphabet, reference); + Collection>> queries = LearnerITUtil.generateSamples(alphabet, reference); final PassiveLearnerVariantListImpl, I, Word> variants = new PassiveLearnerVariantListImpl<>(); @@ -66,7 +66,7 @@ public Object[] createExampleITCases() { final PassiveLearningExample> effectiveExample = new DefaultPassiveLearningExample<>(queries, alphabet); - return super.createPassiveExampleITCases(effectiveExample, variants); + return LearnerITUtil.createPassiveExampleITCases(effectiveExample, variants); } /** diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java index bb8e21eb71..648e71fdc0 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java @@ -40,7 +40,7 @@ * * @author Malte Isberner */ -public abstract class AbstractMealySymLearnerIT extends AbstractLearnerIT { +public abstract class AbstractMealySymLearnerIT { @Factory public Object[] createExampleITCases() { @@ -62,7 +62,7 @@ public Object[] createExampleITCases() { final MealySymLearnerVariantListImpl variants = new MealySymLearnerVariantListImpl<>(); addLearnerVariants(alphabet, MealyUtil.wrapWordOracle(mqOracle), variants); - return super.createExampleITCases(example, variants.getMealyLearnerVariants()); + return LearnerITUtil.createExampleITCases(example, variants.getMealyLearnerVariants()); } /** diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractPassiveLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java similarity index 68% rename from test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractPassiveLearnerIT.java rename to test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java index 42a1cd8e66..873d229655 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractPassiveLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java @@ -21,34 +21,58 @@ import java.util.Random; import de.learnlib.api.query.DefaultQuery; +import de.learnlib.examples.LearningExample; import de.learnlib.examples.PassiveLearningExample; import net.automatalib.automata.UniversalAutomaton; +import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.SuffixOutput; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; + /** - * Abstract integration test for a passive learning algorithm (or "learner"). + * Utility class for integration tests for a learning algorithm (or "learner"). *

* A learner integration test tests the functionality of a learning algorithm against a well-defined set of example * setups. - *

- * This class most probably does not need to be subclassed directly. Instead, extend one of the existing subclasses. * - * @author frohme + * @author Malte Isberner */ -public abstract class AbstractPassiveLearnerIT { +public final class LearnerITUtil { private static final int MAX_LENGTH = 50; private static final int MAX_SIZE = 100; + private LearnerITUtil() { + // prevent instantiation + } + + /** + * Creates a list of per-example test cases for all learner variants. + * + * @return the list of test cases, one for each example + */ + public static & SuffixOutput> List> createExampleITCases( + LearningExample example, + LearnerVariantListImpl variants) { + + final List> variantList = variants.getLearnerVariants(); + final List> result = new ArrayList<>(variantList.size()); + + for (LearnerVariant variant : variantList) { + result.add(new LearnerVariantITCase<>(variant, example)); + } + + return result; + } + /** * Creates a list of per-example test cases for all learner variants (passive version). * * @return the list of test cases, one for each example */ - protected > List> createPassiveExampleITCases( + public static > List> createPassiveExampleITCases( PassiveLearningExample example, PassiveLearnerVariantListImpl variants) { @@ -62,7 +86,7 @@ protected > List & SuffixOutput> Collection> generateSamples( + public static & SuffixOutput> Collection> generateSamples( Alphabet alphabet, M reference) { @@ -87,5 +111,4 @@ protected > List Date: Sat, 9 Jun 2018 22:23:12 +0200 Subject: [PATCH 050/125] update code-analysis configurations - use new PMD categories - consolidate checkstyle and spotbugs exclusions --- .../learnlib-checkstyle-suppressions.xml | 1 - .../learnlib-pmd-exclusions.properties | 11 ++- .../main/resources/learnlib-pmd-ruleset.xml | 97 ++++++++++++------- .../learnlib-spotbugs-exclusions.xml | 6 -- 4 files changed, 71 insertions(+), 44 deletions(-) diff --git a/build-tools/src/main/resources/learnlib-checkstyle-suppressions.xml b/build-tools/src/main/resources/learnlib-checkstyle-suppressions.xml index ac8e241275..c6d2363703 100644 --- a/build-tools/src/main/resources/learnlib-checkstyle-suppressions.xml +++ b/build-tools/src/main/resources/learnlib-checkstyle-suppressions.xml @@ -20,7 +20,6 @@ limitations under the License. - diff --git a/build-tools/src/main/resources/learnlib-pmd-exclusions.properties b/build-tools/src/main/resources/learnlib-pmd-exclusions.properties index bb02e911e2..19f11a1071 100644 --- a/build-tools/src/main/resources/learnlib-pmd-exclusions.properties +++ b/build-tools/src/main/resources/learnlib-pmd-exclusions.properties @@ -21,21 +21,24 @@ de.learnlib.algorithms.adt.config.model.extender.DefaultExtender=EmptyCatchBlock de.learnlib.algorithms.dhc.mealy.MealyDHC=LooseCoupling de.learnlib.algorithms.dhc.mealy.MealyDHCState=LooseCoupling +# we don't perform arithmetic operations on Shorts, so usage is fine +de.learnlib.algorithms.kv.StateInfo=AvoidUsingShortType + # we want to store the size of the list before changing it de.learnlib.algorithms.nlstar.ObservationTable=PrematureDeclaration # ignore exception -de.learnlib.algorithms.ttt.base.AbstractTTTLearner=EmptyCatchBlock +de.learnlib.algorithms.ttt.base.AbstractTTTLearner=EmptyCatchBlock,ExcessiveClassLength # fine here, because we only receive the delegate logger during instantiation -de.learnlib.api.logging.Slf4jDelegator=LoggerIsNotStaticFinal +de.learnlib.api.logging.Slf4jDelegator=LoggerIsNotStaticFinal,MoreThanOneLogger # we want to store the size of the list before changing it de.learnlib.datastructure.observationtable.GenericObservationTable=PrematureDeclaration # RuntimeExceptions are the type of exceptions we allow to handle, therefore we should throw them -de.learnlib.drivers.reflect.ConcreteMethodInput=AvoidThrowingRawExceptionTypes -de.learnlib.drivers.reflect.SimplePOJODataMapper=AvoidThrowingRawExceptionTypes +de.learnlib.drivers.reflect.ConcreteMethodInput=AvoidThrowingRawExceptionTypes,PreserveStackTrace +de.learnlib.drivers.reflect.SimplePOJODataMapper=AvoidThrowingRawExceptionTypes,PreserveStackTrace # fine for exampels de.learnlib.examples.example1.Example=SystemPrintln diff --git a/build-tools/src/main/resources/learnlib-pmd-ruleset.xml b/build-tools/src/main/resources/learnlib-pmd-ruleset.xml index cfd4c0020b..2daa62d355 100644 --- a/build-tools/src/main/resources/learnlib-pmd-ruleset.xml +++ b/build-tools/src/main/resources/learnlib-pmd-ruleset.xml @@ -22,46 +22,77 @@ limitations under the License. LearnLib PMD ruleset - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - + + + - - - - - + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + - - - + + + + + + - - + + + - + + + \ No newline at end of file diff --git a/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml b/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml index 99909a9837..aed280d934 100644 --- a/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml +++ b/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml @@ -16,12 +16,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - - From ea9233f2042111ae358d5fbcdb22646296fce683 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 12 Jun 2018 13:00:41 +0200 Subject: [PATCH 051/125] cleanup: remove auto-inferable generics --- .../java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java | 2 +- .../de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java | 2 +- .../algorithms/lstar/AbstractExtensibleAutomatonLStar.java | 2 +- .../main/java/de/learnlib/algorithms/lstar/AbstractLStar.java | 2 +- .../de/learnlib/algorithms/lstar/dfa/ExtensibleLStarDFA.java | 2 +- .../learnlib/datastructures/writer/SuffixASCIIWriterTest.java | 3 +-- .../learnlib/oracle/equivalence/AbstractTestWordEQOracle.java | 2 +- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java index 1dc75413cb..f3ecebc128 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java @@ -203,7 +203,7 @@ private void initialize() { private StateInfo createInitialState(boolean accepting) { int state = hypothesis.addIntInitialState(accepting); - StateInfo si = new StateInfo<>(state, Word.epsilon()); + StateInfo si = new StateInfo<>(state, Word.epsilon()); assert stateInfos.size() == state; stateInfos.add(si); diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java index aa728ab6f4..1585505e01 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java @@ -209,7 +209,7 @@ private StateInfo> createInitialState() { int state = hypothesis.addIntInitialState(); assert state == stateInfos.size(); - StateInfo> stateInfo = new StateInfo<>(state, Word.epsilon()); + StateInfo> stateInfo = new StateInfo<>(state, Word.epsilon()); stateInfos.add(stateInfo); return stateInfo; diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java index ae9f2f173a..40c11626fa 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java @@ -80,7 +80,7 @@ private BuilderDefaults() { } public static List> initialPrefixes() { - return Collections.singletonList(Word.epsilon()); + return Collections.singletonList(Word.epsilon()); } public static List> initialSuffixes() { diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java index 0af041d97b..cedfade3cc 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java @@ -114,7 +114,7 @@ protected List>> incorporateCounterExample(DefaultQuery ce) { } protected List> initialPrefixes() { - return Collections.singletonList(Word.epsilon()); + return Collections.singletonList(Word.epsilon()); } /** diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/ExtensibleLStarDFA.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/ExtensibleLStarDFA.java index 9ae62a239e..4f8212b44a 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/ExtensibleLStarDFA.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/ExtensibleLStarDFA.java @@ -79,7 +79,7 @@ public ExtensibleLStarDFA(Alphabet alphabet, @Override protected List> initialSuffixes() { - return Collections.singletonList(Word.epsilon()); + return Collections.singletonList(Word.epsilon()); } @Override diff --git a/datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/SuffixASCIIWriterTest.java b/datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/SuffixASCIIWriterTest.java index 1e30584e21..f1233b85b4 100644 --- a/datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/SuffixASCIIWriterTest.java +++ b/datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/SuffixASCIIWriterTest.java @@ -52,8 +52,7 @@ public void testRead() { alphabet.add("A"); alphabet.add("B"); - ObservationTable parsedOt = - OTUtils.fromString(str, alphabet, new SuffixASCIIReader()); + ObservationTable parsedOt = OTUtils.fromString(str, alphabet, new SuffixASCIIReader<>()); Assert.assertEquals(ot.getSuffixes(), parsedOt.getSuffixes()); } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java index 5f970fb28a..86cdc24382 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java @@ -77,7 +77,7 @@ public DefaultQuery findCounterExample(A hypothesis, Collection> testWordStream = generateTestWords(hypothesis, inputs); - final Stream> queryStream = testWordStream.map(DefaultQuery::new); + final Stream> queryStream = testWordStream.map(DefaultQuery::new); final Stream> answeredQueryStream = answerQueries(queryStream); final Stream> ceStream = answeredQueryStream.filter(query -> { From f3c908f314b8421fcfdbbff2a306ce3fca6cdeef Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 12 Jun 2018 13:17:13 +0200 Subject: [PATCH 052/125] cleanup: use more idiomatic TestNg asserts --- .../util/src/test/java/de/learnlib/util/ExperimentTest.java | 4 ++-- .../de/learnlib/filter/reuse/test/DomainKnowledgeTest.java | 6 +++--- .../java/de/learnlib/filter/reuse/test/ReuseOracleTest.java | 4 ++-- .../learnlib/testsupport/AbstractResumableLearnerTest.java | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/commons/util/src/test/java/de/learnlib/util/ExperimentTest.java b/commons/util/src/test/java/de/learnlib/util/ExperimentTest.java index e47c9c6217..9892d8fa88 100644 --- a/commons/util/src/test/java/de/learnlib/util/ExperimentTest.java +++ b/commons/util/src/test/java/de/learnlib/util/ExperimentTest.java @@ -65,7 +65,7 @@ public void testExperiment() { DFA finalModel = experiment.getFinalHypothesis(); Assert.assertNotNull(experiment.getFinalHypothesis()); - Assert.assertTrue(finalModel == target); + Assert.assertSame(finalModel, target); Assert.assertTrue(learner.startLearningCalled); Assert.assertEquals(learner.refinementSteps, REFINEMENT_STEPS); @@ -120,7 +120,7 @@ private static final class MockUpOracle implements DFAEquivalenceOracle { @Override public DefaultQuery findCounterExample(DFA hypothesis, Collection inputs) { if (counterexamples < REFINEMENT_STEPS) { - Assert.assertTrue(hypothesis == intermediateTarget); + Assert.assertSame(hypothesis, intermediateTarget); counterexamples++; return new DefaultQuery<>(Word.epsilon(), true); diff --git a/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/DomainKnowledgeTest.java b/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/DomainKnowledgeTest.java index e98171163a..624be33f4e 100644 --- a/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/DomainKnowledgeTest.java +++ b/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/DomainKnowledgeTest.java @@ -90,7 +90,7 @@ public void testReuseNodePrefixWhileReusing() { Word input = getInput(1, 0, 1, 1); NodeResult node = reuseOracle.getReuseTree().fetchSystemState(input); - Assert.assertTrue(node.prefixLength == 3); // ''1 0 1'' + Assert.assertEquals(node.prefixLength, 3); // ''1 0 1'' // reuse the prefix qr = new QueryResult<>(getOutput("ok"), 3); reuseOracle.getReuseTree().insert(getInput(1), node.reuseNode, qr); @@ -102,7 +102,7 @@ public void testReuseNodePrefixWhileReusing() { // There should be a "1 1 1" system state, even this query was never seen node = reuseOracle.getReuseTree().fetchSystemState(getInput(1, 1, 1)); Assert.assertNotNull(node); - Assert.assertTrue(node.prefixLength == 3); // query "1 1 1" + Assert.assertEquals(node.prefixLength, 3); // query "1 1 1" // The system state is invalidated, so querying again "1 1 1" reveals null this time node = reuseOracle.getReuseTree().fetchSystemState(getInput(1, 1, 1)); @@ -111,7 +111,7 @@ public void testReuseNodePrefixWhileReusing() { // The output of "1 0 0 0 0 1 1" should be known, even the query was never seen Word output = reuseOracle.getReuseTree().getOutput(getInput(1, 0, 0, 0, 0, 1, 1)); Assert.assertNotNull(output); - Assert.assertTrue(output.size() == 7); + Assert.assertEquals(output.size(), 7); } private class NullReuseCapableFactory implements Supplier> { diff --git a/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/ReuseOracleTest.java b/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/ReuseOracleTest.java index 4aaffed9d3..e1bfcaa120 100644 --- a/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/ReuseOracleTest.java +++ b/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/ReuseOracleTest.java @@ -153,7 +153,7 @@ public void testReusePossible() { Integer systemState = node.systemState; Assert.assertNotNull(systemState); - Assert.assertTrue(systemState.equals(2)); + Assert.assertEquals((int) systemState, 2); // we have automatic invalidation, so the reuseNode already has system state set to null // and although querying again reveals nothing reusable @@ -183,7 +183,7 @@ public void testReusePossibleWithInvalidation() { // now we check query 112, reuse possible in 11 NodeResult node = reuseOracle.getReuseTree().fetchSystemState(getInput(1, 1, 2)); Assert.assertNotNull(node); - Assert.assertTrue(node.prefixLength == 2); // query '1 1' + Assert.assertEquals(node.prefixLength, 2); // query '1 1' qr = new ReuseCapableOracle.QueryResult<>(getOutput("ok"), 4); reuseOracle.getReuseTree().insert(getInput(2), node.reuseNode, qr); diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java index 50ed063a2b..d5530884d7 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java @@ -122,6 +122,6 @@ public void testSuspendAndResumeLearner() throws Exception { Automata.testEquivalence(learner.getHypothesisModel(), learner2.getHypothesisModel(), inputAlphabet); Assert.assertTrue(modelsAreEquivalent); - Assert.assertTrue(roundsPre - roundsPost == rounds); + Assert.assertEquals(roundsPre - roundsPost, rounds); } } From d99aefa800aba387248c035a92bff82a32c986ea Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 12 Jun 2018 14:30:54 +0200 Subject: [PATCH 053/125] oracles: Add test for checking batch sizes of TestWordEQOracles --- .../TestWordEQOracleBatchTest.java | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/TestWordEQOracleBatchTest.java diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/TestWordEQOracleBatchTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/TestWordEQOracleBatchTest.java new file mode 100644 index 0000000000..df40f2fead --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/TestWordEQOracleBatchTest.java @@ -0,0 +1,107 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Collection; +import java.util.Collections; +import java.util.stream.Stream; + +import javax.annotation.Nullable; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.query.Query; +import net.automatalib.automata.concepts.Output; +import net.automatalib.words.Word; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * Test for size of batch generation of {@link AbstractTestWordEQOracle}. + * + * @author frohme + */ +public class TestWordEQOracleBatchTest { + + private static final int BATCH_SIZE = 20; + private static final int EXPECTED_NUM_OF_QUERIES = 60; + private static final int MAX_QUERIES = 100; + private static final int THRESHOLD = 47; + + @Test + public void testBatchMode() { + final DummyMQOracle mOracle = new DummyMQOracle<>(); + final DummyEQOracle eqOracle = new DummyEQOracle<>(mOracle); + final DummyHypothesis hyp = new DummyHypothesis<>(); + + eqOracle.findCounterExample(hyp, Collections.singleton('a')); + + Assert.assertEquals(mOracle.getQueryCounter(), EXPECTED_NUM_OF_QUERIES); + Assert.assertEquals(eqOracle.getGeneratedWordsCounter(), EXPECTED_NUM_OF_QUERIES); + Assert.assertEquals(hyp.getQueryCounter(), THRESHOLD); + } + + private static class DummyHypothesis implements Output { + + private int queryCounter; + + int getQueryCounter() { + return queryCounter; + } + + @Nullable + @Override + public Boolean computeOutput(Iterable input) { + queryCounter++; + + return queryCounter >= THRESHOLD ? Boolean.TRUE : null; + } + } + + private static class DummyMQOracle implements DFAMembershipOracle { + + private int queryCounter; + + int getQueryCounter() { + return queryCounter; + } + + @Override + public void processQueries(Collection> queries) { + queryCounter += queries.size(); + } + } + + private static class DummyEQOracle extends AbstractTestWordEQOracle, I, Boolean> { + + private int generatedWordsCounter; + + DummyEQOracle(MembershipOracle membershipOracle) { + super(membershipOracle, BATCH_SIZE); + } + + int getGeneratedWordsCounter() { + return generatedWordsCounter; + } + + @Override + protected Stream> generateTestWords(Output hypothesis, Collection inputs) { + final I sym = inputs.iterator().next(); + return Stream.generate(() -> Word.fromLetter(sym)).peek((w) -> generatedWordsCounter++).limit(MAX_QUERIES); + } + } + +} From 5629a3a2f8587a890af9eec4993f595c70809956 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 12 Jun 2018 16:07:06 +0200 Subject: [PATCH 054/125] datastructure/ot: cleanup + tests - added default implementation for #cellContents - removed unused NoSuchRowException exception - cleaned up JavaDoc - added tests for OT writers --- .../GenericObservationTable.java | 6 - .../observationtable/NoSuchRowException.java | 29 ----- .../observationtable/ObservationTable.java | 7 +- .../reader/SimpleObservationTable.java | 5 +- .../MockedObservationTable.java | 114 ++++++++++++++++++ .../ObservationTableSource.java | 27 +++-- .../writer/ObservationTableWriterTest.java | 68 +++++++++++ .../writer/SuffixASCIIWriterTest.java | 5 +- .../src/test/resources/OT_ASCII.txt | 9 ++ .../src/test/resources/OT_HTML.html | 11 ++ 10 files changed, 229 insertions(+), 52 deletions(-) delete mode 100644 datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/NoSuchRowException.java create mode 100644 datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/MockedObservationTable.java rename datastructures/observation-table/src/test/java/de/learnlib/{datastructures/writer/otsource => datastructure/observationtable}/ObservationTableSource.java (63%) create mode 100644 datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/writer/ObservationTableWriterTest.java rename datastructures/observation-table/src/test/java/de/learnlib/{datastructures => datastructure/observationtable}/writer/SuffixASCIIWriterTest.java (92%) create mode 100644 datastructures/observation-table/src/test/resources/OT_ASCII.txt create mode 100644 datastructures/observation-table/src/test/resources/OT_HTML.html diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java index 1f8324676b..4ce640bbbc 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java @@ -468,12 +468,6 @@ private static void buildRowQueries(List> queryList, } } - @Override - public D cellContents(Row row, int columnId) { - List contents = rowContents(row); - return contents.get(columnId); - } - @Override public List rowContents(Row row) { return allRowContents.get(row.getRowContentId()); diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/NoSuchRowException.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/NoSuchRowException.java deleted file mode 100644 index acf922ce5d..0000000000 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/NoSuchRowException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.datastructure.observationtable; - -public class NoSuchRowException extends IllegalArgumentException { - - private static final long serialVersionUID = 1L; - - public NoSuchRowException() { - } - - public NoSuchRowException(String s) { - super(s); - } - -} diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/ObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/ObservationTable.java index 1c255bd929..2da6745fb4 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/ObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/ObservationTable.java @@ -235,9 +235,6 @@ default Word findDistinguishingSuffix(Row row1, Row row2) { /** * @return the suffix (column) index where the contents of the rows differ, or {@code #NO_DISTINGUISHING_SUFFIX} if * the contents of the rows are equal. - * - * @throws NoSuchRowException - * if the */ @Signed default int findDistinguishingSuffixIndex(Inconsistency inconsistency) { @@ -333,6 +330,8 @@ default Row getRowSuccessor(Row row, I sym) { List rowContents(Row row); - D cellContents(Row row, int columnId); + default D cellContents(Row row, int columnId) { + return rowContents(row).get(columnId); + } } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/reader/SimpleObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/reader/SimpleObservationTable.java index 8b1e07bed0..503a208a51 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/reader/SimpleObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/reader/SimpleObservationTable.java @@ -22,7 +22,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import de.learnlib.datastructure.observationtable.NoSuchRowException; import de.learnlib.datastructure.observationtable.OTUtils; import de.learnlib.datastructure.observationtable.ObservationTable; import de.learnlib.datastructure.observationtable.Row; @@ -68,8 +67,8 @@ public Row getRow(int idx) { @Nonnull @Override - public Row getRow(Word prefix) throws NoSuchRowException { - throw new NoSuchRowException(); + public Row getRow(Word prefix) { + throw new UnsupportedOperationException(); } @Override diff --git a/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/MockedObservationTable.java b/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/MockedObservationTable.java new file mode 100644 index 0000000000..7cbb0cb11e --- /dev/null +++ b/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/MockedObservationTable.java @@ -0,0 +1,114 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.observationtable; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.google.common.base.Preconditions; +import de.learnlib.datastructure.observationtable.reader.SimpleObservationTable; +import net.automatalib.words.Word; + +/** + * Mock-up observation table for testing writers. + * + * @param + * input symbol type + * @param + * observation (output) domain type + * + * @author frohme + */ +public class MockedObservationTable extends SimpleObservationTable { + + private final Map, Integer> contentsToIdMap; + private final List> rowContents; + + private final List> rows; + private final List> shortPrefixes; + private final List> longPrefixes; + + MockedObservationTable(List> suffixes) { + super(suffixes); + this.rowContents = new LinkedList<>(); + this.contentsToIdMap = new HashMap<>(); + + this.rows = new LinkedList<>(); + this.shortPrefixes = new LinkedList<>(); + this.longPrefixes = new LinkedList<>(); + } + + void addShortPrefix(final Word prefix, List contents) { + shortPrefixes.add(addPrefix(prefix, contents)); + } + + void addLongPrefix(final Word prefix, List contents) { + longPrefixes.add(addPrefix(prefix, contents)); + } + + private RowImpl addPrefix(final Word prefix, List contents) { + Preconditions.checkArgument(getSuffixes().size() == contents.size()); + + final RowImpl row = new RowImpl<>(prefix, rows.size()); + + final int contentId = contentsToIdMap.computeIfAbsent(contents, k -> { + rowContents.add(k); + return contentsToIdMap.size(); + }); + + row.setRowContentId(contentId); + rows.add(row); + + return row; + } + + @Nonnull + @Override + public Collection> getShortPrefixRows() { + return Collections.unmodifiableList(shortPrefixes); + } + + @Nonnull + @Override + public Collection> getLongPrefixRows() { + return Collections.unmodifiableList(longPrefixes); + } + + @Nullable + @Override + public RowImpl getRow(int idx) { + Preconditions.checkPositionIndex(0, rows.size()); + return rows.get(idx); + } + + @Override + public int numberOfDistinctRows() { + return contentsToIdMap.size(); + } + + @Override + public List rowContents(Row row) { + return this.rowContents.get(this.getRow(row.getRowId()).getRowContentId()); + } + +} diff --git a/datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/otsource/ObservationTableSource.java b/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/ObservationTableSource.java similarity index 63% rename from datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/otsource/ObservationTableSource.java rename to datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/ObservationTableSource.java index 5eb985f4a5..916751d10c 100644 --- a/datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/otsource/ObservationTableSource.java +++ b/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/ObservationTableSource.java @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.datastructures.writer.otsource; +package de.learnlib.datastructure.observationtable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import de.learnlib.datastructure.observationtable.ObservationTable; -import de.learnlib.datastructure.observationtable.reader.SimpleObservationTable; import net.automatalib.words.Word; /** @@ -35,8 +34,12 @@ public static ObservationTable otWithFourSuffixes() { suffixes.add(Word.epsilon()); suffixes.add(Word.fromLetter("A")); suffixes.add(Word.fromLetter("B")); - suffixes.add(Word.fromLetter("A").concat(Word.fromLetter("B"))); - return new SimpleObservationTable<>(suffixes); + suffixes.add(Word.fromSymbols("A", "B")); + + final MockedObservationTable result = new MockedObservationTable<>(suffixes); + addPrefixes(result); + + return result; } public static ObservationTable otWithFourSuffixesUsingDelimiterInNames() { @@ -44,8 +47,18 @@ public static ObservationTable otWithFourSuffixesUsingDelimiterI suffixes.add(Word.epsilon()); suffixes.add(Word.fromLetter("A,")); suffixes.add(Word.fromLetter("B")); - suffixes.add(Word.fromLetter("A,").concat(Word.fromLetter("B"))); - return new SimpleObservationTable<>(suffixes); + suffixes.add(Word.fromSymbols("A,", "B")); + + final MockedObservationTable result = new MockedObservationTable<>(suffixes); + addPrefixes(result); + + return result; + } + + private static void addPrefixes(MockedObservationTable ot) { + ot.addShortPrefix(Word.fromLetter("A"), Arrays.asList("0", "1", "2", "3")); + ot.addShortPrefix(Word.fromSymbols("A", "B"), Arrays.asList("3", "2", "1", "0")); + ot.addLongPrefix(Word.fromSymbols("A", "B", "C"), Arrays.asList("0123", "0123", "0123", "0123")); } } diff --git a/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/writer/ObservationTableWriterTest.java b/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/writer/ObservationTableWriterTest.java new file mode 100644 index 0000000000..53cad9e20c --- /dev/null +++ b/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/writer/ObservationTableWriterTest.java @@ -0,0 +1,68 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.observationtable.writer; + +import java.io.IOException; +import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +import de.learnlib.datastructure.observationtable.ObservationTable; +import de.learnlib.datastructure.observationtable.ObservationTableSource; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class ObservationTableWriterTest { + + @Test + public void testWriteASCII() throws URISyntaxException, IOException { + + final ObservationTableASCIIWriter writer = + new ObservationTableASCIIWriter<>(input -> String.join(" ", input), output -> "out: " + output, true); + + testInternal(writer, "/OT_ASCII.txt"); + } + + @Test + public void testWriteHTML() throws URISyntaxException, IOException { + + final ObservationTableHTMLWriter writer = + new ObservationTableHTMLWriter<>(input -> String.join(" ", input), output -> "out: " + output); + + testInternal(writer, "/OT_HTML.html"); + } + + private static void testInternal(AbstractObservationTableWriter writer, String urlOfExpectedResult) + throws URISyntaxException, IOException { + + final ObservationTable ot = ObservationTableSource.otWithFourSuffixes(); + + final StringWriter writerResult = new StringWriter(); + writer.write(ot, writerResult); + + final URI testResource = ObservationTableWriterTest.class.getResource(urlOfExpectedResult).toURI(); + final String expectedResult = new String(Files.readAllBytes(Paths.get(testResource)), StandardCharsets.UTF_8); + + Assert.assertEquals(writerResult.toString(), expectedResult); + } + +} diff --git a/datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/SuffixASCIIWriterTest.java b/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/writer/SuffixASCIIWriterTest.java similarity index 92% rename from datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/SuffixASCIIWriterTest.java rename to datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/writer/SuffixASCIIWriterTest.java index f1233b85b4..b8e0115b9b 100644 --- a/datastructures/observation-table/src/test/java/de/learnlib/datastructures/writer/SuffixASCIIWriterTest.java +++ b/datastructures/observation-table/src/test/java/de/learnlib/datastructure/observationtable/writer/SuffixASCIIWriterTest.java @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.datastructures.writer; +package de.learnlib.datastructure.observationtable.writer; import de.learnlib.datastructure.observationtable.OTUtils; import de.learnlib.datastructure.observationtable.ObservationTable; +import de.learnlib.datastructure.observationtable.ObservationTableSource; import de.learnlib.datastructure.observationtable.reader.SuffixASCIIReader; -import de.learnlib.datastructure.observationtable.writer.SuffixASCIIWriter; -import de.learnlib.datastructures.writer.otsource.ObservationTableSource; import net.automatalib.words.Alphabet; import net.automatalib.words.impl.SimpleAlphabet; import org.testng.Assert; diff --git a/datastructures/observation-table/src/test/resources/OT_ASCII.txt b/datastructures/observation-table/src/test/resources/OT_ASCII.txt new file mode 100644 index 0000000000..549017c750 --- /dev/null +++ b/datastructures/observation-table/src/test/resources/OT_ASCII.txt @@ -0,0 +1,9 @@ ++=======+===========+===========+===========+===========+ +| | | A | B | A B | ++=======+===========+===========+===========+===========+ +| A | out: 0 | out: 1 | out: 2 | out: 3 | ++-------+-----------+-----------+-----------+-----------+ +| A B | out: 3 | out: 2 | out: 1 | out: 0 | ++=======+===========+===========+===========+===========+ +| A B C | out: 0123 | out: 0123 | out: 0123 | out: 0123 | ++=======+===========+===========+===========+===========+ diff --git a/datastructures/observation-table/src/test/resources/OT_HTML.html b/datastructures/observation-table/src/test/resources/OT_HTML.html new file mode 100644 index 0000000000..3c08eaeb67 --- /dev/null +++ b/datastructures/observation-table/src/test/resources/OT_HTML.html @@ -0,0 +1,11 @@ + + + + + + + + + + +
PrefixSuffixes
ABA B
Aout: 0out: 1out: 2out: 3
A Bout: 3out: 2out: 1out: 0
A B Cout: 0123out: 0123out: 0123out: 0123
From 36f3ebc3f50392ca98dd02a0f745a08bba76c19e Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 14 Jun 2018 16:40:31 +0200 Subject: [PATCH 055/125] oracles: some cleanups + tests - the RandomWellMatchedWordsEQOracle now uses the alphabet passed in the #findCounterexample method to generate test words - DFA/Mealy variants of the CompleteExplorationEQOracle now directly inherit from/delegate to super class - added tests for RandomWord and SampleSet EQ oracles (with more to come) --- .../CompleteExplorationEQOracle.java | 63 +++------- .../equivalence/EquivalenceQueries.java | 24 ++-- .../equivalence/RandomWordsEQOracle.java | 9 +- .../oracle/equivalence/WpMethodEQOracle.java | 2 +- .../vpda/RandomWellMatchedWordsEQOracle.java | 49 ++++---- .../equivalence/AbstractEQOracleTest.java | 94 +++++++++++++++ .../RandomWMethodEQOracleTest.java | 85 +++++++++++++ .../equivalence/RandomWordsEQOracleTest.java | 84 +++++++++++++ .../equivalence/SampleSetEQOracleTest.java | 96 +++++++++++++++ .../RandomWellMatchedWordsEQOracleTest.java | 113 ++++++++++++++++++ 10 files changed, 529 insertions(+), 90 deletions(-) create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractEQOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWordsEQOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/SampleSetEQOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracleTest.java diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java index bcf776b402..6728cbe7d0 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java @@ -37,7 +37,7 @@ * * @author Malte Isberner */ -public class CompleteExplorationEQOracle extends AbstractTestWordEQOracle, I, D> { +public class CompleteExplorationEQOracle, I, D> extends AbstractTestWordEQOracle { private final int minDepth; private final int maxDepth; @@ -87,81 +87,46 @@ public CompleteExplorationEQOracle(MembershipOracle sulOracle, int minDept } @Override - protected Stream> generateTestWords(Output hypothesis, - Collection inputs) { + protected Stream> generateTestWords(A hypothesis, Collection inputs) { return Streams.stream(CollectionsUtil.allTuples(inputs, minDepth, maxDepth)).map(Word::fromList); } - public static class DFACompleteExplorationEQOracle - extends AbstractTestWordEQOracle, I, Boolean> + public static class DFACompleteExplorationEQOracle extends CompleteExplorationEQOracle, I, Boolean> implements DFAEquivalenceOracle { - private final CompleteExplorationEQOracle delegate; - - public DFACompleteExplorationEQOracle(MembershipOracle mqOracle, - int maxDepth) { - super(mqOracle); - this.delegate = new CompleteExplorationEQOracle<>(mqOracle, maxDepth); + public DFACompleteExplorationEQOracle(MembershipOracle mqOracle, int maxDepth) { + super(mqOracle, maxDepth); } - public DFACompleteExplorationEQOracle(MembershipOracle mqOracle, - int minDepth, - int maxDepth) { - super(mqOracle); - this.delegate = new CompleteExplorationEQOracle<>(mqOracle, minDepth, maxDepth); + public DFACompleteExplorationEQOracle(MembershipOracle mqOracle, int minDepth, int maxDepth) { + super(mqOracle, minDepth, maxDepth); } public DFACompleteExplorationEQOracle(MembershipOracle mqOracle, int minDepth, int maxDepth, int batchSize) { - super(mqOracle, batchSize); - this.delegate = new CompleteExplorationEQOracle<>(mqOracle, minDepth, maxDepth, batchSize); + super(mqOracle, minDepth, maxDepth, batchSize); } - - @Override - protected Stream> generateTestWords(DFA hypothesis, - Collection inputs) { - return delegate.generateTestWords(hypothesis, inputs); - } - } public static class MealyCompleteExplorationEQOracle - extends AbstractTestWordEQOracle, I, Word> + extends CompleteExplorationEQOracle, I, Word> implements MealyEquivalenceOracle { - private final CompleteExplorationEQOracle> delegate; - - public MealyCompleteExplorationEQOracle(MembershipOracle> mqOracle, - int maxDepth) { - super(mqOracle); - this.delegate = new CompleteExplorationEQOracle<>(mqOracle, maxDepth); + public MealyCompleteExplorationEQOracle(MembershipOracle> mqOracle, int maxDepth) { + super(mqOracle, maxDepth); } - public MealyCompleteExplorationEQOracle(MembershipOracle> mqOracle, - int minDepth, - int maxDepth) { - super(mqOracle); - this.delegate = new CompleteExplorationEQOracle<>(mqOracle, - minDepth, maxDepth); + public MealyCompleteExplorationEQOracle(MembershipOracle> mqOracle, int minDepth, int maxDepth) { + super(mqOracle, minDepth, maxDepth); } public MealyCompleteExplorationEQOracle(MembershipOracle> mqOracle, int minDepth, int maxDepth, int batchSize) { - super(mqOracle, batchSize); - this.delegate = new CompleteExplorationEQOracle<>(mqOracle, minDepth, maxDepth, batchSize); - } - - @Override - protected Stream> generateTestWords(MealyMachine hypothesis, - Collection inputs) { - return delegate.generateTestWords(hypothesis, inputs); + super(mqOracle, minDepth, maxDepth, batchSize); } - } - - } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EquivalenceQueries.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EquivalenceQueries.java index 1ea7e203c5..373a87104c 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EquivalenceQueries.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EquivalenceQueries.java @@ -25,28 +25,32 @@ private EquivalenceQueries() { // prevent instantiation } - public static , I, D> RandomWordsEQOracle - randomWords(MembershipOracle sulOracle, int minLength, int maxLength, int maxTests) { + public static , I, D> RandomWordsEQOracle randomWords(MembershipOracle sulOracle, + int minLength, + int maxLength, + int maxTests) { return new RandomWordsEQOracle<>(sulOracle, minLength, maxLength, maxTests); } - public static CompleteExplorationEQOracle - complete(MembershipOracle sulOracle, int maxDepth) { + public static , I, D> CompleteExplorationEQOracle complete(MembershipOracle sulOracle, + int maxDepth) { return new CompleteExplorationEQOracle<>(sulOracle, maxDepth); } - public static & Output, I, D> WMethodEQOracle - wMethod(MembershipOracle sulOracle, int maxDepth) { + public static & Output, I, D> WMethodEQOracle wMethod( + MembershipOracle sulOracle, + int maxDepth) { return new WMethodEQOracle<>(sulOracle, maxDepth); } - public static & Output, I, D> WpMethodEQOracle - wpMethod(MembershipOracle sulOracle, int maxDepth) { + public static & Output, I, D> WpMethodEQOracle wpMethod( + MembershipOracle sulOracle, + int maxDepth) { return new WpMethodEQOracle<>(sulOracle, maxDepth); } - public static & Output, I, D> SimulatorEQOracle - simulator(A target) { + public static & Output, I, D> SimulatorEQOracle simulator( + A target) { return new SimulatorEQOracle<>(target); } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java index fc27a8fb72..21d4feba0b 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java @@ -15,7 +15,6 @@ */ package de.learnlib.oracle.equivalence; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; @@ -25,6 +24,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.commons.util.collections.CollectionsUtil; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; @@ -69,12 +69,7 @@ public RandomWordsEQOracle(MembershipOracle mqOracle, @Override protected Stream> generateTestWords(A hypothesis, Collection inputs) { - final List symbolList; - if (inputs instanceof List) { - symbolList = (List) inputs; - } else { - symbolList = new ArrayList<>(inputs); - } + final List symbolList = CollectionsUtil.randomAccessList(inputs); return Stream.generate(() -> generateTestWord(symbolList, symbolList.size())).limit(maxTests); } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java index 4b019e3a75..c8424f04e2 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java @@ -51,7 +51,7 @@ public class WpMethodEQOracle sulOracle, int maxDepth) { this(sulOracle, maxDepth, 1); diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracle.java index 5518fefbf5..22e130b349 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracle.java @@ -22,7 +22,7 @@ import com.google.common.base.Preconditions; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.oracle.equivalence.AbstractTestWordEQOracle; -import net.automatalib.ts.acceptors.DeterministicAcceptorTS; +import net.automatalib.automata.concepts.Output; import net.automatalib.words.VPDAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; @@ -35,30 +35,25 @@ * * @author Malte Isberner */ -public class RandomWellMatchedWordsEQOracle - extends AbstractTestWordEQOracle, I, Boolean> { +public class RandomWellMatchedWordsEQOracle extends AbstractTestWordEQOracle, I, Boolean> { private final Random random; - private final VPDAlphabet alphabet; - private final double callProb; private final int maxTests, minLength, maxLength; public RandomWellMatchedWordsEQOracle(final Random random, final MembershipOracle oracle, - final VPDAlphabet alphabet, final double callProb, final int maxTests, final int minLength, final int maxLength) { - this(random, oracle, alphabet, callProb, maxTests, minLength, maxLength, 1); + this(random, oracle, callProb, maxTests, minLength, maxLength, 1); } public RandomWellMatchedWordsEQOracle(final Random random, final MembershipOracle oracle, - final VPDAlphabet alphabet, final double callProb, final int maxTests, final int minLength, @@ -69,7 +64,6 @@ public RandomWellMatchedWordsEQOracle(final Random random, Preconditions.checkArgument(minLength <= maxLength, "minLength is smaller than maxLength"); this.random = random; - this.alphabet = alphabet; this.callProb = callProb; this.maxTests = maxTests; this.minLength = minLength; @@ -77,19 +71,28 @@ public RandomWellMatchedWordsEQOracle(final Random random, } @Override - protected Stream> generateTestWords(DeterministicAcceptorTS hypothesis, - Collection inputs) { + protected Stream> generateTestWords(Output hypothesis, Collection inputs) { + + if (!(inputs instanceof VPDAlphabet)) { + throw new IllegalArgumentException( + "In order to generate well-matched words, a structured alphabet is required"); + } + + @SuppressWarnings("unchecked") + final VPDAlphabet alphabet = (VPDAlphabet) inputs; + final int lengthRange = (maxLength - minLength) + 1; - return Stream.generate(() -> generateWellMatched(minLength + random.nextInt(lengthRange))).limit(maxTests); + return Stream.generate(() -> generateWellMatched(alphabet, minLength + random.nextInt(lengthRange))) + .limit(maxTests); } - private Word generateWellMatched(final int len) { + private Word generateWellMatched(VPDAlphabet alphabet, final int len) { WordBuilder wb = new WordBuilder<>(len); - generateWellMatched(wb, len); + generateWellMatched(wb, alphabet, len); return wb.toWord(); } - private void generateWellMatched(WordBuilder wb, int length) { + private void generateWellMatched(WordBuilder wb, VPDAlphabet alphabet, int length) { if (length == 0) { return; } @@ -102,25 +105,25 @@ private void generateWellMatched(WordBuilder wb, int length) { boolean dir = random.nextBoolean(); if (dir) { final int cpos = random.nextInt(length - 1); - generateWellMatched(wb, cpos); + generateWellMatched(wb, alphabet, cpos); wb.append(alphabet.getCallSymbol(random.nextInt(alphabet.getNumCalls()))); final int rpos = cpos + 1 + random.nextInt(length - cpos - 1); - generateWellMatched(wb, rpos - cpos - 1); + generateWellMatched(wb, alphabet, rpos - cpos - 1); wb.append(alphabet.getReturnSymbol(random.nextInt(alphabet.getNumReturns()))); - generateWellMatched(wb, length - rpos - 1); + generateWellMatched(wb, alphabet, length - rpos - 1); } else { final int rpos = 1 + random.nextInt(length - 1); final int cpos = random.nextInt(rpos); - generateWellMatched(wb, cpos); + generateWellMatched(wb, alphabet, cpos); wb.append(alphabet.getCallSymbol(random.nextInt(alphabet.getNumCalls()))); - generateWellMatched(wb, rpos - cpos - 1); + generateWellMatched(wb, alphabet, rpos - cpos - 1); wb.append(alphabet.getReturnSymbol(random.nextInt(alphabet.getNumReturns()))); - generateWellMatched(wb, length - rpos - 1); + generateWellMatched(wb, alphabet, length - rpos - 1); } } else { final int sep = 1 + random.nextInt(length - 1); - generateWellMatched(wb, sep); - generateWellMatched(wb, length - sep); + generateWellMatched(wb, alphabet, sep); + generateWellMatched(wb, alphabet, length - sep); } } diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractEQOracleTest.java new file mode 100644 index 0000000000..4b0aef7a82 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractEQOracleTest.java @@ -0,0 +1,94 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Collection; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.oracle.SingleQueryOracle; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.testng.annotations.Test; + +/** + * Abstract class for testing equivalence oracles. + * + * @param + * hypothesis type + * @param + * input symbol type + * @param + * output domain type + * + * @author frohme + */ +public abstract class AbstractEQOracleTest, I, D> { + + @Test + public void testGeneratedEQQueries() { + final SuffixOutput output = getHypothesis(); + final EquivalenceOracle oracle = getOracle(new DummyMQOracle(output)); + oracle.findCounterExample(getHypothesis(), getAlphabet()); + } + + /** + * The hypothesis passed to the {@link EquivalenceOracle#findCounterExample(Object, Collection)} method. + * + * @return the hypothesis + */ + protected abstract A getHypothesis(); + + /** + * The alphabet passed to the {@link EquivalenceOracle#findCounterExample(Object, Collection)} method. + * + * @return the alphabet + */ + protected abstract Alphabet getAlphabet(); + + /** + * The check method to be invoked for every query generated by the tested equivalence oracle. + */ + protected abstract void checkGeneratedQuery(Word query); + + /** + * Method that retrieves the equivalence oracle instance to test. + * + * @param mOracle + * the (mocked) membership oracle which does not answer any queries. + * + * @return the equivalence oracle to test + */ + protected abstract EquivalenceOracle getOracle(MembershipOracle mOracle); + + private class DummyMQOracle implements SingleQueryOracle { + + private final SuffixOutput output; + + DummyMQOracle(SuffixOutput output) { + this.output = output; + } + + @Override + public D answerQuery(Word prefix, Word suffix) { + checkGeneratedQuery(prefix.concat(suffix)); + // return hypothesis output, so we don't find an actual counterexample and continue searching + return output.computeSuffixOutput(prefix, suffix); + } + } + +} diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java new file mode 100644 index 0000000000..e92adc7e66 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java @@ -0,0 +1,85 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Random; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class RandomWMethodEQOracleTest + extends AbstractEQOracleTest, Character, Boolean> { + + private static final int RANDOM_SEED; + private static final Alphabet ALPHABET; + private static final int MAX_TESTS; + private static final int MIN_LENGTH; + private static final int MAX_LENGTH; + + private int numberOfGeneratedQueries; + + static { + RANDOM_SEED = 42; + ALPHABET = Alphabets.characters('1', '6'); + MAX_TESTS = 100; + MIN_LENGTH = 25; + MAX_LENGTH = 100; + } + + @BeforeClass + public void setUp() { + this.numberOfGeneratedQueries = 0; + } + + @Test(dependsOnMethods = "testGeneratedEQQueries") + public void testNumberOfTotalQueries() { + Assert.assertEquals(this.numberOfGeneratedQueries, MAX_TESTS); + } + + @Override + protected void checkGeneratedQuery(Word query) { + numberOfGeneratedQueries++; + + Assert.assertTrue(query.length() <= MAX_LENGTH); + Assert.assertTrue(query.length() >= MIN_LENGTH); + } + + @Override + protected EquivalenceOracle, Character, Boolean> getOracle(MembershipOracle mOracle) { + return new RandomWordsEQOracle<>(mOracle, MIN_LENGTH, MAX_TESTS, MAX_LENGTH, new Random(RANDOM_SEED)); + } + + @Override + protected SuffixOutput getHypothesis() { + return (prefix, suffix) -> Boolean.TRUE; + } + + @Override + protected Alphabet getAlphabet() { + return ALPHABET; + } +} + diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWordsEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWordsEQOracleTest.java new file mode 100644 index 0000000000..8cf83e2c98 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWordsEQOracleTest.java @@ -0,0 +1,84 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Random; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class RandomWordsEQOracleTest + extends AbstractEQOracleTest, Character, Boolean> { + + private static final int RANDOM_SEED; + private static final Alphabet ALPHABET; + private static final int MAX_TESTS; + private static final int MIN_LENGTH; + private static final int MAX_LENGTH; + + private int numberOfGeneratedQueries; + + static { + RANDOM_SEED = 42; + ALPHABET = Alphabets.characters('1', '6'); + MAX_TESTS = 100; + MIN_LENGTH = 25; + MAX_LENGTH = 100; + } + + @BeforeClass + public void setUp() { + this.numberOfGeneratedQueries = 0; + } + + @Test(dependsOnMethods = "testGeneratedEQQueries") + public void testNumberOfTotalQueries() { + Assert.assertEquals(this.numberOfGeneratedQueries, MAX_TESTS); + } + + @Override + protected void checkGeneratedQuery(Word query) { + numberOfGeneratedQueries++; + + Assert.assertTrue(query.length() <= MAX_LENGTH); + Assert.assertTrue(query.length() >= MIN_LENGTH); + } + + @Override + protected EquivalenceOracle, Character, Boolean> getOracle(MembershipOracle mOracle) { + return new RandomWordsEQOracle<>(mOracle, MIN_LENGTH, MAX_TESTS, MAX_LENGTH, new Random(RANDOM_SEED)); + } + + @Override + protected SuffixOutput getHypothesis() { + return (prefix, suffix) -> Boolean.TRUE; + } + + @Override + protected Alphabet getAlphabet() { + return ALPHABET; + } +} diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/SampleSetEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/SampleSetEQOracleTest.java new file mode 100644 index 0000000000..3a6dfca1a7 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/SampleSetEQOracleTest.java @@ -0,0 +1,96 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.commons.util.random.RandomUtil; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class SampleSetEQOracleTest extends AbstractEQOracleTest, Character, Boolean> { + + private static final Alphabet ALPHABET = Alphabets.characters('1', '6'); + private static final int TEST_WORD_LENGTH = 10; + + private Random random; + private SampleSetEQOracle oracle; + private List> expectedTestWords; + private List> testedWords; + + @BeforeClass + public void setUp() { + + this.oracle = new SampleSetEQOracle<>(true); + this.random = new Random(42); + + final List alphabet = new ArrayList<>(ALPHABET); + + // add initial queries + this.oracle.add(generateTestWord(alphabet), Boolean.TRUE); + this.oracle.add(generateTestWord(alphabet), Boolean.TRUE); + this.oracle.add(generateTestWord(alphabet), Boolean.TRUE); + // check if unsuccessful queries will be removed + this.oracle.findCounterExample(((prefix, suffix) -> Boolean.TRUE), ALPHABET); + + this.expectedTestWords = + Arrays.asList(generateTestWord(alphabet), generateTestWord(alphabet), generateTestWord(alphabet)); + this.testedWords = new ArrayList<>(this.expectedTestWords.size()); + } + + private Word generateTestWord(List alphabet) { + return Word.fromList(RandomUtil.sample(alphabet, TEST_WORD_LENGTH, random)); + } + + @Test(dependsOnMethods = "testGeneratedEQQueries") + public void testName() { + Assert.assertEquals(this.expectedTestWords, this.testedWords); + } + + @Override + protected void checkGeneratedQuery(Word query) { + this.testedWords.add(query); + } + + @Override + protected EquivalenceOracle, Character, Boolean> getOracle(MembershipOracle mOracle) { + return this.oracle.addAll(mOracle, expectedTestWords); + } + + @Override + protected SuffixOutput getHypothesis() { + return (prefix, suffix) -> Boolean.TRUE; + } + + @Override + protected Alphabet getAlphabet() { + return ALPHABET; + } +} + diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracleTest.java new file mode 100644 index 0000000000..870a76fe6a --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracleTest.java @@ -0,0 +1,113 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.vpda; + +import java.util.Random; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.oracle.equivalence.AbstractEQOracleTest; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.words.Alphabet; +import net.automatalib.words.VPDAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.DefaultVPDAlphabet; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; + +/** + * @author frohme + */ +public class RandomWellMatchedWordsEQOracleTest + extends AbstractEQOracleTest, Character, Boolean> { + + private static final int RANDOM_SEED; + private static final VPDAlphabet ALPHABET; + private static final double CALL_PROB; + private static final int MAX_TESTS; + private static final int MIN_LENGTH; + private static final int MAX_LENGTH; + + private int numberOfGeneratedQueries; + + static { + RANDOM_SEED = 42; + ALPHABET = new DefaultVPDAlphabet<>(Alphabets.characters('1', '3'), + Alphabets.characters('a', 'c'), + Alphabets.characters('x', 'z')); + CALL_PROB = 0.5; + MAX_TESTS = 100; + MIN_LENGTH = 25; + MAX_LENGTH = 100; + } + + @BeforeClass + public void setUp() { + this.numberOfGeneratedQueries = 0; + } + + @Override + protected void checkGeneratedQuery(Word query) { + numberOfGeneratedQueries++; + + Assert.assertTrue(numberOfGeneratedQueries <= MAX_TESTS); + Assert.assertTrue(query.length() <= MAX_LENGTH); + Assert.assertTrue(query.length() >= MIN_LENGTH); + Assert.assertTrue(isWellMatched(ALPHABET, query)); + } + + private static boolean isWellMatched(VPDAlphabet alphabet, Word word) { + + int callBalance = 0; + + for (final I i : word) { + switch (alphabet.getSymbolType(i)) { + case CALL: + callBalance++; + break; + case RETURN: + callBalance--; + break; + default: + // do nothing + } + } + + return callBalance == 0; + } + + @Override + protected EquivalenceOracle, Character, Boolean> getOracle(MembershipOracle mOracle) { + return new RandomWellMatchedWordsEQOracle<>(new Random(RANDOM_SEED), + mOracle, + CALL_PROB, + MAX_TESTS, + MIN_LENGTH, + MAX_LENGTH); + } + + @Override + protected SuffixOutput getHypothesis() { + return (prefix, suffix) -> Boolean.TRUE; + } + + @Override + protected Alphabet getAlphabet() { + return ALPHABET; + } +} From ec4b724a68fc5c5c95a38ae1d3c46a3d136769c4 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 19 Jun 2018 13:53:41 +0200 Subject: [PATCH 056/125] Moved LTSmin model checker from LearnLib to AutomataLib ... with necessary refactorings --- .../api/exception/ModelCheckingException.java | 33 -- .../api/logging/LoggingBlackBoxProperty.java | 2 +- .../modelchecking/counterexample/Lasso.java | 356 ------------------ .../modelchecker/ModelChecker.java | 114 ------ .../learnlib/api/oracle/AutomatonOracle.java | 10 +- .../learnlib/api/oracle/BlackBoxOracle.java | 2 +- .../learnlib/api/oracle/EmptinessOracle.java | 52 +-- .../counterexample/AbstractLassoTest.java | 5 +- .../counterexample/DFALassoTest.java | 10 +- .../counterexample/MealyLassoTest.java | 10 +- build-parent/pom.xml | 3 - .../de/learnlib/setting/LearnLibProperty.java | 7 - .../setting/LearnLibSettingsTest.java | 4 - .../src/test/resources/learnlib.properties | 1 - distribution/pom.xml | 14 - examples/pom.xml | 8 +- .../examples/bbc/example1/Example.java | 4 +- .../examples/bbc/example2/Example.java | 4 +- .../examples/bbc/example3/Example.java | 4 +- model-checkers/pom.xml | 79 ---- .../modelchecker/AbstractLTSminLTL.java | 303 --------------- .../modelchecker/AbstractLTSminLTLMealy.java | 168 --------- .../AbstractUnfoldingModelChecker.java | 113 ------ .../modelchecker/LTSminLTLAlternating.java | 69 ---- .../modelchecker/LTSminLTLDFA.java | 125 ------ .../modelchecker/LTSminLTLIO.java | 69 ---- .../modelchecker/LTSminUtil.java | 122 ------ .../AbstractLTSminLTLMealyTest.java | 66 ---- .../modelchecker/AbstractLTSminLTLTest.java | 83 ---- .../AbstractUnfoldingModelCheckerTest.java | 73 ---- .../LTSminLTLAlternatingTest.java | 54 --- .../modelchecker/LTSminLTLDFATest.java | 73 ---- .../modelchecker/LTSminLTLIOTest.java | 53 --- model-checkers/src/test/resources/test.etf | 26 -- model-checkers/src/test/resources/test.fsm | 9 - .../oracle/blackbox/CExFirstBBOracle.java | 2 +- .../blackbox/DisproveFirstBBOracle.java | 2 +- .../blackbox/ModelCheckingBBProperty.java | 18 +- ...AbstractLassoAutomatonEmptinessOracle.java | 8 +- .../blackbox/ModelCheckingBBPropertyTest.java | 2 +- ...stractBreadthFirstEmptinessOracleTest.java | 120 ------ .../AbstractLassoAutomatonEmptinessTest.java | 143 +------ .../emptiness/DFABFEmptinessOracleTest.java | 83 ++++ .../DFALassoDFAEmptinessOracleTest.java | 95 +++++ .../emptiness/MealyBFEmptinessOracleTest.java | 86 +++++ .../MealyLassoMealyEmptinessOracleTest.java | 97 +++++ ...stractBreadthFirstInclusionOracleTest.java | 116 ------ .../DFABreadthFirstInclusionOracleTest.java | 83 ++++ .../MealyBreadthFirstInclusionOracleTest.java | 87 +++++ pom.xml | 8 - 50 files changed, 606 insertions(+), 2472 deletions(-) delete mode 100644 api/src/main/java/de/learnlib/api/exception/ModelCheckingException.java delete mode 100644 api/src/main/java/de/learnlib/api/modelchecking/counterexample/Lasso.java delete mode 100644 api/src/main/java/de/learnlib/api/modelchecking/modelchecker/ModelChecker.java delete mode 100644 model-checkers/pom.xml delete mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java delete mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java delete mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelChecker.java delete mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java delete mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java delete mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java delete mode 100644 model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java delete mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java delete mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java delete mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java delete mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternatingTest.java delete mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java delete mode 100644 model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIOTest.java delete mode 100644 model-checkers/src/test/resources/test.etf delete mode 100644 model-checkers/src/test/resources/test.fsm create mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java create mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoDFAEmptinessOracleTest.java create mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java create mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoMealyEmptinessOracleTest.java create mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/DFABreadthFirstInclusionOracleTest.java create mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/MealyBreadthFirstInclusionOracleTest.java diff --git a/api/src/main/java/de/learnlib/api/exception/ModelCheckingException.java b/api/src/main/java/de/learnlib/api/exception/ModelCheckingException.java deleted file mode 100644 index 18233c3950..0000000000 --- a/api/src/main/java/de/learnlib/api/exception/ModelCheckingException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.api.exception; - -/** - * An Exception that may occur during model checking. - * - * @author Jeroen Meijer - */ -public class ModelCheckingException extends RuntimeException { - - public ModelCheckingException(Exception exception) { - super(exception); - } - - public ModelCheckingException(String message) { - super(message); - } - -} diff --git a/api/src/main/java/de/learnlib/api/logging/LoggingBlackBoxProperty.java b/api/src/main/java/de/learnlib/api/logging/LoggingBlackBoxProperty.java index b8f5cebacd..0beac3522b 100644 --- a/api/src/main/java/de/learnlib/api/logging/LoggingBlackBoxProperty.java +++ b/api/src/main/java/de/learnlib/api/logging/LoggingBlackBoxProperty.java @@ -19,13 +19,13 @@ import javax.annotation.Nullable; -import de.learnlib.api.exception.ModelCheckingException; import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxProperty; import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.exception.ModelCheckingException; import net.automatalib.words.Word; /** diff --git a/api/src/main/java/de/learnlib/api/modelchecking/counterexample/Lasso.java b/api/src/main/java/de/learnlib/api/modelchecking/counterexample/Lasso.java deleted file mode 100644 index 5c10d47f65..0000000000 --- a/api/src/main/java/de/learnlib/api/modelchecking/counterexample/Lasso.java +++ /dev/null @@ -1,356 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.api.modelchecking.counterexample; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - -import net.automatalib.automata.concepts.InputAlphabetHolder; -import net.automatalib.automata.concepts.Output; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.simple.SimpleAutomaton; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealyTransition; -import net.automatalib.commons.util.collections.CollectionsUtil; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import net.automatalib.words.WordBuilder; -import net.automatalib.words.impl.Alphabets; - -/** - * A lasso is an single infinite word. - * - * The implementation is an automaton such that its singleton language is the infinite word. Also, the implementation - * is actually the finite representation (by unrolling the loop) of the infinite word, including information how many - * times the loop of the lasso is unrolled. - * - * @param the state type of the automaton that contains the infinite word. - * @param the automaton type which contains the lasso. - * @param the input type - * @param the output type - */ -@ParametersAreNonnullByDefault -public abstract class Lasso & Output, I, D> - implements SimpleDTS, Output, SimpleAutomaton, InputAlphabetHolder { - - public static final String NO_LASSO = "Automaton is not lasso shaped"; - - /** - * @see #getWord() - */ - private final Word word; - - /** - * @see #getLoop() - */ - private final Word loop; - - /** - * @see #getPrefix() - */ - private final Word prefix; - - /** - * @see #getOutput() - */ - private final D output; - - /** - * @see #getAutomaton() - */ - private final A automaton; - - /** - * @see #getInputAlphabet() - */ - private final Alphabet inputAlphabet; - - /** - * @see #getLoopBeginIndices() - */ - private final SortedSet loopBeginIndices = new TreeSet<>(); - - /** - * Constructs a finite representation of a given automaton (that contains a lasso), by unrolling the loop {@code - * unfoldTimes}. - * - * @param automaton the automaton containing the lasso. - * @param inputs the input alphabet. - * @param unfoldTimes the number of times the loop needs to be unrolled, must be {@code > 0}. - */ - public Lasso(A automaton, Collection inputs, int unfoldTimes) { - assert unfoldTimes > 0; - - // save the original automaton - this.automaton = automaton; - - // construct the input alphabet - inputAlphabet = Alphabets.fromCollection(inputs); - - // create a map for the visited states - final Map states = new HashMap<>(); - - // create a WordBuilder, for the finite representation of the lasso - final WordBuilder wb = new WordBuilder<>(); - - // start visiting the initial state - S current = automaton.getInitialState(); - - // index for the current state - int i = 0; - do { - // create a mapping from the current state to the state index - states.put(current, i++); - - // find the input that leads to the next state - final S c = current; - final I input = inputAlphabet.stream().filter(in -> automaton.getSuccessor(c, in) != null). - findAny().orElseThrow(() -> new IllegalArgumentException(NO_LASSO)); - - // append the input to the finite representation - wb.append(input); - - // continue with the next state. - current = automaton.getSuccessor(current, input); - } while (!states.containsKey(current)); - - // save the state index at which the loop begins - final int loopBegin = states.get(current); - - // determine the loop of the lasso - loop = wb.toWord(loopBegin, wb.size()); - - // determine the prefix of the lasso - prefix = wb.toWord(0, loopBegin); - - // append the loop several times to the finite representation - for (int u = 1; u < unfoldTimes; u++) { - wb.append(loop); - } - - // store the entire finite representation of the lasso - word = wb.toWord(); - - // store the finite representation of output of the lasso - output = automaton.computeOutput(word); - - // store all the symbol indices after which the beginning of the loop is visited. - for (int l = prefix.length(); l <= word.length(); l += loop.length()) { - loopBeginIndices.add(l); - } - } - - /** - * Gets the finite representation of the lasso. - * - * @return the Word. - */ - public Word getWord() { - return word; - } - - /** - * Gets the loop of the lasso. - * - * @return the Word. - */ - public Word getLoop() { - return loop; - } - - /** - * Gets the prefix of the lasso. - * - * @return the Word. - */ - public Word getPrefix() { - return prefix; - } - - /** - * Gets the finite representation of the output of the lasso. - * - * @return the output type D. - */ - public D getOutput() { - return output; - } - - /** - * Gets the automaton containing the lasso. - * - * @return the automaton type a. - */ - public A getAutomaton() { - return automaton; - } - - /** - * The sorted set containing some symbol indices after which the begin state of the loop is visited. - */ - public SortedSet getLoopBeginIndices() { - return loopBeginIndices; - } - - @Nullable - @Override - public Integer getInitialState() { - return 0; - } - - /** - * Get the successor state of a given state, or {@code null} when no such successor exists. - * - * @see SimpleDTS#getSuccessor(Object, Object) - */ - @Nullable - @Override - public Integer getSuccessor(Integer state, @Nullable I input) { - final Integer result; - if (state < word.length() && input.equals(word.getSymbol(state))) { - result = state + 1; - } else { - result = null; - } - - return result; - } - - @Nonnull - @Override - public Collection getStates() { - return CollectionsUtil.intRange(0, word.length()); - } - - /** - * Gets the input alphabet of this automaton. - * - * @return the Alphabet. - */ - @Nonnull - @Override - public Alphabet getInputAlphabet() { - return inputAlphabet; - } - - /** - * A DFALasso is a lasso for {@link DFA}s. - * - * @param the state type of the DFA that contains the lasso. - * @param the input type - */ - public static class DFALasso extends Lasso, I, Boolean> implements DFA { - - public DFALasso(DFA automaton, Collection inputs, int unfoldTimes) { - super(automaton, inputs, unfoldTimes); - } - - @Nullable - @Override - public Integer getTransition(Integer state, @Nullable I input) { - return getSuccessor(state, input); - } - - /** - * Returns whether the given state is accepting. - * - * The current state is only accepting iff it is precisely the state after the last symbol index in the - * finite representation of the lasso. - * - * @param state to compute whether it is accepting. - * - * @return whether the given {@code state} is accepting. - */ - @Override - public boolean isAccepting(Integer state) { - return state == getWord().length(); - } - } - - /** - * A MealyLasso is a lasso for {@link MealyMachine}s. - * - * @param the state type of the Mealy machine that contains the lasso. - * @param the input type - * @param the output type - */ - public static class MealyLasso extends Lasso, I, Word> - implements MealyMachine, O> { - - public MealyLasso(MealyMachine automaton, Collection inputs, int unfoldTimes) { - super(automaton, inputs, unfoldTimes); - } - - @Nullable - @Override - public O getTransitionOutput(CompactMealyTransition transition) { - return transition.getOutput(); - } - - /** - * Returns the transition from a given {@code state}, and {@code input}, or {@code null} if such a transition - * does not exist. - * - * @see net.automatalib.ts.DeterministicTransitionSystem#getTransition(Object, Object) - */ - @Nullable - @Override - public CompactMealyTransition getTransition(Integer state, @Nullable I input) { - final CompactMealyTransition result; - if (getWord().getSymbol(state).equals(input)) { - result = new CompactMealyTransition<>(state + 1, getOutput().getSymbol(state)); - } else { - result = null; - } - return result; - } - - @Nonnull - @Override - public Integer getSuccessor(CompactMealyTransition transition) { - return transition.getSuccId(); - } - - /** - * Computes the output of the given input sequence. - * - * Only returns a word ({@code null} otherwise) when the input sequence is precisely the finite representation - * of the input word of the lasso. - * - * @see Output#computeOutput(Iterable) - */ - @Override - public Word computeOutput(Iterable input) { - final Word output = getAutomaton().computeOutput(input); - final Word result; - if (output.equals(getOutput())) { - result = output; - } else { - result = Word.epsilon(); - } - - return result; - } - } -} diff --git a/api/src/main/java/de/learnlib/api/modelchecking/modelchecker/ModelChecker.java b/api/src/main/java/de/learnlib/api/modelchecking/modelchecker/ModelChecker.java deleted file mode 100644 index 581fef879e..0000000000 --- a/api/src/main/java/de/learnlib/api/modelchecking/modelchecker/ModelChecker.java +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.api.modelchecking.modelchecker; - -import java.util.Collection; - -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - -import de.learnlib.api.exception.ModelCheckingException; -import de.learnlib.api.modelchecking.counterexample.Lasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; - -/** - * A ModelChecker checks whether a given hypothesis satisfies a given property. If the property can not be satisfied - * it provides a counterexample. - * - * @author Jeroen Meijer - * - * @param the input type - * @param the automaton type - * @param

the property type - * @param the type of a counterexample - */ -@ParametersAreNonnullByDefault -public interface ModelChecker { - - /** - * Try to find a counterexample for the given {@code property} and {@code hypothesis}. - * - * @param hypothesis the automaton to check the property on. - * @param inputs the alphabet. - * @param property the property. - * - * @return the counterexample, or {@code null} if a counterexample does not exist. - * - * @throws ModelCheckingException when a model checker can not check the property. - */ - @Nullable - R findCounterExample(A hypothesis, Collection inputs, P property) throws ModelCheckingException; - - interface DFAModelChecker> extends ModelChecker, P, R> {} - - interface MealyModelChecker> - extends ModelChecker, P, R> {} - - /** - * A model checker where the counterexample is a lasso. - * - * @param the input type. - * @param the automaton type. - * @param

the property type. - * @param the type of lasso. - */ - interface ModelCheckerLasso> extends ModelChecker { - - /** - * Return the multiplier for the number of times a loop of the lasso must be unrolled, relative to the size - * of the hypothesis. - * - * @return the multiplier - */ - double getMultiplier(); - - /** - * Set the multiplier for the number of times a loop of the lasso must be unrolled, relative to the size of - * the hypothesis. - * - * @param multiplier the multiplier - * - * @throws IllegalArgumentException when {@code multiplier < 0.0}. - */ - void setMultiplier(double multiplier) throws IllegalArgumentException; - - /** - * Returns the minimum number of times a loop must be unrolled. - * - * @return the minimum - */ - int getMinimumUnfolds(); - - /** - * Set the minimum number of times a loop must be unrolled. - * - * @param minimumUnfolds the minimum - * - * @throws IllegalArgumentException when {@code minimumUnfolds < 1}. - */ - void setMinimumUnfolds(int minimumUnfolds) throws IllegalArgumentException; - } - - interface DFAModelCheckerLasso - extends ModelCheckerLasso, P, DFALasso>, DFAModelChecker> {} - - interface MealyModelCheckerLasso extends - ModelCheckerLasso, P, MealyLasso>, - MealyModelChecker> {} -} diff --git a/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java b/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java index c02fb89534..da4b76ea34 100644 --- a/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java @@ -19,14 +19,14 @@ import javax.annotation.Nullable; -import de.learnlib.api.modelchecking.counterexample.Lasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; import de.learnlib.api.query.Query; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.Lasso.DFALasso; +import net.automatalib.modelchecking.Lasso.MealyLasso; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Word; @@ -294,7 +294,7 @@ interface DFALassoOracle extends LassoOracle, S, I, Boolean> {} interface MealyLassoOracle extends - MealyOracle, I, O, OmegaQuery>>, - LassoOracle, S, I, Word> {} + MealyOracle, I, O, OmegaQuery>>, + LassoOracle, S, I, Word> {} } diff --git a/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java b/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java index cfeedbff62..e2dfda39df 100644 --- a/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java @@ -23,11 +23,11 @@ import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; -import de.learnlib.api.exception.ModelCheckingException; import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.exception.ModelCheckingException; import net.automatalib.words.Word; /** diff --git a/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java index 50ba5c904a..a5dac5ccd5 100644 --- a/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java @@ -17,32 +17,36 @@ import javax.annotation.ParametersAreNonnullByDefault; -import de.learnlib.api.modelchecking.counterexample.Lasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; import de.learnlib.api.query.Query; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.Lasso.DFALasso; +import net.automatalib.modelchecking.Lasso.MealyLasso; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Word; /** - * Decides whether the intersection of the language of a given hypothesis and some other language (e.g. from a - * {@link de.learnlib.api.SUL} is empty. If the intersection is not empty it provides a counterexample, such that is - * a word in the intersection. + * Decides whether the intersection of the language of a given hypothesis and some other language (e.g. from a {@link + * de.learnlib.api.SUL} is empty. If the intersection is not empty it provides a counterexample, such that is a word in + * the intersection. + *

+ * A {@link DFAEmptinessOracle}, and {@link MealyEmptinessOracle} use {@link DefaultQuery}s, while {@link + * DFALassoEmptinessOracle}, and {@link MealyLassoEmptinessOracle} use {@link OmegaQuery}s. * - * A {@link DFAEmptinessOracle}, and {@link MealyEmptinessOracle} use {@link DefaultQuery}s, while - * {@link DFALassoEmptinessOracle}, and {@link MealyLassoEmptinessOracle} use {@link OmegaQuery}s. + * @param + * the automaton type + * @param + * the input type + * @param + * the output type + * @param + * the DefaultQuery type * * @author Jeroen Meijer - * - * @param the automaton type - * @param the input type - * @param the output type - * @param the DefaultQuery type */ @ParametersAreNonnullByDefault public interface EmptinessOracle & SimpleDTS, I, D, Q extends DefaultQuery> @@ -59,19 +63,19 @@ default boolean isCounterExample(A hypothesis, Q query) { return query.getOutput().equals(hypothesis.computeOutput(query.getInput())); } - interface DFAEmptinessOracle extends - EmptinessOracle, I, Boolean, DefaultQuery>, DFADefaultOracle {} + interface DFAEmptinessOracle + extends EmptinessOracle, I, Boolean, DefaultQuery>, DFADefaultOracle {} - interface MealyEmptinessOracle extends - EmptinessOracle, I, Word, DefaultQuery>>, MealyDefaultOracle {} + interface MealyEmptinessOracle + extends EmptinessOracle, I, Word, DefaultQuery>>, + MealyDefaultOracle {} - interface LassoEmptinessOracle, S, I, D> extends - EmptinessOracle>, LassoOracle { - } + interface LassoEmptinessOracle, S, I, D> + extends EmptinessOracle>, LassoOracle {} - interface DFALassoEmptinessOracle extends - LassoEmptinessOracle, S, I, Boolean>, DFALassoOracle {} + interface DFALassoEmptinessOracle + extends LassoEmptinessOracle, S, I, Boolean>, DFALassoOracle {} - interface MealyLassoEmptinessOracle extends - LassoEmptinessOracle, S, I, Word>, MealyLassoOracle {} + interface MealyLassoEmptinessOracle + extends LassoEmptinessOracle, S, I, Word>, MealyLassoOracle {} } diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java index 89e7f603c5..84d52d3094 100644 --- a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java +++ b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java @@ -18,6 +18,7 @@ import java.util.SortedSet; import java.util.TreeSet; +import net.automatalib.modelchecking.AbstractLasso; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -28,11 +29,11 @@ /** * Tests whether lassos are constructed correctly for any automaton. * - * @param the {@link Lasso} type to test. + * @param the {@link AbstractLasso} type to test. * * @author Jeroen Meijer */ -public abstract class AbstractLassoTest> { +public abstract class AbstractLassoTest> { private Alphabet alphabet = Alphabets.fromArray("a"); diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java index 0d963e9639..baadd012d1 100644 --- a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java +++ b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java @@ -20,9 +20,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; import net.automatalib.automata.fsa.DFA; import net.automatalib.commons.util.collections.CollectionsUtil; +import net.automatalib.modelchecking.DFALassoImpl; import net.automatalib.words.Word; import org.testng.Assert; import org.testng.annotations.Test; @@ -30,16 +30,16 @@ /** * @author Jeroen Meijer */ -public class DFALassoTest extends AbstractLassoTest> { +public class DFALassoTest extends AbstractLassoTest> { @Override - protected DFALasso getLasso(Word prefix, Word loop, int unfoldTimes) { - return new DFALasso<>(new DFAMock(prefix, loop), getAlphabet(), unfoldTimes); + protected DFALassoImpl getLasso(Word prefix, Word loop, int unfoldTimes) { + return new DFALassoImpl<>(new DFAMock(prefix, loop), getAlphabet(), unfoldTimes); } @Test public void testGetOutput() { - final DFALasso lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); + final DFALassoImpl lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); Assert.assertTrue(lasso.getOutput()); } diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java index a1f5b9c048..7cc6d426c2 100644 --- a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java +++ b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java @@ -20,10 +20,10 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.automata.transout.impl.compact.CompactMealyTransition; import net.automatalib.commons.util.collections.CollectionsUtil; +import net.automatalib.modelchecking.MealyLassoImpl; import net.automatalib.words.Word; import org.testng.Assert; import org.testng.annotations.Test; @@ -31,16 +31,16 @@ /** * @author Jeroen Meijer */ -public class MealyLassoTest extends AbstractLassoTest> { +public class MealyLassoTest extends AbstractLassoTest> { @Override - protected MealyLasso getLasso(Word prefix, Word loop, int unfoldTimes) { - return new MealyLasso<>(new MealyMachineMock(prefix, loop), getAlphabet(), 1); + protected MealyLassoImpl getLasso(Word prefix, Word loop, int unfoldTimes) { + return new MealyLassoImpl<>(new MealyMachineMock(prefix, loop), getAlphabet(), 1); } @Test public void testGetOutput() { - final MealyLasso lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); + final MealyLassoImpl lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); Assert.assertEquals(lasso.getOutput(), Word.fromSymbols(MealyMachineMock.OUTPUT)); } diff --git a/build-parent/pom.xml b/build-parent/pom.xml index ca8d37d2fd..147e27eea3 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -56,9 +56,6 @@ limitations under the License. **/NLStarLearnerBuilder.class **/TTTLearner*Builder.class **/TTTLearnerVPDABuilder.class - **/LTSminLTLAlternatingBuilder.class - **/LTSminLTLDFABuilder.class - **/LTSminLTLIOBuilder.class diff --git a/commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.java b/commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.java index 7977500901..a0c982ca3f 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.java +++ b/commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.java @@ -22,13 +22,6 @@ */ public enum LearnLibProperty { - /** - * {@code learnlib.external.ltsmin.path}. - *

- * Path to the binary folder of the LTSmin installation. - */ - LTSMIN_PATH("external.ltsmin.path"), - /** * {@code learnlib.parallel.batch_size.dynamic}. *

diff --git a/commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.java b/commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.java index aa39c46038..4151a4ba2b 100644 --- a/commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.java +++ b/commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.java @@ -30,7 +30,6 @@ public class LearnLibSettingsTest { public void setUp() { final File properties = new File(LearnLibSettingsTest.class.getResource("/learnlib.properties").getFile()); System.setProperty("learnlib.properties", properties.getAbsolutePath()); - System.setProperty(LearnLibProperty.LTSMIN_PATH.getPropertyKey(), "OVERRIDDEN"); } @Test @@ -39,9 +38,6 @@ public void testProperties() { for (LearnLibProperty p : LearnLibProperty.values()) { switch (p) { - case LTSMIN_PATH: - Assert.assertEquals("OVERRIDDEN", settings.getProperty(LearnLibProperty.LTSMIN_PATH)); - break; case PARALLEL_BATCH_SIZE_DYNAMIC: Assert.assertEquals(1, settings.getInt(LearnLibProperty.PARALLEL_BATCH_SIZE_DYNAMIC, 0)); break; diff --git a/commons/settings/src/test/resources/learnlib.properties b/commons/settings/src/test/resources/learnlib.properties index 0428e8b409..cf8c485426 100644 --- a/commons/settings/src/test/resources/learnlib.properties +++ b/commons/settings/src/test/resources/learnlib.properties @@ -1,4 +1,3 @@ -learnlib.external.ltsmin.path=ltsmin learnlib.parallel.batch_size.dynamic=1 learnlib.parallel.batch_size.static=2 learnlib.parallel.pool_policy=CACHED diff --git a/distribution/pom.xml b/distribution/pom.xml index 9c11303cae..70450c5879 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -171,12 +171,6 @@ limitations under the License. learnlib-drivers-simulator - - - de.learnlib - learnlib-model-checkers - - de.learnlib @@ -429,14 +423,6 @@ limitations under the License. sources - - - de.learnlib - learnlib-model-checkers - ${project.version} - sources - - de.learnlib diff --git a/examples/pom.xml b/examples/pom.xml index 465bc30715..052006b581 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -92,10 +92,6 @@ limitations under the License. de.learnlib learnlib-util - - de.learnlib - learnlib-model-checkers - de.learnlib.testsupport learnlib-learning-examples @@ -120,6 +116,10 @@ limitations under the License. net.automatalib automata-serialization-dot + + net.automatalib + automata-modelchecking-ltsmin + net.automatalib diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java index 79340d0674..3239081bbe 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java @@ -21,7 +21,6 @@ import de.learnlib.algorithms.ttt.dfa.TTTLearnerDFA; import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; import de.learnlib.api.logging.LoggingBlackBoxProperty.DFALoggingBlackBoxProperty; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelCheckerLasso; import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxOracle; import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxProperty; import de.learnlib.api.oracle.EmptinessOracle.DFALassoEmptinessOracle; @@ -31,7 +30,6 @@ import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; import de.learnlib.examples.LearningExample.DFALearningExample; import de.learnlib.examples.dfa.ExampleTinyDFA; -import de.learnlib.modelchecking.modelchecker.LTSminLTLDFABuilder; import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstDFABBOracle; import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.DFABBPropertyDFALasso; import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.DFALassoDFAEmptinessOracle; @@ -40,6 +38,8 @@ import de.learnlib.oracle.membership.SimulatorOmegaOracle.DFASimulatorOmegaOracle; import de.learnlib.util.BBCExperiment.DFABBCExperiment; import net.automatalib.automata.fsa.DFA; +import net.automatalib.modelcheckers.ltsmin.LTSminLTLDFABuilder; +import net.automatalib.modelchecking.ModelCheckerLasso.DFAModelCheckerLasso; import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; import net.automatalib.words.Alphabet; diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java index 1244d40389..8f14b0ccf9 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java @@ -20,7 +20,6 @@ import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelCheckerLasso; import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxOracle; import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; import de.learnlib.api.oracle.EmptinessOracle.MealyLassoEmptinessOracle; @@ -30,7 +29,6 @@ import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; import de.learnlib.examples.LearningExample.MealyLearningExample; import de.learnlib.examples.mealy.ExampleTinyMealy; -import de.learnlib.modelchecking.modelchecker.LTSminLTLIOBuilder; import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstMealyBBOracle; import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.MealyBBPropertyMealyLasso; import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; @@ -39,6 +37,8 @@ import de.learnlib.oracle.membership.SimulatorOmegaOracle.MealySimulatorOmegaOracle; import de.learnlib.util.BBCExperiment.MealyBBCExperiment; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.modelcheckers.ltsmin.LTSminLTLIOBuilder; +import net.automatalib.modelchecking.ModelCheckerLasso.MealyModelCheckerLasso; import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; import net.automatalib.words.Alphabet; diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java index 2e1c79bef3..d209dc933e 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java @@ -20,7 +20,6 @@ import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelCheckerLasso; import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxOracle; import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; import de.learnlib.api.oracle.EmptinessOracle.MealyLassoEmptinessOracle; @@ -30,7 +29,6 @@ import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; import de.learnlib.examples.LearningExample.MealyLearningExample; import de.learnlib.examples.mealy.ExampleTinyMealy; -import de.learnlib.modelchecking.modelchecker.LTSminLTLAlternatingBuilder; import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstMealyBBOracle; import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.MealyBBPropertyMealyLasso; import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; @@ -39,6 +37,8 @@ import de.learnlib.oracle.membership.SimulatorOmegaOracle.MealySimulatorOmegaOracle; import de.learnlib.util.BBCExperiment.MealyBBCExperiment; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.modelcheckers.ltsmin.LTSminLTLAlternatingBuilder; +import net.automatalib.modelchecking.ModelCheckerLasso.MealyModelCheckerLasso; import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; import net.automatalib.words.Alphabet; diff --git a/model-checkers/pom.xml b/model-checkers/pom.xml deleted file mode 100644 index 1457c70378..0000000000 --- a/model-checkers/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - 4.0.0 - - - de.learnlib - learnlib-build-parent - 0.14.0-SNAPSHOT - ../build-parent/pom.xml - - - learnlib-model-checkers - - LearnLib :: Model Checkers - Module for model checkers - - - - de.learnlib - learnlib-api - - - net.automatalib - automata-util - - - net.automatalib - automata-core - - - net.automatalib - automata-serialization-etf - - - net.automatalib - automata-serialization-fsm - - - net.automatalib - automata-api - - - com.github.misberner.buildergen - buildergen - - - org.slf4j - slf4j-api - - - org.testng - testng - - - org.mockito - mockito-core - - - de.learnlib - learnlib-settings - - - diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java deleted file mode 100644 index 132afde5af..0000000000 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTL.java +++ /dev/null @@ -1,303 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.Function; - -import de.learnlib.api.exception.ModelCheckingException; -import de.learnlib.api.modelchecking.counterexample.Lasso; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker; -import de.learnlib.setting.LearnLibSettings; -import net.automatalib.automata.concepts.Output; -import net.automatalib.serialization.etf.writer.AbstractETFWriter; -import net.automatalib.serialization.fsm.parser.AbstractFSMParser; -import net.automatalib.serialization.fsm.parser.FSMParseException; -import net.automatalib.ts.simple.SimpleDTS; - -/** - * An LTL model checker using LTSmin. - * - * The user must install LTSmin in order for {@link AbstractLTSminLTL} to run without exceptions. Once LTSmin is installed - * the user may specify the path to the installed LTSmin binaries with the property - * learnlib.external.ltsmin.path. If this property is not set the binaries will be run as usual (e.g. simply - * by invoking etf2lts-mc, and ltsmin-convert), which means the user can also specify the location of the binaries - * in the PATH environment variable. - * - * This model checker is implemented as follows. The hypothesis automaton is first written to an LTS in ETF - * {@link AbstractETFWriter} file, which serves as input for the etf2lts-mc binary. - * Then the etf2lts-mc binary is run, which will write an LTS in GCF format. This LTS will be a subset of the - * language of the given hypothesis. Next, the GCF is converted to FSM using the ltsmin-convert binary. Lastly, the - * FSM is read back into an automaton using an {@link AbstractFSMParser}. - * - * @author Jeroen Meijer - * - * @see http://ltsmin.utwente.nl - * @see AbstractFSMParser - * @see AbstractETFWriter - * @see LearnLibSettings - * - * @param the input type. - * @param the output type. - * @param the Lasso type. - */ -public abstract class AbstractLTSminLTL & Output, - L extends Lasso> - extends AbstractUnfoldingModelChecker implements ModelChecker { - - /** - * @see #isKeepFiles() - */ - private final boolean keepFiles; - - /** - * @see #getString2Input() - */ - private final Function string2Input; - - /** - * Constructs a new AbstractLTSminLTL. - * - * @param keepFiles whether to keep intermediate files, (e.g. etfs, gcfs etc.). - * @param string2Input a function that transforms edges in FSM files to actual input. - * @param minimumUnfolds the minimum number of unfolds. - * @param multiplier the multiplier - * @throws ModelCheckingException when the LTSmin binaries can not be run successfully. - */ - protected AbstractLTSminLTL(boolean keepFiles, - Function string2Input, - int minimumUnfolds, - double multiplier) throws ModelCheckingException { - super(minimumUnfolds, multiplier); - this.keepFiles = keepFiles; - this.string2Input = string2Input; - - if (!LazyBinaryChecker.AVAILABLE) { - throw new ModelCheckingException("LTSmin binary could not be executed correctly"); - } - } - - /** - * Returns whether intermediate files should be kept, e.g. etfs, gcfs, etc. - * - * @return the boolean - */ - protected boolean isKeepFiles() { - return keepFiles; - } - - /** - * Returns the function that transforms edges in FSM files to actual input. - * - * @return the Function. - */ - public Function getString2Input() { - return string2Input; - } - - /** - * Writes the given {@code automaton} to the given {@code etf} file. - * - * @param automaton the automaton to write. - * @param inputs the alphabet. - * @param etf the file to write to. - * - * @throws IOException when the given {@code automaton} can not be written to {@code etf}. - */ - protected abstract void automaton2ETF(A automaton, Collection inputs, File etf) throws IOException; - - /** - * Reads the {@code fsm} and converts it to a {@link Lasso}. - * - * @param fsm the FSM to read. - * @param automaton the automaton that was used as a hypothesis. - * - * @return the {@link Lasso}. - * - * @throws IOException when {@code fsm} can not be read correctly. - * @throws FSMParseException when the FSM definition in {@code fsm} is invalid. - */ - protected abstract L fsm2Lasso(File fsm, A automaton) throws IOException, FSMParseException; - - /** - * Finds a counterexample for the given {@code formula}, and given {@code hypothesis}. - * - * @see AbstractLTSminLTL - */ - @Override - public final L findCounterExample(A hypothesis, Collection inputs, String formula) throws ModelCheckingException { - - final File etf, gcf; - try { - // create the ETF that will contain the LTS of the hypothesis - etf = File.createTempFile("automaton2etf", ".etf"); - - // create the GCF that will possibly contain the counterexample - gcf = File.createTempFile("etf2gcf", ".gcf"); - - // write to the ETF file - automaton2ETF(hypothesis, inputs, etf); - - } catch (IOException ioe) { - throw new ModelCheckingException(ioe); - } - - // the command lines for the ProcessBuilder - final List commandLines = new ArrayList<>(); - - // add the etf2lts-mc binary - commandLines.add(LTSminUtil.ETF2LTS_MC); - - // add the ETF file that contains the LTS of the hypothesis - commandLines.add(etf.getAbsolutePath()); - - // add the LTL formula - commandLines.add("--ltl=" + formula); - - // use Buchi automata created by spot - commandLines.add("--buchi-type=spotba"); - - // use the Union-Find strategy - commandLines.add("--strategy=ufscc"); - - // write the lasso to this file - commandLines.add("--trace=" + gcf.getAbsolutePath()); - - // use only one thread (hypotheses are always small) - commandLines.add("--threads=1"); - - // use LTSmin LTL semantics - commandLines.add("--ltl-semantics=ltsmin"); - - // do not abort on partial LTSs - commandLines.add("--allow-undefined-edges"); - - final Process ltsmin; - try { - // run the etf2lts-mc binary - ProcessBuilder processBuilder = new ProcessBuilder(commandLines); - ltsmin = processBuilder.start(); - ltsmin.waitFor(); - } catch (IOException | InterruptedException e) { - throw new ModelCheckingException(e); - } - - // check if we need to delete the ETF - if (!keepFiles && !etf.delete()) { - throw new ModelCheckingException("Could not delete file: " + etf.getAbsolutePath()); - } - - final L result; - - if (ltsmin.exitValue() == 1) { - // we have found a counterexample - commandLines.clear(); - - final File fsm; - try { - // create a file for the FSM - fsm = File.createTempFile("gcf2fsm", ".fsm"); - } catch (IOException ioe) { - throw new ModelCheckingException(ioe); - } - - // add the ltsmin-convert binary - commandLines.add(LTSminUtil.LTSMIN_CONVERT); - - // use the GCF as input - commandLines.add(gcf.getAbsolutePath()); - - // use the FSM as output - commandLines.add(fsm.getAbsolutePath()); - - // required option - commandLines.add("--rdwr"); - - final Process convert; - try { - // convert the GCF to FSM - ProcessBuilder processBuilder = new ProcessBuilder(commandLines); - convert = processBuilder.start(); - convert.waitFor(); - } catch (IOException | InterruptedException e) { - throw new ModelCheckingException(e); - } - - // check the conversion is successful - if (convert.exitValue() != 0) { - throw new ModelCheckingException("Could not convert gcf to fsm"); - } - - try { - // convert the FSM to a Lasso - result = fsm2Lasso(fsm, hypothesis); - - // check if we must keep the FSM file - if (!keepFiles && !fsm.delete()) { - throw new ModelCheckingException("Could not delete file: " + fsm.getAbsolutePath()); - } - } catch (IOException | FSMParseException e) { - throw new ModelCheckingException(e); - } - } else { - result = null; - } - - // check if we must keep the GCF - if (!keepFiles && !gcf.delete()) { - throw new ModelCheckingException("Could not delete file: " + gcf.getAbsolutePath()); - } - - return result; - } - - /** - * Lazy holder for checking availability of LTSMin binary. See - * - * Initialization-on-demand holder idiom - */ - private static class LazyBinaryChecker { - - /** - * Whether or not we made sure the LTSmin binaries can be run. - */ - private static boolean AVAILABLE = LTSminUtil.checkUsable(); - } - - public static final class BuilderDefaults { - - private BuilderDefaults() { - // prevent instantiation - } - - public static boolean keepFiles() { - return false; - } - - public static int minimumUnfolds() { - return 3; // super arbitrary number - } - - public static double multiplier() { - return 1.0; // quite arbitrary too - } - } -} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java deleted file mode 100644 index d8733e01ae..0000000000 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealy.java +++ /dev/null @@ -1,168 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.function.Function; - -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelChecker; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelCheckerLasso; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.serialization.fsm.parser.FSMParseException; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.util.automata.transout.MealyFilter; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.Alphabets; - -/** - * An LTL model checker using LTSmin for Mealy machines. - * - * A feature of this {@link de.learnlib.api.modelchecking.modelchecker.ModelChecker}, is that one can remove - * particular output symbols from the a given MealyMachine hypothesis. This is useful when those symbols are actually - * symbols representing system deadlocks. When checking LTL formulae special attention has to be given to deadlock - * situations. - * - * @author Jeroen Meijer - * - * @param the input type. - * @param the output type. - */ -public abstract class AbstractLTSminLTLMealy - extends AbstractLTSminLTL, MealyLasso> - implements MealyModelChecker>, MealyModelCheckerLasso { - - /** - * @see #getString2Output() - */ - private final Function string2Output; - - /** - * @see #getSkipOutputs() - * @see #setSkipOutputs(Collection) - */ - private Collection skipOutputs; - - /** - * Constructs a new AbstractLTSminLTLMealy. - * - * @param string2Output the function that transforms edges in the FSM file to actual output. - * @param skipOutputs the set of outputs that need to be skipped while writing the Mealy machine to ETF. - * - * @see AbstractLTSminLTL - */ - protected AbstractLTSminLTLMealy(boolean keepFiles, - Function string2Input, - Function string2Output, - int minimumUnfolds, - double multiplier, - Collection skipOutputs) { - super(keepFiles, string2Input, minimumUnfolds, multiplier); - this.string2Output = string2Output; - this.skipOutputs = skipOutputs == null ? Collections.emptyList() : skipOutputs; - } - - /** - * Gets a function that transforms edges in the FSM file to actual output. - * - * @return the Function. - */ - public Function getString2Output() { - return string2Output; - } - - /** - * Gets a set of outputs that need to be skipped while writing the Mealy machine to ETF. - * - * @return the Colleciton. - */ - public Collection getSkipOutputs() { - return skipOutputs; - } - - /** - * Sets a set of outputs that need to be skipped while writing the Mealy machine to ETF. - */ - public void setSkipOutputs(Collection skipOutputs) { - this.skipOutputs = skipOutputs; - } - - /** - * Converts the given {@code fsm} to a {@link CompactMealy}. - * - * @param fsm the FSM to convert. - * - * @return the {@link CompactMealy}. - * - * @throws IOException when {@code fsm} can not be read. - * @throws FSMParseException when {@code fsm} is invalid. - */ - protected abstract CompactMealy fsm2Mealy(File fsm) throws IOException, FSMParseException; - - /** - * Writes the {@link MealyMachine} to the {@code etf} file while pruning way the outputs given in - * {@link #getSkipOutputs()}. - * - * @param mealyMachine the {@link MealyMachine} to write. - * - * @see AbstractLTSminLTL#automaton2ETF(SimpleDTS, Collection, File) - * - * @throws IOException see {@link #mealy2ETF(MealyMachine, Collection, File)}. - */ - @Override - protected final void automaton2ETF(MealyMachine mealyMachine, Collection inputs, File etf) - throws IOException { - final Alphabet alphabet = Alphabets.fromCollection(inputs); - mealy2ETF(MealyFilter.pruneTransitionsWithOutput(mealyMachine, alphabet, skipOutputs), inputs, etf); - } - - /** - * Writes the given {@link MealyMachine} to the {@code etf} file. - * - * @param automaton the {@link MealyMachine} to write. - * @param inputs the alphabet. - * @param etf the file to write to. - * - * @throws IOException when {@code etf} can not be read. - */ - protected abstract void mealy2ETF(MealyMachine automaton, Collection inputs, File etf) - throws IOException; - - /** - * Converts the FSM to a Lasso. - * - * @param fsm the FSM to read. - * @param hypothesis the hypothesis used to compute the number of loop unfolds. - * - * @return the {@link MealyLasso}. - * - * @throws IOException see {@link #fsm2Mealy(File)}. - * @throws FSMParseException see {@link #fsm2Mealy(File)}. - */ - @Override - protected final MealyLasso fsm2Lasso(File fsm, MealyMachine hypothesis) - throws IOException, FSMParseException { - CompactMealy mealy = fsm2Mealy(fsm); - // miniminzation is generally not possible, since a Lasso is partial. - // mealy = HopcroftMinimization.minimizeMealy(mealy); - - return new MealyLasso<>(mealy, mealy.getInputAlphabet(), computeUnfolds(hypothesis.size())); - } -} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelChecker.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelChecker.java deleted file mode 100644 index 540202c7b4..0000000000 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelChecker.java +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import de.learnlib.api.modelchecking.counterexample.Lasso; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.ModelCheckerLasso; -import net.automatalib.automata.concepts.Output; -import net.automatalib.ts.simple.SimpleDTS; - -/** - * An {@link ModelCheckerLasso} that can unfold loops of lassos. - * - * Unfolding a lasso is done according to two conditions: - * 1. the lasso has to be unfolded a minimum number of times ({@link #getMinimumUnfolds()}. - * 2. the lasso has to be unfolded relative to the number of states in an hypothesis, multiplied by some double - * ({@link #getMultiplier()}. - * - * Note that one can unfold a lasso a fixed number of times if the multiplier is set to {@code 0.0}. - * Also note that a lasso needs to be unfolded at least once, and the multiplier can not be negative. - * - * @param the input type - * @param the automaton type - * @param

the property type - * @param the Lasso type - */ -public abstract class AbstractUnfoldingModelChecker & Output, - P, - L extends Lasso> - implements ModelCheckerLasso { - - /** - * The minimum number of unfolds. - * - * @see AbstractUnfoldingModelChecker - */ - private int minimumUnfolds; - - /** - * The multiplier. - * - * @see AbstractUnfoldingModelChecker - */ - private double multiplier; - - /** - * Constructs a new AbstractUnfoldingModelChecker. - * - * @param minimumUnfolds the minimum number of unfolds. - * @param multiplier the multiplier - * - * @throws IllegalArgumentException when {@code minimumUnfolds < 1 || multiplier < 0.0}. - */ - protected AbstractUnfoldingModelChecker(int minimumUnfolds, double multiplier) throws IllegalArgumentException { - setMinimumUnfolds(minimumUnfolds); - setMultiplier(multiplier); - } - - /** - * Compute the number of unfolds according to {@code size}. - * - * @param size the number of states in the hypothesis. - * - * @return the number of times the loop of a lasso has to be unfolded. - */ - protected final int computeUnfolds(int size) { - if (size < 1) { - throw new IllegalArgumentException("Illegal size: " + size); - } - final int relativeUnfolds = (int) Math.ceil(size * multiplier); - return Math.max(minimumUnfolds, relativeUnfolds); - } - - @Override - public int getMinimumUnfolds() { - assert minimumUnfolds > 0; - return minimumUnfolds; - } - - @Override - public void setMinimumUnfolds(int minimumUnfolds) throws IllegalArgumentException { - if (minimumUnfolds < 1) { - throw new IllegalArgumentException("must unfold at least once"); - } - this.minimumUnfolds = minimumUnfolds; - } - - @Override - public void setMultiplier(double multiplier) throws IllegalArgumentException { - if (multiplier < 0.0) { - throw new IllegalArgumentException("multiplier must be >= 0.0"); - } - this.multiplier = multiplier; - } - - @Override - public double getMultiplier() { - return multiplier; - } -} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java deleted file mode 100644 index bd5e2548f3..0000000000 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternating.java +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.function.Function; - -import com.github.misberner.buildergen.annotations.GenerateBuilder; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.serialization.etf.writer.Mealy2ETFWriterAlternating; -import net.automatalib.serialization.fsm.parser.FSM2MealyParserAlternating; -import net.automatalib.serialization.fsm.parser.FSMParseException; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.Alphabets; - -/** - * An LTL model checker using LTSmin for Mealy machines using alternating edge semantics. - *

- * The implementation uses {@link FSM2MealyParserAlternating}, and {@link Mealy2ETFWriterAlternating}, to read the - * {@link de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso}, and write the {@link MealyMachine} - * respectively. - * - * @param - * the input type - * @param - * the output type - * - * @author Jeroen Meijer - */ -public class LTSminLTLAlternating extends AbstractLTSminLTLMealy { - - @GenerateBuilder(defaults = BuilderDefaults.class) - public LTSminLTLAlternating(boolean keepFiles, - Function string2Input, - Function string2Output, - int minimumUnfolds, - double multiplier, - Collection skipOutputs) { - super(keepFiles, string2Input, string2Output, minimumUnfolds, multiplier, skipOutputs); - } - - @Override - protected CompactMealy fsm2Mealy(File fsm) throws IOException, FSMParseException { - return FSM2MealyParserAlternating.parse(fsm, getString2Input(), getString2Output()); - } - - @Override - protected void mealy2ETF(MealyMachine automaton, Collection inputs, File etf) - throws IOException { - final Alphabet alphabet = Alphabets.fromCollection(inputs); - Mealy2ETFWriterAlternating.write(etf, automaton, alphabet); - } -} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java deleted file mode 100644 index 02f94e61d2..0000000000 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFA.java +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.function.Function; - -import com.github.misberner.buildergen.annotations.GenerateBuilder; -import de.learnlib.api.exception.ModelCheckingException; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelCheckerLasso; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.fsa.MutableDFA; -import net.automatalib.automata.fsa.impl.compact.CompactDFA; -import net.automatalib.serialization.etf.writer.DFA2ETFWriter; -import net.automatalib.serialization.fsm.parser.FSM2DFAParser; -import net.automatalib.serialization.fsm.parser.FSMParseException; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.util.automata.copy.AutomatonCopyMethod; -import net.automatalib.util.automata.copy.AutomatonLowLevelCopy; -import net.automatalib.util.automata.fsa.DFAs; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.Alphabets; - -/** - * An LTL model checker using LTSmin for DFAs. - * - * An important feature of this {@link de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelChecker}, is - * that it will check if a given DFA hypothesis is prefix-closed. - * - * Another important feature is that rejecting states are NOT part of the LTS. This avoids the need for an - * unconditional fairness constraint in LTL formulae. - * - * @author Jeroen Meijer - * - * @see DFAs#isPrefixClosed(DFA, Alphabet) - * - * @param the input type - */ -public class LTSminLTLDFA - extends AbstractLTSminLTL, DFALasso> - implements DFAModelCheckerLasso { - - /** - * The index in the FSM state vector for accept/reject. - */ - public static final String LABEL_NAME = "label"; - - /** - * The value in the state vector for acceptance. - */ - public static final String LABEL_VALUE = "accept"; - - @GenerateBuilder(defaults = BuilderDefaults.class) - public LTSminLTLDFA(boolean keepFiles, Function string2Input, int minimumUnfolds, double multiplier) { - super(keepFiles, string2Input, minimumUnfolds, multiplier); - } - - - @Override - protected void automaton2ETF(DFA automaton, Collection inputs, File etf) throws IOException { - dfa2ETF(automaton, inputs, etf); - } - - /** - * Writes the given {@code dfa} to {@code etf}, while skipping rejecting states. - * - * @param dfa the DFA to write. - * @param inputs the alphabet. - * @param etf the file to write to. - * - * @param the state type - * - * @throws IOException see {@link DFA2ETFWriter#write(File, DFA, Alphabet)}. - */ - private void dfa2ETF(DFA dfa, Collection inputs, File etf) throws IOException { - // check that the DFA rejects the empty language - if (DFAs.acceptsEmptyLanguage(dfa)) { - throw new ModelCheckingException("DFA accepts the empty language, the LTS for such a DFA is not defined."); - } - - final Alphabet alphabet = Alphabets.fromCollection(inputs); - - // check the DFA is prefix-closed - if (!DFAs.isPrefixClosed(dfa, alphabet)) { - throw new ModelCheckingException("DFA is not prefix closed."); - } - - // remove all rejecting states - final MutableDFA copy = new CompactDFA<>(alphabet, dfa.size()); - AutomatonLowLevelCopy.copy(AutomatonCopyMethod.STATE_BY_STATE, dfa, inputs, copy, dfa::isAccepting, (s, i, t) -> true); - DFA2ETFWriter.write(etf, copy, alphabet); - } - - /** - * Converts the FSM file to a {@link DFALasso}. - * - * @param hypothesis the DFA used to compute the number of loop unrolls. - * - * @see AbstractLTSminLTL#fsm2Lasso(File, SimpleDTS) - */ - @Override - protected DFALasso fsm2Lasso(File fsm, DFA hypothesis) throws IOException, FSMParseException { - CompactDFA dfa = FSM2DFAParser.parse(fsm, getString2Input(), LABEL_NAME, LABEL_VALUE); - //dfa = DFAs.complete(dfa, dfa.getInputAlphabet()); - //dfa = HopcroftMinimization.minimizeDFA(dfa, dfa.getInputAlphabet()); - - return new DFALasso<>(dfa, dfa.getInputAlphabet(), computeUnfolds(hypothesis.size())); - } -} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java deleted file mode 100644 index 72cef64ad8..0000000000 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIO.java +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.function.Function; - -import com.github.misberner.buildergen.annotations.GenerateBuilder; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.serialization.etf.writer.Mealy2ETFWriterIO; -import net.automatalib.serialization.fsm.parser.FSM2MealyParserIO; -import net.automatalib.serialization.fsm.parser.FSMParseException; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.Alphabets; - -/** - * An LTL model checker using LTSmin for Mealy machines using alternating edge semantics. - *

- * The implementation uses {@link FSM2MealyParserIO}, and {@link Mealy2ETFWriterIO}, to read the - * {@link de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso}, and write the {@link MealyMachine} - * respectively. - * - * @param - * the input type - * @param - * the output type - * - * @author Jeroen Meijer - */ -public class LTSminLTLIO extends AbstractLTSminLTLMealy { - - @GenerateBuilder(defaults = BuilderDefaults.class) - public LTSminLTLIO(boolean keepFiles, - Function string2Input, - Function string2Output, - int minimumUnfolds, - double multiplier, - Collection skipOutputs) { - super(keepFiles, string2Input, string2Output, minimumUnfolds, multiplier, skipOutputs); - } - - @Override - protected CompactMealy fsm2Mealy(File fsm) throws IOException, FSMParseException { - return FSM2MealyParserIO.parse(fsm, getString2Input(), getString2Output()); - } - - @Override - protected void mealy2ETF(MealyMachine automaton, Collection inputs, File etf) - throws IOException { - final Alphabet alphabet = Alphabets.fromCollection(inputs); - Mealy2ETFWriterIO.write(etf, automaton, alphabet); - } -} diff --git a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java b/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java deleted file mode 100644 index a64f98c03b..0000000000 --- a/model-checkers/src/main/java/de/learnlib/modelchecking/modelchecker/LTSminUtil.java +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import java.io.IOException; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; - -import de.learnlib.setting.LearnLibProperty; -import de.learnlib.setting.LearnLibSettings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A utility class that encapsulates certain technical aspects of LTSmin (e.g. accessibility of the binary, etc.) - * - * @author Jeroen Meijer - * @author frohme - */ -public final class LTSminUtil { - - /** - * Path to the "etf2lts-mc" binary. - */ - static final String ETF2LTS_MC; - - /** - * Path to the "ltsmin-convert" binary. - */ - static final String LTSMIN_CONVERT; - - private static final Logger LOGGER = LoggerFactory.getLogger(LTSminUtil.class); - - private static final String CHECK = "An exception occurred while checking if LTSmin is installed. " + - "Could not run binary '%s', the following exception occurred: %s. " + - "LTSmin can be obtained at https://ltsmin.utwente.nl. If you installed LTSmin " + - "in a non standard location you can set the property: '" + - LearnLibProperty.LTSMIN_PATH.getPropertyKey() + - "'. Setting the $PATH variable works too."; - - /** - * The exit code for running an LTSmin binary with --version. - */ - private static final int VERSION_EXIT = 255; - - static { - LearnLibSettings settings = LearnLibSettings.getInstance(); - - final String ltsMinPath = settings.getProperty(LearnLibProperty.LTSMIN_PATH, ""); - - ETF2LTS_MC = Paths.get(ltsMinPath, "etf2lts-mc").toString(); - LTSMIN_CONVERT = Paths.get(ltsMinPath, "ltsmin-convert").toString(); - } - - private LTSminUtil() { - throw new AssertionError(); - } - - /** - * Checks whether the required binaries for the {@link AbstractLTSminLTL LTSmin modelchecker} can be executed, by - * performing a version check. - * - * @return {@code true} if the binary returned with the expected exit value, {@code false} otherwise. - * - * @see #ETF2LTS_MC - * @see #LTSMIN_CONVERT - */ - public static boolean checkUsable() { - return checkUsable(ETF2LTS_MC) && checkUsable(LTSMIN_CONVERT); - } - - /** - * Checks whether the given binary can be executed, by performing a version check. - * - * @param bin - * the binary to check. - * - * @return {@code true} if the binary returned with the expected exit value, {@code false} otherwise. - */ - private static boolean checkUsable(String bin) { - - // the command lines for the ProcessBuilder - final List commandLines = new ArrayList<>(); - - // add the binary - commandLines.add(bin); - - // just run a version check - commandLines.add("--version"); - - final Process check; - try { - ProcessBuilder processBuilder = new ProcessBuilder(commandLines); - check = processBuilder.start(); - check.waitFor(); - } catch (IOException | InterruptedException e) { - LOGGER.error(String.format(CHECK, bin, e.toString()), e); - return false; - } - - if (check.exitValue() != VERSION_EXIT) { - LOGGER.error(String.format(CHECK, bin, String.format("Command '%s --version' did not exit with 255", bin))); - return false; - } - - return true; - } -} diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java deleted file mode 100644 index 122e399950..0000000000 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLMealyTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import java.io.File; -import java.util.HashSet; - -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.util.automata.builders.AutomatonBuilders; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import net.automatalib.words.impl.Alphabets; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public abstract class AbstractLTSminLTLMealyTest> - extends AbstractLTSminLTLTest, M, MealyLasso> { - - @SuppressWarnings("unchecked") - @Test - public void testSkipOutputs() throws Exception { - final HashSet skip = new HashSet<>(); - skip.add("1"); - getModelChecker().setSkipOutputs(skip); - - final Alphabet alphabet = Alphabets.fromArray("a"); - final MealyMachine mealy = AutomatonBuilders.forMealy( - new CompactMealy(alphabet) - ).from("q0").on("a").withOutput("1").loop().withInitial("q0").create(); - - AbstractLTSminLTLMealy spy = Mockito.spy(getModelChecker()); - - File etf = File.createTempFile("tmp", ".etf"); - etf.deleteOnExit(); - - spy.automaton2ETF(mealy, alphabet, etf); - - // test the transition is removed from the Mealy machine - ArgumentCaptor> modifiedMealy = ArgumentCaptor.forClass(MealyMachine.class); - Mockito.verify(spy).mealy2ETF(modifiedMealy.capture(), Mockito.eq(alphabet), Mockito.eq(etf)); - Assert.assertEquals(modifiedMealy.getValue().computeOutput(Word.fromSymbols("a")), Word.epsilon()); - if (!etf.delete()) { - throw new Exception(); - } - } -} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java deleted file mode 100644 index 42bf7a7a32..0000000000 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractLTSminLTLTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import de.learnlib.api.modelchecking.counterexample.Lasso; -import net.automatalib.automata.concepts.Output; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.Alphabets; -import org.testng.Assert; -import org.testng.SkipException; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * Tests for AbstractLTSminLTL with arbitrary LTSs. - * - * @author Jeroen Meijer - */ -public abstract class AbstractLTSminLTLTest & Output, - M extends AbstractLTSminLTL, - L extends Lasso> - extends AbstractUnfoldingModelCheckerTest { - - private final Alphabet alphabet = Alphabets.fromArray("a", "b"); - - private L lasso; - - private A automaton; - - private String falseProperty; - - public Alphabet getAlphabet() { - return alphabet; - } - - protected abstract L createLasso(); - - protected abstract A createAutomaton(); - - protected abstract String createFalseProperty(); - - @BeforeClass - public void setupBeforeClass() { - if (!LTSminUtil.checkUsable()) { - throw new SkipException("LTSmin not installed"); - } - } - - @BeforeMethod - public void setUp() throws Exception { - super.setUp(); - lasso = createLasso(); - automaton = createAutomaton(); - falseProperty = createFalseProperty(); - } - - /** - * First test for the absence of a counterexample, then test for the presence. - */ - @Test - public void testFindCounterExample() { - Object lasso = getModelChecker().findCounterExample(automaton, alphabet, "true"); - Assert.assertNull(lasso); - - L actualLasso = getModelChecker().findCounterExample(automaton, alphabet, falseProperty); - Assert.assertEquals(actualLasso.getWord(), this.lasso.getWord()); - } -} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java deleted file mode 100644 index a2bb9989bc..0000000000 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/AbstractUnfoldingModelCheckerTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public abstract class AbstractUnfoldingModelCheckerTest> { - - private M modelChecker; - - public M getModelChecker() { - return modelChecker; - } - - protected abstract M createModelChecker(); - - @BeforeMethod - public void setUp() throws Exception { - modelChecker = createModelChecker(); - } - - @Test - public void testComputeUnfolds() { - Assert.assertEquals(modelChecker.computeUnfolds(1), 3); - modelChecker.setMultiplier(2.0); - Assert.assertEquals(modelChecker.computeUnfolds(2), 4); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testComputeUnfoldsExcept() { - modelChecker.computeUnfolds(0); - } - - @Test - public void testSetMinimumUnfolds() { - modelChecker.setMinimumUnfolds(1337); - Assert.assertEquals(modelChecker.getMinimumUnfolds(), 1337); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testSetMinimumUnfoldsExcept() { - modelChecker.setMinimumUnfolds(0); - } - - @Test - public void testSetMultiplier() { - modelChecker.setMultiplier(1337.0); - Assert.assertEquals(modelChecker.getMultiplier(), 1337.0, 0.0); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testSetMultiplierExcept() { - modelChecker.setMultiplier(-1.0); - } -} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternatingTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternatingTest.java deleted file mode 100644 index 504fa93f93..0000000000 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLAlternatingTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.util.automata.builders.AutomatonBuilders; - -/** - * Tests whether LTSminLTLAlternating actually uses alternating edge semantics. - * - * @see LTSminLTLIOTest - * - * @author Jeroen Meijer - */ -public class LTSminLTLAlternatingTest extends AbstractLTSminLTLMealyTest> { - - @Override - protected LTSminLTLAlternating createModelChecker() { - return new LTSminLTLAlternatingBuilder().withString2Input(s -> s). - withString2Output(s -> s).create(); - } - - @Override - protected MealyLasso createLasso() { - return new MealyLasso<>(createAutomaton(), getAlphabet(), 4); - } - - @Override - protected MealyMachine createAutomaton() { - return AutomatonBuilders.forMealy(new CompactMealy(getAlphabet())). - withInitial("q0"). - from("q0").on("a").withOutput("1").loop().create(); - } - - @Override - protected String createFalseProperty() { - return "X letter == \"a\""; - } -} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java deleted file mode 100644 index 3be7a88d0b..0000000000 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLDFATest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import de.learnlib.api.exception.ModelCheckingException; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.util.automata.builders.AutomatonBuilders; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public class LTSminLTLDFATest extends AbstractLTSminLTLTest, LTSminLTLDFA, DFALasso> { - - @Override - protected LTSminLTLDFA createModelChecker() { - return new LTSminLTLDFABuilder().withString2Input(s -> s).create(); - } - - @Override - protected DFALasso createLasso() { - return new DFALasso<>(createAutomaton(), getAlphabet(), 4); - } - - @Override - protected DFA createAutomaton() { - return AutomatonBuilders.newDFA(getAlphabet()). - withInitial("q0").withAccepting("q0"). - from("q0").on("a").loop().create(); - } - - @Override - protected String createFalseProperty() { - return "letter == \"b\""; - } - - /** - * Test that a {@link ModelCheckingException} is thrown when a {@link DFA} is not prefix-closed. - */ - @Test(expectedExceptions = ModelCheckingException.class) - public void testPrefixClosed() { - final DFA dfa = AutomatonBuilders.newDFA(getAlphabet()). - withInitial("q0").withAccepting("q1"). - from("q0").on("a").to("q1").create(); - - getModelChecker().findCounterExample(dfa, getAlphabet(), "true"); - } - - /** - * Test that a {@link ModelCheckingException} is thrown when a {@link DFA} accepts the empty language. - */ - @Test(expectedExceptions = ModelCheckingException.class) - public void testEmptyLanguage() { - final DFA dfa = AutomatonBuilders.newDFA(getAlphabet()). - withInitial("q0").from("q0").on("a").loop().from("q0").on("b").loop().create(); - - getModelChecker().findCounterExample(dfa, getAlphabet(), "true"); - } -} \ No newline at end of file diff --git a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIOTest.java b/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIOTest.java deleted file mode 100644 index ea42f070af..0000000000 --- a/model-checkers/src/test/java/de/learnlib/modelchecking/modelchecker/LTSminLTLIOTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.modelchecking.modelchecker; - -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.util.automata.builders.AutomatonBuilders; - -/** - * Tests whether LTSminLTLAlternating actually uses regular edge semantics. - * - * @see LTSminLTLAlternatingTest - * - * @author Jeroen Meijer - */ -public class LTSminLTLIOTest extends AbstractLTSminLTLMealyTest> { - - @Override - protected LTSminLTLIO createModelChecker() { - return new LTSminLTLIOBuilder().withString2Input(s -> s).withString2Output(s -> s).create(); - } - - @Override - protected MealyLasso createLasso() { - return new MealyLasso<>(createAutomaton(), getAlphabet(), 4); - } - - @Override - protected MealyMachine createAutomaton() { - return AutomatonBuilders.forMealy(new CompactMealy(getAlphabet())). - withInitial("q0"). - from("q0").on("a").withOutput("1").loop().create(); - } - - @Override - protected String createFalseProperty() { - return "input == \"b\""; - } -} \ No newline at end of file diff --git a/model-checkers/src/test/resources/test.etf b/model-checkers/src/test/resources/test.etf deleted file mode 100644 index 90b4450941..0000000000 --- a/model-checkers/src/test/resources/test.etf +++ /dev/null @@ -1,26 +0,0 @@ -begin state -id:id -end state -begin edge -letter:letter -end edge -begin init -0 -end init -begin sort id -"0" -end sort -begin sort letter -"a" -"b" -end sort -begin trans -0/0 0 -end trans -begin sort label -"reject" -"accept" -end sort -begin map label:label -0 1 -end map \ No newline at end of file diff --git a/model-checkers/src/test/resources/test.fsm b/model-checkers/src/test/resources/test.fsm deleted file mode 100644 index ba8b550409..0000000000 --- a/model-checkers/src/test/resources/test.fsm +++ /dev/null @@ -1,9 +0,0 @@ -ltl(0) buchi -id(1) id "0" -label(2) label "reject" "accept" -buchi_accept(0) LTL_bool -weak_ltl_progress(0) LTL_bool ---- - 0 0 1 1 0 ---- -1 1 "a" diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java index 12e0e63536..c8d2f64a8e 100644 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java @@ -22,11 +22,11 @@ import javax.annotation.Nullable; -import de.learnlib.api.exception.ModelCheckingException; import de.learnlib.api.oracle.BlackBoxOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.exception.ModelCheckingException; import net.automatalib.words.Word; /** diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java index 4e7240fb12..00040932fc 100644 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java @@ -22,11 +22,11 @@ import javax.annotation.Nullable; -import de.learnlib.api.exception.ModelCheckingException; import de.learnlib.api.oracle.BlackBoxOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.exception.ModelCheckingException; import net.automatalib.words.Word; /** diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java index f41d92f296..d9c61f22f4 100644 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java @@ -19,14 +19,6 @@ import javax.annotation.Nullable; -import de.learnlib.api.exception.ModelCheckingException; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelChecker; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.DFAModelCheckerLasso; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelChecker; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker.MealyModelCheckerLasso; import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxProperty; import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; @@ -42,6 +34,14 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.exception.ModelCheckingException; +import net.automatalib.modelchecking.Lasso.DFALasso; +import net.automatalib.modelchecking.Lasso.MealyLasso; +import net.automatalib.modelchecking.ModelChecker; +import net.automatalib.modelchecking.ModelChecker.DFAModelChecker; +import net.automatalib.modelchecking.ModelChecker.MealyModelChecker; +import net.automatalib.modelchecking.ModelCheckerLasso.DFAModelCheckerLasso; +import net.automatalib.modelchecking.ModelCheckerLasso.MealyModelCheckerLasso; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Word; @@ -265,7 +265,7 @@ public DFABBPropertyDFALasso( } public static class MealyBBPropertyMealyLasso - extends ModelCheckingBBProperty, I, Word, MealyLasso> + extends ModelCheckingBBProperty, I, Word, MealyLasso> implements MealyBlackBoxProperty { public MealyBBPropertyMealyLasso( diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java index 2d59590c3e..45df15bd94 100644 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java +++ b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java @@ -19,15 +19,15 @@ import java.util.List; import java.util.SortedSet; -import de.learnlib.api.modelchecking.counterexample.Lasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; import de.learnlib.api.oracle.EmptinessOracle.LassoEmptinessOracle; import de.learnlib.api.oracle.OmegaMembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; import de.learnlib.oracle.AbstractBreadthFirstOracle; import net.automatalib.automata.concepts.Output; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.Lasso.DFALasso; +import net.automatalib.modelchecking.Lasso.MealyLasso; import net.automatalib.words.Word; /** @@ -128,7 +128,7 @@ public DFALassoDFAEmptinessOracle(OmegaMembershipOracle membershi } public static class MealyLassoMealyEmptinessOracle - extends AbstractLassoAutomatonEmptinessOracle, S, I, Word> + extends AbstractLassoAutomatonEmptinessOracle, S, I, Word> implements MealyLassoEmptinessOracle { public MealyLassoMealyEmptinessOracle(OmegaMembershipOracle> membershipOracle) { diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java index 78159c5de5..6dba532778 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java @@ -17,11 +17,11 @@ import java.util.Collection; -import de.learnlib.api.modelchecking.modelchecker.ModelChecker; import de.learnlib.api.oracle.EmptinessOracle; import de.learnlib.api.oracle.InclusionOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.concepts.Output; +import net.automatalib.modelchecking.ModelChecker; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; import net.automatalib.words.impl.Alphabets; diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java index f6036f6d4b..17c8682bba 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java @@ -15,25 +15,11 @@ */ package de.learnlib.oracle.emptiness; -import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; -import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.examples.dfa.ExampleAngluin; -import de.learnlib.examples.mealy.ExampleCoffeeMachine; -import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; -import de.learnlib.oracle.AbstractBreadthFirstOracle; import de.learnlib.oracle.AbstractBreadthFirstOracleTest; -import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.DFABFEmptinessOracle; -import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.MealyBreadthFirstEmptinessOracle; import net.automatalib.automata.concepts.Output; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -75,110 +61,4 @@ public void testFindCounterExample() { Assert.assertEquals(query, cex); } - public static class DFABFEmptinessOracleTest - extends AbstractBreadthFirstEmptinessOracleTest, Integer, Boolean> { - - @Mock - private DFAMembershipOracle dfaMembershipOracle; - - @Mock - private DFAMembershipOracle dfaMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final DefaultQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(0, 0))) { - q.answer(false); - } else { - q.answer(true); - } - return null; - }).when(dfaMembershipOracle).processQuery(ArgumentMatchers.any()); - } - - @Override - protected DFA createAutomaton() { - return ExampleAngluin.constructMachine(); - } - - @Override - protected AbstractBreadthFirstEmptinessOracle, Integer, Boolean> createBreadthFirstEmptinessOracle() { - return new DFABFEmptinessOracle<>(5, dfaMembershipOracle); - } - - @Override - protected Alphabet createAlphabet() { - return ExampleAngluin.createInputAlphabet(); - } - - @Override - protected DefaultQuery createQuery() { - return new DefaultQuery<>(Word.fromSymbols(1, 1), true); - } - - @Override - protected AbstractBreadthFirstOracle, - Character, - Boolean, - DefaultQuery> createBreadthFirstOracle(int maxWords) { - return new DFABFEmptinessOracle<>(maxWords, dfaMembershipOracle2); - } - } - - public static class MealyBFEmptinessOracleTest - extends AbstractBreadthFirstEmptinessOracleTest, Input, Word> { - - @Mock - private MealyMembershipOracle mealyMembershipOracle; - - @Mock - private MealyMembershipOracle mealyMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final DefaultQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(Input.POD))) { - q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; - }).when(mealyMembershipOracle).processQuery(ArgumentMatchers.any()); - } - - @Override - protected AbstractBreadthFirstEmptinessOracle, Input, Word> - createBreadthFirstEmptinessOracle() { - return new MealyBreadthFirstEmptinessOracle<>(5, mealyMembershipOracle); - } - - @Override - protected MealyMachine createAutomaton() { - return ExampleCoffeeMachine.constructMachine(); - } - - @Override - protected Alphabet createAlphabet() { - return ExampleCoffeeMachine.createInputAlphabet(); - } - - @Override - protected DefaultQuery> createQuery() { - return new DefaultQuery<>(Word.epsilon(), - Word.fromSymbols(Input.POD), - Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); - } - - @Override - protected AbstractBreadthFirstOracle, - Character, - Word, - DefaultQuery>> createBreadthFirstOracle(int maxWords) { - return new MealyBreadthFirstEmptinessOracle<>(maxWords, mealyMembershipOracle2); - } - } } diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java index e39a03bbbb..a1dde3a3a9 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java @@ -15,32 +15,11 @@ */ package de.learnlib.oracle.emptiness; -import java.util.ArrayList; -import java.util.List; - -import de.learnlib.api.modelchecking.counterexample.Lasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.DFALasso; -import de.learnlib.api.modelchecking.counterexample.Lasso.MealyLasso; -import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; -import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.OmegaQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracle; import de.learnlib.oracle.AbstractBreadthFirstOracleTest; -import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.DFALassoDFAEmptinessOracle; -import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.fsa.impl.compact.CompactDFA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.modelchecking.Lasso; import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -79,124 +58,4 @@ public void testFindCounterExample() { Assert.assertEquals(query, cex); } - public static class DFALassoDFAEmptinessOracleTest - extends AbstractLassoAutomatonEmptinessTest, Boolean> { - - @Mock - private DFAOmegaMembershipOracle dfaOmegaMembershipOracle; - - @Mock - private DFAOmegaMembershipOracle dfaOmegaMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final OmegaQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { - q.answer(true); - final List states = new ArrayList<>(); - states.add(0); - states.add(0); - states.add(0); - states.add(0); - q.setStates(states); - } else { - q.answer(false); - } - return null; - }).when(dfaOmegaMembershipOracle).processQuery(ArgumentMatchers.any()); - Mockito.when(dfaOmegaMembershipOracle.isSameState(ArgumentMatchers.any(), - ArgumentMatchers.any(), - ArgumentMatchers.any(), - ArgumentMatchers.any())).thenReturn(true); - } - - @Override - protected AbstractLassoAutomatonEmptinessOracle, ?, String, ?> - createLassoAutomatonEmptinessOracle() { - return new DFALassoDFAEmptinessOracle<>(dfaOmegaMembershipOracle); - } - - @Override - protected DFALasso createLasso() { - final DFA dfa = AutomatonBuilders.forDFA(new CompactDFA<>(ALPHABET)). - from("q0").on("a").loop().withAccepting("q0").withInitial("q0").create(); - return new DFALasso<>(dfa, ALPHABET, 3); - } - - @Override - protected DefaultQuery createQuery() { - return new DefaultQuery<>(Word.fromSymbols("a", "a", "a"), true); - } - - @Override - protected AbstractBreadthFirstOracle, - Character, - Boolean, - OmegaQuery> createBreadthFirstOracle(int maxWords) { - return new DFALassoDFAEmptinessOracle<>(dfaOmegaMembershipOracle2); - } - } - - public static class MealyLassoMealyEmptinessOracleTest - extends AbstractLassoAutomatonEmptinessTest, Word> { - - @Mock - private MealyOmegaMembershipOracle mealyOmegaMembershipOracle; - - @Mock - private MealyOmegaMembershipOracle mealyOmegaMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final OmegaQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { - q.answer(Word.fromSymbols("1", "1", "1")); - final List states = new ArrayList<>(); - states.add(0); - states.add(0); - states.add(0); - states.add(0); - q.setStates(states); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; - }).when(mealyOmegaMembershipOracle).processQuery(ArgumentMatchers.any()); - Mockito.when(mealyOmegaMembershipOracle.isSameState(ArgumentMatchers.any(), - ArgumentMatchers.any(), - ArgumentMatchers.any(), - ArgumentMatchers.any())).thenReturn(true); - } - - @Override - protected AbstractLassoAutomatonEmptinessOracle, ?, String, ?> - createLassoAutomatonEmptinessOracle() { - return new MealyLassoMealyEmptinessOracle<>(mealyOmegaMembershipOracle); - } - - @Override - protected MealyLasso createLasso() { - final MealyMachine mealy = AutomatonBuilders.forMealy( - new CompactMealy(ALPHABET)). - from("q0").on("a").withOutput("1").loop().withInitial("q0").create(); - return new MealyLasso<>(mealy, ALPHABET, 3); - } - - @Override - protected DefaultQuery> createQuery() { - return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols("a", "a", "a"), Word.fromSymbols("1", "1", "1")); - } - - @Override - protected AbstractBreadthFirstOracle, - Character, - Word, - OmegaQuery>> createBreadthFirstOracle(int maxWords) { - return new MealyLassoMealyEmptinessOracle<>(mealyOmegaMembershipOracle2); - } - } } diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java new file mode 100644 index 0000000000..2849e585de --- /dev/null +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java @@ -0,0 +1,83 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.examples.dfa.ExampleAngluin; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.DFABFEmptinessOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class DFABFEmptinessOracleTest + extends AbstractBreadthFirstEmptinessOracleTest, Integer, Boolean> { + + @Mock + private DFAMembershipOracle dfaMembershipOracle; + + @Mock + private DFAMembershipOracle dfaMembershipOracle2; + + @BeforeMethod + public void setUp() { + super.setUp(); + Mockito.doAnswer(invocation -> { + final DefaultQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(0, 0))) { + q.answer(false); + } else { + q.answer(true); + } + return null; + }).when(dfaMembershipOracle).processQuery(ArgumentMatchers.any()); + } + + @Override + protected DFA createAutomaton() { + return ExampleAngluin.constructMachine(); + } + + @Override + protected AbstractBreadthFirstEmptinessOracle, Integer, Boolean> createBreadthFirstEmptinessOracle() { + return new DFABFEmptinessOracle<>(5, dfaMembershipOracle); + } + + @Override + protected Alphabet createAlphabet() { + return ExampleAngluin.createInputAlphabet(); + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols(1, 1), true); + } + + @Override + protected AbstractBreadthFirstOracle, Character, Boolean, DefaultQuery> createBreadthFirstOracle( + int maxWords) { + return new DFABFEmptinessOracle<>(maxWords, dfaMembershipOracle2); + } +} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoDFAEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoDFAEmptinessOracleTest.java new file mode 100644 index 0000000000..3a6f9d0de1 --- /dev/null +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoDFAEmptinessOracleTest.java @@ -0,0 +1,95 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.DFALassoDFAEmptinessOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.modelchecking.DFALassoImpl; +import net.automatalib.modelchecking.Lasso.DFALasso; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class DFALassoDFAEmptinessOracleTest extends AbstractLassoAutomatonEmptinessTest, Boolean> { + + @Mock + private DFAOmegaMembershipOracle dfaOmegaMembershipOracle; + + @Mock + private DFAOmegaMembershipOracle dfaOmegaMembershipOracle2; + + @BeforeMethod + public void setUp() { + super.setUp(); + Mockito.doAnswer(invocation -> { + final OmegaQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { + q.answer(true); + final List states = new ArrayList<>(); + states.add(0); + states.add(0); + states.add(0); + states.add(0); + q.setStates(states); + } else { + q.answer(false); + } + return null; + }).when(dfaOmegaMembershipOracle).processQuery(ArgumentMatchers.any()); + Mockito.when(dfaOmegaMembershipOracle.isSameState(ArgumentMatchers.any(), + ArgumentMatchers.any(), + ArgumentMatchers.any(), + ArgumentMatchers.any())).thenReturn(true); + } + + @Override + protected AbstractLassoAutomatonEmptinessOracle, ?, String, ?> createLassoAutomatonEmptinessOracle() { + return new DFALassoDFAEmptinessOracle<>(dfaOmegaMembershipOracle); + } + + @Override + protected DFALassoImpl createLasso() { + final DFA dfa = AutomatonBuilders.forDFA(new CompactDFA<>(ALPHABET)). + from("q0").on("a").loop().withAccepting("q0").withInitial("q0").create(); + return new DFALassoImpl<>(dfa, ALPHABET, 3); + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols("a", "a", "a"), true); + } + + @Override + protected AbstractBreadthFirstOracle, Character, Boolean, OmegaQuery> createBreadthFirstOracle( + int maxWords) { + return new DFALassoDFAEmptinessOracle<>(dfaOmegaMembershipOracle2); + } +} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java new file mode 100644 index 0000000000..3936ce2057 --- /dev/null +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java @@ -0,0 +1,86 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.examples.mealy.ExampleCoffeeMachine; +import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.MealyBreadthFirstEmptinessOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class MealyBFEmptinessOracleTest + extends AbstractBreadthFirstEmptinessOracleTest, Input, Word> { + + @Mock + private MealyMembershipOracle mealyMembershipOracle; + + @Mock + private MealyMembershipOracle mealyMembershipOracle2; + + @BeforeMethod + public void setUp() { + super.setUp(); + Mockito.doAnswer(invocation -> { + final DefaultQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(Input.POD))) { + q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); + } else { + q.answer(Word.fromSymbols("not-an-output")); + } + return null; + }).when(mealyMembershipOracle).processQuery(ArgumentMatchers.any()); + } + + @Override + protected AbstractBreadthFirstEmptinessOracle, Input, Word> createBreadthFirstEmptinessOracle() { + return new MealyBreadthFirstEmptinessOracle<>(5, mealyMembershipOracle); + } + + @Override + protected MealyMachine createAutomaton() { + return ExampleCoffeeMachine.constructMachine(); + } + + @Override + protected Alphabet createAlphabet() { + return ExampleCoffeeMachine.createInputAlphabet(); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), + Word.fromSymbols(Input.POD), + Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); + } + + @Override + protected AbstractBreadthFirstOracle, Character, Word, DefaultQuery>> createBreadthFirstOracle( + int maxWords) { + return new MealyBreadthFirstEmptinessOracle<>(maxWords, mealyMembershipOracle2); + } +} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoMealyEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoMealyEmptinessOracleTest.java new file mode 100644 index 0000000000..657f2542ce --- /dev/null +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoMealyEmptinessOracleTest.java @@ -0,0 +1,97 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.modelchecking.Lasso.MealyLasso; +import net.automatalib.modelchecking.MealyLassoImpl; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class MealyLassoMealyEmptinessOracleTest + extends AbstractLassoAutomatonEmptinessTest, Word> { + + @Mock + private MealyOmegaMembershipOracle mealyOmegaMembershipOracle; + + @Mock + private MealyOmegaMembershipOracle mealyOmegaMembershipOracle2; + + @BeforeMethod + public void setUp() { + super.setUp(); + Mockito.doAnswer(invocation -> { + final OmegaQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { + q.answer(Word.fromSymbols("1", "1", "1")); + final List states = new ArrayList<>(); + states.add(0); + states.add(0); + states.add(0); + states.add(0); + q.setStates(states); + } else { + q.answer(Word.fromSymbols("not-an-output")); + } + return null; + }).when(mealyOmegaMembershipOracle).processQuery(ArgumentMatchers.any()); + Mockito.when(mealyOmegaMembershipOracle.isSameState(ArgumentMatchers.any(), + ArgumentMatchers.any(), + ArgumentMatchers.any(), + ArgumentMatchers.any())).thenReturn(true); + } + + @Override + protected AbstractLassoAutomatonEmptinessOracle, ?, String, ?> createLassoAutomatonEmptinessOracle() { + return new MealyLassoMealyEmptinessOracle<>(mealyOmegaMembershipOracle); + } + + @Override + protected MealyLasso createLasso() { + final MealyMachine mealy = + AutomatonBuilders.forMealy(new CompactMealy(ALPHABET)). + from("q0").on("a").withOutput("1").loop().withInitial("q0").create(); + return new MealyLassoImpl<>(mealy, ALPHABET, 3); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols("a", "a", "a"), Word.fromSymbols("1", "1", "1")); + } + + @Override + protected AbstractBreadthFirstOracle, Character, Word, OmegaQuery>> createBreadthFirstOracle( + int maxWords) { + return new MealyLassoMealyEmptinessOracle<>(mealyOmegaMembershipOracle2); + } +} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java index 2d5738c96f..057322e60f 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java @@ -15,25 +15,11 @@ */ package de.learnlib.oracle.inclusion; -import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; -import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.examples.dfa.ExampleAngluin; -import de.learnlib.examples.mealy.ExampleCoffeeMachine; -import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; -import de.learnlib.oracle.AbstractBreadthFirstOracle; import de.learnlib.oracle.AbstractBreadthFirstOracleTest; -import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.DFABreadthFirstInclusionOracle; -import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; import net.automatalib.automata.concepts.Output; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -75,106 +61,4 @@ public void testFindCounterExample() { Assert.assertEquals(query, cex); } - public static class DFABreadthFirstInclusionOracleTest - extends AbstractBreadthFirstInclusionOracleTest, Integer, Boolean> { - - @Mock - private DFAMembershipOracle dfaMembershipOracle; - - @Mock - private DFAMembershipOracle dfaMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final DefaultQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(0, 0))) { - q.answer(true); - } else { - q.answer(false); - } - return null; - }).when(dfaMembershipOracle).processQuery(ArgumentMatchers.any()); - } - - @Override - protected DFA createAutomaton() { - return ExampleAngluin.constructMachine(); - } - - @Override - protected AbstractBreadthFirstInclusionOracle, Integer, Boolean> createBreadthFirstInclusionOracle() { - return new DFABreadthFirstInclusionOracle<>(5, dfaMembershipOracle); - } - - @Override - protected Alphabet createAlphabet() { - return ExampleAngluin.createInputAlphabet(); - } - - @Override - protected DefaultQuery createQuery() { - return new DefaultQuery<>(Word.fromSymbols(1, 1), false); - } - - @Override - protected AbstractBreadthFirstOracle, Character, Boolean, DefaultQuery> - createBreadthFirstOracle(int maxWords) { - return new DFABreadthFirstInclusionOracle<>(maxWords, dfaMembershipOracle2); - } - } - - public static class MealyBreadthFirstInclusionOracleTest - extends AbstractBreadthFirstInclusionOracleTest, Input, Word> { - - @Mock - private MealyMembershipOracle mealyMembershipOracle; - - @Mock - private MealyMembershipOracle mealyMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final DefaultQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(Input.WATER))) { - q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; - }).when(mealyMembershipOracle).processQuery(ArgumentMatchers.any()); - - } - - @Override - protected AbstractBreadthFirstInclusionOracle, Input, Word> - createBreadthFirstInclusionOracle() { - return new MealyBreadthFirstInclusionOracle<>(5, mealyMembershipOracle); - } - - @Override - protected MealyMachine createAutomaton() { - return ExampleCoffeeMachine.constructMachine(); - } - - @Override - protected Alphabet createAlphabet() { - return ExampleCoffeeMachine.createInputAlphabet(); - } - - @Override - protected DefaultQuery> createQuery() { - return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols(Input.POD), Word.fromSymbols("not-an-output")); - } - - @Override - protected AbstractBreadthFirstOracle, - Character, Word, DefaultQuery>> - createBreadthFirstOracle(int maxWords) { - return new MealyBreadthFirstInclusionOracle<>(maxWords, mealyMembershipOracle2); - } - } } diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/DFABreadthFirstInclusionOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/DFABreadthFirstInclusionOracleTest.java new file mode 100644 index 0000000000..90f54e58cc --- /dev/null +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/DFABreadthFirstInclusionOracleTest.java @@ -0,0 +1,83 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.inclusion; + +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.examples.dfa.ExampleAngluin; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.DFABreadthFirstInclusionOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class DFABreadthFirstInclusionOracleTest + extends AbstractBreadthFirstInclusionOracleTest, Integer, Boolean> { + + @Mock + private DFAMembershipOracle dfaMembershipOracle; + + @Mock + private DFAMembershipOracle dfaMembershipOracle2; + + @BeforeMethod + public void setUp() { + super.setUp(); + Mockito.doAnswer(invocation -> { + final DefaultQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(0, 0))) { + q.answer(true); + } else { + q.answer(false); + } + return null; + }).when(dfaMembershipOracle).processQuery(ArgumentMatchers.any()); + } + + @Override + protected DFA createAutomaton() { + return ExampleAngluin.constructMachine(); + } + + @Override + protected AbstractBreadthFirstInclusionOracle, Integer, Boolean> createBreadthFirstInclusionOracle() { + return new DFABreadthFirstInclusionOracle<>(5, dfaMembershipOracle); + } + + @Override + protected Alphabet createAlphabet() { + return ExampleAngluin.createInputAlphabet(); + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols(1, 1), false); + } + + @Override + protected AbstractBreadthFirstOracle, Character, Boolean, DefaultQuery> + createBreadthFirstOracle(int maxWords) { + return new DFABreadthFirstInclusionOracle<>(maxWords, dfaMembershipOracle2); + } +} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/MealyBreadthFirstInclusionOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/MealyBreadthFirstInclusionOracleTest.java new file mode 100644 index 0000000000..8ec198b0e2 --- /dev/null +++ b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/MealyBreadthFirstInclusionOracleTest.java @@ -0,0 +1,87 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.inclusion; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.examples.mealy.ExampleCoffeeMachine; +import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; +import de.learnlib.oracle.AbstractBreadthFirstOracle; +import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class MealyBreadthFirstInclusionOracleTest + extends AbstractBreadthFirstInclusionOracleTest, Input, Word> { + + @Mock + private MealyMembershipOracle mealyMembershipOracle; + + @Mock + private MealyMembershipOracle mealyMembershipOracle2; + + @BeforeMethod + public void setUp() { + super.setUp(); + Mockito.doAnswer(invocation -> { + final DefaultQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols(Input.WATER))) { + q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); + } else { + q.answer(Word.fromSymbols("not-an-output")); + } + return null; + }).when(mealyMembershipOracle).processQuery(ArgumentMatchers.any()); + + } + + @Override + protected AbstractBreadthFirstInclusionOracle, Input, Word> + createBreadthFirstInclusionOracle() { + return new MealyBreadthFirstInclusionOracle<>(5, mealyMembershipOracle); + } + + @Override + protected MealyMachine createAutomaton() { + return ExampleCoffeeMachine.constructMachine(); + } + + @Override + protected Alphabet createAlphabet() { + return ExampleCoffeeMachine.createInputAlphabet(); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols(Input.POD), Word.fromSymbols("not-an-output")); + } + + @Override + protected AbstractBreadthFirstOracle, + Character, Word, DefaultQuery>> + createBreadthFirstOracle(int maxWords) { + return new MealyBreadthFirstInclusionOracle<>(maxWords, mealyMembershipOracle2); + } +} diff --git a/pom.xml b/pom.xml index 0971b83bce..32a647e326 100644 --- a/pom.xml +++ b/pom.xml @@ -143,7 +143,6 @@ limitations under the License. examples oracles test-support - model-checkers From 9c188a06fcb660b2272784cd8a59d64960375eae Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 19 Jun 2018 16:41:05 +0200 Subject: [PATCH 057/125] travis: fix installation of LTSmin --- .travis.yml | 2 +- build-tools/install-ltsmin.sh | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8cf0d508e4..62fe15fdb8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ before_install: install: # install LTSmin - build-tools/install-ltsmin.sh - - PATH="$PATH:$HOME/ltsmin/bin" + - PATH="$PATH:$HOME/ltsmin/v3.0.0/bin" script: - mvn install -B -Pintegration-tests,code-analysis,bundles diff --git a/build-tools/install-ltsmin.sh b/build-tools/install-ltsmin.sh index 9fa3a49b33..06c0e2c506 100755 --- a/build-tools/install-ltsmin.sh +++ b/build-tools/install-ltsmin.sh @@ -1,10 +1,11 @@ #!/bin/bash -LTSMIN_NAME="ltsmin-v3.0.0-$TRAVIS_OS_NAME.tgz" +LTSMIN_VERSION=v3.0.0 +LTSMIN_NAME="ltsmin-${LTSMIN_VERSION}-$TRAVIS_OS_NAME.tgz" LTSMIN_URL="https://github.com/Meijuh/ltsmin/releases/download/v3.0.0/$LTSMIN_NAME" # test if we have a cached version -test -f "$HOME/ltsmin/bin/ltsmin-convert" -a -f "$HOME/ltsmin/bin/etf2lts-mc" && exit 0 +test -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/ltsmin-convert" -a -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/etf2lts-mc" && exit 0 # create the directoy where the binaries end up. mkdir -p "$HOME/ltsmin" From 591574677d853948a25bc6175128c6b31eb73d01 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 22 Jun 2018 11:15:59 +0200 Subject: [PATCH 058/125] examples: add exemplary logback config [skip ci] --- examples/src/main/resources/logback.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 examples/src/main/resources/logback.xml diff --git a/examples/src/main/resources/logback.xml b/examples/src/main/resources/logback.xml new file mode 100644 index 0000000000..c6e779da9e --- /dev/null +++ b/examples/src/main/resources/logback.xml @@ -0,0 +1,11 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %30.30(%logger{30}) - %msg%n + + + + + + + \ No newline at end of file From 3c9ed7690f61c75b8e1d857095416bf4ae6decc7 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sun, 24 Jun 2018 01:36:13 +0200 Subject: [PATCH 059/125] adjust to AutomataLib refactorings --- .../java/de/learnlib/algorithms/adt/automaton/ADTState.java | 6 +++--- .../de/learnlib/algorithms/adt/model/ObservationTree.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTState.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTState.java index 9dfce2ca05..7247263040 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTState.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTState.java @@ -19,7 +19,7 @@ import java.util.Set; import de.learnlib.api.AccessSequenceProvider; -import net.automatalib.automata.base.fast.AbstractFastDetState; +import net.automatalib.automata.base.fast.AbstractFastState; import net.automatalib.words.Word; /** @@ -32,7 +32,7 @@ * * @author frohme */ -public class ADTState extends AbstractFastDetState, ADTTransition> +public class ADTState extends AbstractFastState> implements AccessSequenceProvider { private final Set> incomingTransitions; @@ -54,7 +54,7 @@ public void setAccessSequence(Word accessSequence) { } @Override - public void clearTransition(final ADTTransition transition) { + public void clearTransitionObject(final ADTTransition transition) { if (transition != null) { final ADTState target = transition.getTarget(); if (target != null) { diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ObservationTree.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ObservationTree.java index 86adfa8e0d..1116fae439 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ObservationTree.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ObservationTree.java @@ -186,7 +186,7 @@ public void addState(final S newState, final Word accessSequence, final O out this.observationTree.getSuccessor(this.observationTree.getInitialState(), prefix); final FastMealyState target; - if (pred.getTransition(alphabet.getSymbolIndex(sym)) == null) { + if (pred.getTransitionObject(alphabet.getSymbolIndex(sym)) == null) { target = this.observationTree.addState(); this.observationTree.addTransition(pred, sym, target, output); } else { From 4719095997775788582180552b896c6da0f06c97 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sun, 24 Jun 2018 01:36:24 +0200 Subject: [PATCH 060/125] oracles: fixes and tests - fixed test for RandomWMethodOracle to actually test the RandomWMethodOracle - added test for RandomWpMethodOracle - added test for RandomWalkOracle - fixed RandomWMethod to use transitionCover and reformated JavaDoc --- .../equivalence/RandomWMethodEQOracle.java | 40 +++---- .../equivalence/RandomWpMethodEQOracle.java | 29 +++-- .../equivalence/mealy/RandomWalkEQOracle.java | 8 +- .../RandomWMethodEQOracleTest.java | 48 ++++---- .../RandomWpMethodEQOracleTest.java | 90 ++++++++++++++ .../mealy/RandomWalkEQOracleTest.java | 113 ++++++++++++++++++ 6 files changed, 266 insertions(+), 62 deletions(-) create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracleTest.java diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java index 4b38bf5e83..576fa5bef3 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java @@ -33,12 +33,16 @@ /** * Implements an equivalence test by applying the W-method test on the given hypothesis automaton. Generally the * Wp-method performs better in finding counter examples. Instead of enumerating the test suite in order, this is a - * sampling implementation: 1. sample uniformly from the states for a prefix 2. sample geometrically a random word 3. - * sample a word from the set of suffixes / state identifiers There are two parameters: minimalSize determines the - * minimal size of the random word, this is useful when one first performs a W(p)-method with some depth and continue - * with this randomized tester from that depth onward. The second parameter rndLength determines the expected length of - * the random word. (The expected length in effect is minimalSize + rndLength.) In the unbounded case it will not - * terminate for a correct hypothesis. + * sampling implementation: + *

+ * There are two parameters: minimalSize determines the minimal size of the random word, this is useful when one first + * performs a W(p)-method with some depth and continue with this randomized tester from that depth onward. The second + * parameter rndLength determines the expected length of the random word. (The expected length in effect is minimalSize + * + rndLength.) In the unbounded case it will not terminate for a correct hypothesis. * * @param * automaton type @@ -83,10 +87,7 @@ public RandomWMethodEQOracle(MembershipOracle sulOracle, int minimalSize, * @param bound * specifies the bound (set to 0 for unbounded). */ - public RandomWMethodEQOracle(MembershipOracle sulOracle, - int minimalSize, - int rndLength, - int bound) { + public RandomWMethodEQOracle(MembershipOracle sulOracle, int minimalSize, int rndLength, int bound) { this(sulOracle, minimalSize, rndLength, bound, new Random(), 1); } @@ -124,7 +125,7 @@ public RandomWMethodEQOracle(MembershipOracle sulOracle, * @param bound * specifies the bound (set to 0 for unbounded). * @param random - * custom Random generator. + * custom Random generator. * @param batchSize * size of the batches sent to the membership oracle */ @@ -154,8 +155,8 @@ private Stream> doGenerateTestWords(UniversalDeterministicAutomaton< Collection inputs) { // Note that we want to use ArrayLists because we want constant time random access // We will sample from this for a prefix - ArrayList> stateCover = new ArrayList<>(hypothesis.size()); - Covers.stateCover(hypothesis, inputs, stateCover); + ArrayList> transitionCover = new ArrayList<>(hypothesis.size()); + Covers.transitionCover(hypothesis, inputs, transitionCover); // Then repeatedly from this for a random word ArrayList arrayAlphabet = new ArrayList<>(inputs); @@ -165,7 +166,7 @@ private Stream> doGenerateTestWords(UniversalDeterministicAutomaton< Automata.characterizingSet(hypothesis, inputs, globalSuffixes); final Stream> result = - Stream.generate(() -> generateSingleTestWord(stateCover, arrayAlphabet, globalSuffixes)); + Stream.generate(() -> generateSingleTestWord(transitionCover, arrayAlphabet, globalSuffixes)); return bound > 0 ? result.limit(bound) : result; } @@ -195,13 +196,10 @@ private Word generateSingleTestWord(ArrayList> stateCover, return wb.toWord(); } - public static class DFARandomWMethodEQOracle - extends RandomWMethodEQOracle, I, Boolean> + public static class DFARandomWMethodEQOracle extends RandomWMethodEQOracle, I, Boolean> implements DFAEquivalenceOracle { - public DFARandomWMethodEQOracle(MembershipOracle mqOracle, - int minimalSize, - int rndLength) { + public DFARandomWMethodEQOracle(MembershipOracle mqOracle, int minimalSize, int rndLength) { super(mqOracle, minimalSize, rndLength); } @@ -235,9 +233,7 @@ public static class MealyRandomWMethodEQOracle extends RandomWMethodEQOracle, I, Word> implements MealyEquivalenceOracle { - public MealyRandomWMethodEQOracle(MembershipOracle> mqOracle, - int minimalSize, - int rndLength) { + public MealyRandomWMethodEQOracle(MembershipOracle> mqOracle, int minimalSize, int rndLength) { super(mqOracle, minimalSize, rndLength); } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java index 213a31bca3..ae2ee7078e 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java @@ -34,12 +34,16 @@ /** * Implements an equivalence test by applying the Wp-method test on the given hypothesis automaton, as described in * "Test Selection Based on Finite State Models" by S. Fujiwara et al. Instead of enumerating the test suite in order, - * this is a sampling implementation: 1. sample uniformly from the states for a prefix 2. sample geometrically a random - * word 3. sample a word from the set of suffixes / state identifiers (either local or global) There are two parameters: - * minimalSize determines the minimal size of the random word, this is useful when one first performs a W(p)-method with - * some depth and continue with this randomized tester from that depth onward. The second parameter rndLength determines - * the expected length of the random word. (The expected length in effect is minimalSize + rndLength.) In the unbounded - * case it will not terminate for a correct hypothesis. + * this is a sampling implementation: + *
    + *
  • 1. sample uniformly from the states for a prefix
  • + *
  • 2. sample geometrically a random word
  • + *
  • 3. sample a word from the set of suffixes / state identifiers
  • + *
+ * There are two parameters:minimalSize determines the minimal size of the random word, this is useful when one first + * performs a W(p)-method with some depth and continue with this randomized tester from that depth onward. The second + * parameter rndLength determines the expected length of the random word. (The expected length in effect is minimalSize + * + rndLength.) In the unbounded case it will not terminate for a correct hypothesis. * * @param
* automaton type @@ -126,7 +130,7 @@ public RandomWpMethodEQOracle(MembershipOracle sulOracle, * @param bound * specifies the bound (set to 0 for unbounded). * @param random - * custom Random generator. + * custom Random generator. * @param batchSize * size of the batches sent to the membership oracle */ @@ -218,13 +222,10 @@ private Word generateSingleTestWord(UniversalDeterministicAutomaton - extends RandomWpMethodEQOracle, I, Boolean> + public static class DFARandomWpMethodEQOracle extends RandomWpMethodEQOracle, I, Boolean> implements DFAEquivalenceOracle { - public DFARandomWpMethodEQOracle(MembershipOracle mqOracle, - int minimalSize, - int rndLength) { + public DFARandomWpMethodEQOracle(MembershipOracle mqOracle, int minimalSize, int rndLength) { super(mqOracle, minimalSize, rndLength); } @@ -258,9 +259,7 @@ public static class MealyRandomWpMethodEQOracle extends RandomWpMethodEQOracle, I, Word> implements MealyEquivalenceOracle { - public MealyRandomWpMethodEQOracle(MembershipOracle> mqOracle, - int minimalSize, - int rndLength) { + public MealyRandomWpMethodEQOracle(MembershipOracle> mqOracle, int minimalSize, int rndLength) { super(mqOracle, minimalSize, rndLength); } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracle.java index 5d22e5fee4..660c7758d2 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracle.java @@ -17,6 +17,7 @@ import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Random; import de.learnlib.api.SUL; @@ -67,7 +68,7 @@ public class RandomWalkEQOracle implements MealyEquivalenceOracle { */ private long steps; /** - * flag for reseting step count after every search. + * flag for resetting step count after every search. */ private boolean resetStepCount; @@ -141,13 +142,12 @@ private DefaultQuery> doFindCounterExample(MealyMachine> ce = new DefaultQuery<>(wbIn.toWord()); ce.answer(wbOut.toWord()); return ce; diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java index e92adc7e66..0333794c38 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java @@ -15,14 +15,18 @@ */ package de.learnlib.oracle.equivalence; -import java.util.Random; +import java.util.HashSet; +import java.util.Set; import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; -import net.automatalib.automata.concepts.SuffixOutput; +import de.learnlib.examples.dfa.ExamplePaulAndMary; +import de.learnlib.oracle.equivalence.RandomWMethodEQOracle.DFARandomWMethodEQOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.util.automata.Automata; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.Symbol; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -30,28 +34,30 @@ /** * @author frohme */ -public class RandomWMethodEQOracleTest - extends AbstractEQOracleTest, Character, Boolean> { +public class RandomWMethodEQOracleTest extends AbstractEQOracleTest, Symbol, Boolean> { - private static final int RANDOM_SEED; - private static final Alphabet ALPHABET; private static final int MAX_TESTS; private static final int MIN_LENGTH; private static final int MAX_LENGTH; private int numberOfGeneratedQueries; + private DFA dfa; + private Set> transitionCover; + private Set> characterizingSet; static { - RANDOM_SEED = 42; - ALPHABET = Alphabets.characters('1', '6'); - MAX_TESTS = 100; - MIN_LENGTH = 25; - MAX_LENGTH = 100; + MAX_TESTS = 1000; + MIN_LENGTH = 0; + MAX_LENGTH = 5; } @BeforeClass public void setUp() { this.numberOfGeneratedQueries = 0; + this.dfa = ExamplePaulAndMary.constructMachine(); + + this.transitionCover = new HashSet<>(Automata.transitionCover(this.dfa, getAlphabet())); + this.characterizingSet = new HashSet<>(Automata.characterizingSet(this.dfa, getAlphabet())); } @Test(dependsOnMethods = "testGeneratedEQQueries") @@ -60,26 +66,26 @@ public void testNumberOfTotalQueries() { } @Override - protected void checkGeneratedQuery(Word query) { + protected void checkGeneratedQuery(Word query) { numberOfGeneratedQueries++; - Assert.assertTrue(query.length() <= MAX_LENGTH); - Assert.assertTrue(query.length() >= MIN_LENGTH); + transitionCover.stream().filter(w -> w.isPrefixOf(query)).findAny().orElseThrow(AssertionError::new); + characterizingSet.stream().filter(w -> w.isSuffixOf(query)).findAny().orElseThrow(AssertionError::new); } @Override - protected EquivalenceOracle, Character, Boolean> getOracle(MembershipOracle mOracle) { - return new RandomWordsEQOracle<>(mOracle, MIN_LENGTH, MAX_TESTS, MAX_LENGTH, new Random(RANDOM_SEED)); + protected EquivalenceOracle, Symbol, Boolean> getOracle(MembershipOracle mOracle) { + return new DFARandomWMethodEQOracle<>(mOracle, MIN_LENGTH, MAX_LENGTH, MAX_TESTS); } @Override - protected SuffixOutput getHypothesis() { - return (prefix, suffix) -> Boolean.TRUE; + protected DFA getHypothesis() { + return dfa; } @Override - protected Alphabet getAlphabet() { - return ALPHABET; + protected Alphabet getAlphabet() { + return ExamplePaulAndMary.createInputAlphabet(); } } diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracleTest.java new file mode 100644 index 0000000000..4465dbc345 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracleTest.java @@ -0,0 +1,90 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.HashSet; +import java.util.Set; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.examples.dfa.ExamplePaulAndMary; +import de.learnlib.oracle.equivalence.RandomWpMethodEQOracle.DFARandomWpMethodEQOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.util.automata.Automata; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Symbol; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class RandomWpMethodEQOracleTest extends AbstractEQOracleTest, Symbol, Boolean> { + + private static final int MAX_TESTS; + private static final int MIN_LENGTH; + private static final int MAX_LENGTH; + + private int numberOfGeneratedQueries; + private DFA dfa; + private Set> stateCover; + private Set> characterizingSet; + + static { + MAX_TESTS = 1000; + MIN_LENGTH = 0; + MAX_LENGTH = 5; + } + + @BeforeClass + public void setUp() { + this.numberOfGeneratedQueries = 0; + this.dfa = ExamplePaulAndMary.constructMachine(); + + this.stateCover = new HashSet<>(Automata.stateCover(this.dfa, getAlphabet())); + this.characterizingSet = new HashSet<>(Automata.characterizingSet(this.dfa, getAlphabet())); + } + + @Test(dependsOnMethods = "testGeneratedEQQueries") + public void testNumberOfTotalQueries() { + Assert.assertEquals(this.numberOfGeneratedQueries, MAX_TESTS); + } + + @Override + protected void checkGeneratedQuery(Word query) { + numberOfGeneratedQueries++; + + stateCover.stream().filter(w -> w.isPrefixOf(query)).findAny().orElseThrow(AssertionError::new); + characterizingSet.stream().filter(w -> w.isSuffixOf(query)).findAny().orElseThrow(AssertionError::new); + } + + @Override + protected EquivalenceOracle, Symbol, Boolean> getOracle(MembershipOracle mOracle) { + return new DFARandomWpMethodEQOracle<>(mOracle, MIN_LENGTH, MAX_LENGTH, MAX_TESTS); + } + + @Override + protected DFA getHypothesis() { + return dfa; + } + + @Override + protected Alphabet getAlphabet() { + return ExamplePaulAndMary.createInputAlphabet(); + } +} diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracleTest.java new file mode 100644 index 0000000000..3f4465ee53 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracleTest.java @@ -0,0 +1,113 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.mealy; + +import java.util.Random; + +import javax.annotation.Nullable; + +import de.learnlib.api.SUL; +import de.learnlib.api.exception.SULException; +import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class RandomWalkEQOracleTest { + + private static final int MAX_LENGTH; + private static final Alphabet ALPHABET; + + static { + MAX_LENGTH = 100; + ALPHABET = Alphabets.characters('a', 'f'); + } + + @Test + public void testOracle() { + + final DummySUL dummySUL = new DummySUL(); + + final MealyEquivalenceOracle mOracle = + new RandomWalkEQOracle<>(dummySUL, 0.01, MAX_LENGTH, new Random(42)); + + final DefaultQuery> ce = + mOracle.findCounterExample(new DummyMealy(ALPHABET), ALPHABET); + + Assert.assertNull(ce); + Assert.assertTrue(dummySUL.isCalledPost()); + } + + private static class DummySUL implements SUL { + + private boolean calledPre; + private boolean calledPost; + private int inputLength; + + private boolean firstInvocation = true; + + @Override + public void pre() { + calledPre = true; + inputLength = 0; + + if (firstInvocation) { + firstInvocation = false; + } else { + Assert.assertTrue(calledPost); + calledPost = false; + } + } + + @Override + public void post() { + calledPost = true; + Assert.assertTrue(inputLength <= MAX_LENGTH); + calledPre = false; + } + + public boolean isCalledPost() { + return this.calledPost; + } + + @Nullable + @Override + public Character step(@Nullable Character in) throws SULException { + Assert.assertTrue(this.calledPre); + inputLength++; + + return null; + } + } + + private static class DummyMealy extends CompactMealy { + + DummyMealy(Alphabet alphabet) { + super(alphabet); + final Integer init = super.addInitialState(); + + alphabet.forEach(s -> super.addTransition(init, s, init, null)); + } + } + +} From 9a12578430851e218e48220460f93eafe68f75d2 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sun, 24 Jun 2018 21:37:14 +0200 Subject: [PATCH 061/125] drivers: add tests for {SUL,}MapperCompositions --- drivers/mapper/pom.xml | 4 + .../mapper/MapperCompositionTest.java | 107 ++++++++ .../mapper/SULMapperCompositionTest.java | 253 ++++++++++++++++++ 3 files changed, 364 insertions(+) create mode 100644 drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java create mode 100644 drivers/mapper/src/test/java/de/learnlib/mapper/SULMapperCompositionTest.java diff --git a/drivers/mapper/pom.xml b/drivers/mapper/pom.xml index 4f50085642..5beb5c50d7 100644 --- a/drivers/mapper/pom.xml +++ b/drivers/mapper/pom.xml @@ -50,5 +50,9 @@ limitations under the License. jsr305 + + org.testng + testng + diff --git a/drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java b/drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java new file mode 100644 index 0000000000..40f1777c5b --- /dev/null +++ b/drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java @@ -0,0 +1,107 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.mapper; + +import de.learnlib.api.Mapper; +import net.automatalib.words.impl.Alphabets; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class MapperCompositionTest { + + private ToUpperCaseMapper toUpperCaseMapper; + private StringMapper toCharacterMapper; + + private Mapper mapper; + + @BeforeClass + public void setUp() { + toUpperCaseMapper = new ToUpperCaseMapper(); + toCharacterMapper = new StringMapper<>(Alphabets.characters('A', 'z')); + mapper = Mappers.compose(toCharacterMapper, toUpperCaseMapper); + } + + @Test + public void testComposition() { + mapper.pre(); + + // small 'a' to big 'A' + Character mappedInput = mapper.mapInput("a"); + Assert.assertNotNull(mappedInput); + Assert.assertEquals(mappedInput.charValue(), 'A'); + + // big 'B' to big 'B' + mappedInput = mapper.mapInput("B"); + Assert.assertNotNull(mappedInput); + Assert.assertEquals(mappedInput.charValue(), 'B'); + + // small 'a' to big 'A' + String mappedOutput = mapper.mapOutput('a'); + Assert.assertNotNull(mappedOutput); + Assert.assertEquals(mappedOutput, "A"); + + // big 'B' to big 'B' + mappedOutput = mapper.mapOutput('B'); + Assert.assertNotNull(mappedOutput); + Assert.assertEquals(mappedOutput, "B"); + + mapper.post(); + mapper.post(); + mapper.pre(); + mapper.pre(); + + Assert.assertEquals(3, this.toUpperCaseMapper.getPreCounter()); + Assert.assertEquals(2, this.toUpperCaseMapper.getPostCounter()); + } + + private static final class ToUpperCaseMapper implements Mapper { + + private int preCounter; + private int postCounter; + + @Override + public void pre() { + preCounter++; + } + + @Override + public void post() { + postCounter++; + } + + @Override + public Character mapInput(Character abstractInput) { + return Character.toUpperCase(abstractInput); + } + + @Override + public Character mapOutput(Character concreteOutput) { + return Character.toUpperCase(concreteOutput); + } + + int getPreCounter() { + return preCounter; + } + + int getPostCounter() { + return postCounter; + } + } +} diff --git a/drivers/mapper/src/test/java/de/learnlib/mapper/SULMapperCompositionTest.java b/drivers/mapper/src/test/java/de/learnlib/mapper/SULMapperCompositionTest.java new file mode 100644 index 0000000000..cb181422bc --- /dev/null +++ b/drivers/mapper/src/test/java/de/learnlib/mapper/SULMapperCompositionTest.java @@ -0,0 +1,253 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.mapper; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import de.learnlib.api.SUL; +import de.learnlib.api.exception.SULException; +import de.learnlib.mapper.api.SULMapper; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class SULMapperCompositionTest { + + private static final char OUTER_EXCEPTION_TRIGGER_CHAR = 'X'; + private static final char OUTER_EXCEPTION_RESULT = OUTER_EXCEPTION_TRIGGER_CHAR; + + private static final char INNER_EXCEPTION_TRIGGER_CHAR = 'Y'; + private static final int INNER_EXCEPTION_RESULT = (int) INNER_EXCEPTION_TRIGGER_CHAR; + + private static final char NESTED_EXCEPTION_TRIGGER_CHAR = 'Z'; + + private InnerUnwrappedMapper innerUnwrappedMapper; + private OuterWrappedMapper outerWrappedMapper; + private SUL mappedSUL; + + @BeforeClass + public void setUp() { + + innerUnwrappedMapper = new InnerUnwrappedMapper(); + outerWrappedMapper = new OuterWrappedMapper(); + + final SULMapper toUpperCase = + SULMappers.compose(outerWrappedMapper, innerUnwrappedMapper); + + this.mappedSUL = SULMappers.apply(toUpperCase, new MockSUL()); + } + + @Test + public void testComposition() { + + mappedSUL.pre(); + + // regular step + Character result = mappedSUL.step('A'); + Assert.assertNotNull(result); + Assert.assertEquals(result.charValue(), 'A'); + + // exception that returns INNER_EXCEPTION_RESULT + result = mappedSUL.step(INNER_EXCEPTION_TRIGGER_CHAR); + Assert.assertNotNull(result); + Assert.assertEquals(result.charValue(), INNER_EXCEPTION_TRIGGER_CHAR); + + // check repeatedOutput + result = mappedSUL.step('C'); + Assert.assertNotNull(result); + Assert.assertEquals(result.charValue(), INNER_EXCEPTION_TRIGGER_CHAR); + + // check repeatedOutput (for other exceptions) + result = mappedSUL.step(null); + Assert.assertNotNull(result); + Assert.assertEquals(result.charValue(), INNER_EXCEPTION_TRIGGER_CHAR); + + // reset + mappedSUL.post(); + mappedSUL.pre(); + + // regular step + result = mappedSUL.step('A'); + Assert.assertNotNull(result); + Assert.assertEquals(result.charValue(), 'A'); + + // exception that returns OUTER_EXCEPTION_RESULT + result = mappedSUL.step(OUTER_EXCEPTION_TRIGGER_CHAR); + Assert.assertNotNull(result); + Assert.assertEquals(result.charValue(), OUTER_EXCEPTION_RESULT); + + // check next output + result = mappedSUL.step('C'); + Assert.assertNotNull(result); + Assert.assertEquals(result.charValue(), 'C'); + + // check next output + result = mappedSUL.step(NESTED_EXCEPTION_TRIGGER_CHAR); + Assert.assertNotNull(result); + Assert.assertEquals(result.charValue(), NESTED_EXCEPTION_TRIGGER_CHAR); + + // check unhandled exception + Assert.assertThrows(NullPointerException.class, () -> mappedSUL.step(null)); + + // check pre/post invocations + mappedSUL.post(); + mappedSUL.pre(); + mappedSUL.pre(); + + Assert.assertEquals(4, this.innerUnwrappedMapper.getPreCounter()); + Assert.assertEquals(4, this.outerWrappedMapper.getPreCounter()); + + Assert.assertEquals(2, this.innerUnwrappedMapper.getPostCounter()); + Assert.assertEquals(2, this.outerWrappedMapper.getPostCounter()); + + Assert.assertFalse(mappedSUL.canFork()); + Assert.assertThrows(mappedSUL::fork); + } + + private static class MockSUL implements SUL { + + @Override + public void pre() {} + + @Override + public void post() {} + + @Nullable + @Override + public Character step(@Nullable Character in) throws SULException { + switch (in) { + case OUTER_EXCEPTION_TRIGGER_CHAR: + throw new OuterWrappedException(new IllegalArgumentException()); + case INNER_EXCEPTION_TRIGGER_CHAR: + throw new InnerUnwrappedException(); + case NESTED_EXCEPTION_TRIGGER_CHAR: + throw new NestedUnwrappedException(); + default: + return in; + } + } + } + + private static final class InnerUnwrappedMapper implements SULMapper { + + private int preCounter; + private int postCounter; + + @Override + public void pre() { + preCounter++; + } + + @Override + public void post() { + postCounter++; + } + + @Override + public Character mapInput(Integer abstractInput) { + return (char) abstractInput.intValue(); + } + + @Override + public Integer mapOutput(Character concreteOutput) { + return (int) concreteOutput; + } + + @Override + public MappedException mapUnwrappedException(RuntimeException exception) { + if (exception instanceof InnerUnwrappedException) { + return MappedException.repeatOutput(INNER_EXCEPTION_RESULT, INNER_EXCEPTION_RESULT); + } + + throw exception; + } + + int getPreCounter() { + return preCounter; + } + + int getPostCounter() { + return postCounter; + } + } + + private static final class OuterWrappedMapper implements SULMapper { + + private int preCounter; + private int postCounter; + + @Override + public void pre() { + preCounter++; + } + + @Override + public void post() { + postCounter++; + } + + @Override + public Integer mapInput(Character abstractInput) { + return (int) abstractInput; + } + + @Override + public Character mapOutput(Integer concreteOutput) { + return (char) concreteOutput.intValue(); + } + + @Override + public MappedException mapWrappedException(SULException exception) throws SULException { + if (exception instanceof OuterWrappedException) { + return MappedException.ignoreAndContinue(OUTER_EXCEPTION_RESULT); + } + + return MappedException.pass(exception); + } + + @Override + public MappedException mapUnwrappedException(RuntimeException exception) { + if (exception instanceof NestedUnwrappedException) { + return MappedException.ignoreAndContinue(NESTED_EXCEPTION_TRIGGER_CHAR); + } + + throw exception; + } + + int getPreCounter() { + return preCounter; + } + + int getPostCounter() { + return postCounter; + } + } + + private static final class InnerUnwrappedException extends RuntimeException {} + + private static final class NestedUnwrappedException extends RuntimeException {} + + private static final class OuterWrappedException extends SULException { + + OuterWrappedException(@Nonnull Throwable cause) { + super(cause); + } + } +} From 2e9c5af804f797379dec9b9eee09274bfc2a178f Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sun, 24 Jun 2018 21:47:02 +0200 Subject: [PATCH 062/125] api: cleanup Slf4jDelegator impl --- .../learnlib/api/logging/Slf4jDelegator.java | 332 +----------------- 1 file changed, 4 insertions(+), 328 deletions(-) diff --git a/api/src/main/java/de/learnlib/api/logging/Slf4jDelegator.java b/api/src/main/java/de/learnlib/api/logging/Slf4jDelegator.java index c9d2df5f11..763779cffc 100644 --- a/api/src/main/java/de/learnlib/api/logging/Slf4jDelegator.java +++ b/api/src/main/java/de/learnlib/api/logging/Slf4jDelegator.java @@ -16,342 +16,18 @@ package de.learnlib.api.logging; import org.slf4j.Logger; -import org.slf4j.Marker; +import org.slf4j.helpers.SubstituteLogger; /** * A simple {@link LearnLogger} implementation, that delegates all calls to a given {@link Logger} instance. * * @author frohme */ -public class Slf4jDelegator implements LearnLogger { - - private final Logger delegate; +public class Slf4jDelegator extends SubstituteLogger implements LearnLogger { public Slf4jDelegator(final Logger delegate) { - this.delegate = delegate; - } - - @Override - public String getName() { - return delegate.getName(); - } - - @Override - public boolean isTraceEnabled() { - return delegate.isTraceEnabled(); - } - - @Override - public boolean isTraceEnabled(Marker marker) { - return delegate.isTraceEnabled(marker); - } - - @Override - public void trace(String msg) { - delegate.trace(msg); - } - - @Override - public void trace(String format, Object arg) { - delegate.trace(format, arg); - } - - @Override - public void trace(String format, Object arg1, Object arg2) { - delegate.trace(format, arg1, arg2); - } - - @Override - public void trace(String format, Object... arguments) { - delegate.trace(format, arguments); - } - - @Override - public void trace(String msg, Throwable t) { - delegate.trace(msg, t); - } - - @Override - public void trace(Marker marker, String msg) { - delegate.trace(marker, msg); - } - - @Override - public void trace(Marker marker, String format, Object arg) { - delegate.trace(marker, format, arg); - } - - @Override - public void trace(Marker marker, String format, Object arg1, Object arg2) { - delegate.trace(marker, format, arg1, arg2); - } - - @Override - public void trace(Marker marker, String format, Object... argArray) { - delegate.trace(marker, format, argArray); - } - - @Override - public void trace(Marker marker, String msg, Throwable t) { - delegate.trace(marker, msg, t); - } - - @Override - public boolean isDebugEnabled() { - return delegate.isDebugEnabled(); - } - - @Override - public boolean isDebugEnabled(Marker marker) { - return delegate.isDebugEnabled(marker); - } - - @Override - public void debug(String msg) { - delegate.debug(msg); - } - - @Override - public void debug(String format, Object arg) { - delegate.debug(format, arg); - } - - @Override - public void debug(String format, Object arg1, Object arg2) { - delegate.debug(format, arg1, arg2); - } - - @Override - public void debug(String format, Object... arguments) { - delegate.debug(format, arguments); - } - - @Override - public void debug(String msg, Throwable t) { - delegate.debug(msg, t); - } - - @Override - public void debug(Marker marker, String msg) { - delegate.debug(marker, msg); - } - - @Override - public void debug(Marker marker, String format, Object arg) { - delegate.debug(marker, format, arg); - } - - @Override - public void debug(Marker marker, String format, Object arg1, Object arg2) { - delegate.debug(marker, format, arg1, arg2); - } - - @Override - public void debug(Marker marker, String format, Object... arguments) { - delegate.debug(marker, format, arguments); - } - - @Override - public void debug(Marker marker, String msg, Throwable t) { - delegate.debug(marker, msg, t); - } - - @Override - public boolean isInfoEnabled() { - return delegate.isInfoEnabled(); - } - - @Override - public boolean isInfoEnabled(Marker marker) { - return delegate.isInfoEnabled(marker); - } - - @Override - public void info(String msg) { - delegate.info(msg); - } - - @Override - public void info(String format, Object arg) { - delegate.info(format, arg); - } - - @Override - public void info(String format, Object arg1, Object arg2) { - delegate.info(format, arg1, arg2); - } - - @Override - public void info(String format, Object... arguments) { - delegate.info(format, arguments); - } - - @Override - public void info(String msg, Throwable t) { - delegate.info(msg, t); - } - - @Override - public void info(Marker marker, String msg) { - delegate.info(marker, msg); - } - - @Override - public void info(Marker marker, String format, Object arg) { - delegate.info(marker, format, arg); - } - - @Override - public void info(Marker marker, String format, Object arg1, Object arg2) { - delegate.info(marker, format, arg1, arg2); - } - - @Override - public void info(Marker marker, String format, Object... arguments) { - delegate.info(marker, format, arguments); - } - - @Override - public void info(Marker marker, String msg, Throwable t) { - delegate.info(marker, msg, t); - } - - @Override - public boolean isWarnEnabled() { - return delegate.isWarnEnabled(); - } - - @Override - public boolean isWarnEnabled(Marker marker) { - return delegate.isWarnEnabled(marker); - } - - @Override - public void warn(String msg) { - delegate.warn(msg); - } - - @Override - public void warn(String format, Object arg) { - delegate.warn(format, arg); - } - - @Override - public void warn(String format, Object... arguments) { - delegate.warn(format, arguments); - } - - @Override - public void warn(String format, Object arg1, Object arg2) { - delegate.warn(format, arg1, arg2); - } - - @Override - public void warn(String msg, Throwable t) { - delegate.warn(msg, t); - } - - @Override - public void warn(Marker marker, String msg) { - delegate.warn(marker, msg); - } - - @Override - public void warn(Marker marker, String format, Object arg) { - delegate.warn(marker, format, arg); - } - - @Override - public void warn(Marker marker, String format, Object arg1, Object arg2) { - delegate.warn(marker, format, arg1, arg2); - } - - @Override - public void warn(Marker marker, String format, Object... arguments) { - delegate.warn(marker, format, arguments); - } - - @Override - public void warn(Marker marker, String msg, Throwable t) { - delegate.warn(marker, msg, t); - } - - @Override - public boolean isErrorEnabled() { - return delegate.isErrorEnabled(); - } - - @Override - public boolean isErrorEnabled(Marker marker) { - return delegate.isErrorEnabled(marker); - } - - @Override - public void error(String msg) { - delegate.error(msg); - } - - @Override - public void error(String format, Object arg) { - delegate.error(format, arg); - } - - @Override - public void error(String format, Object arg1, Object arg2) { - delegate.error(format, arg1, arg2); - } - - @Override - public void error(String format, Object... arguments) { - delegate.error(format, arguments); - } - - @Override - public void error(String msg, Throwable t) { - delegate.error(msg, t); - } - - @Override - public void error(Marker marker, String msg) { - delegate.error(marker, msg); - } - - @Override - public void error(Marker marker, String format, Object arg) { - delegate.error(marker, format, arg); - } - - @Override - public void error(Marker marker, String format, Object arg1, Object arg2) { - delegate.error(marker, format, arg1, arg2); - } - - @Override - public void error(Marker marker, String format, Object... arguments) { - delegate.error(marker, format, arguments); - } - - @Override - public void error(Marker marker, String msg, Throwable t) { - delegate.error(marker, msg, t); - } - - @Override - public int hashCode() { - return delegate != null ? delegate.hashCode() : 0; + super(delegate.getName(), null, false); + super.setDelegate(delegate); } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Slf4jDelegator that = (Slf4jDelegator) o; - - return delegate != null ? delegate.equals(that.delegate) : that.delegate == null; - } } From f5e705d8cd6ece4b03f746e019c9fa3d5baab8bc Mon Sep 17 00:00:00 2001 From: Alexander Bainczyk Date: Sat, 21 Jul 2018 10:49:07 +0200 Subject: [PATCH 063/125] fixing platform dependent issues - replace hardcoded \n by platform independent line separators --- .../observationtable/OTUtils.java | 23 +++++++++++-------- .../writer/ObservationTableASCIIWriter.java | 4 ++-- .../writer/ObservationTableHTMLWriter.java | 20 ++++++++-------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/OTUtils.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/OTUtils.java index aeb3171157..798678567d 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/OTUtils.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/OTUtils.java @@ -35,15 +35,20 @@ public final class OTUtils { private static final String HTML_FILE_HEADER = - "\n" + "\n" + - "\n" + - "\n"; - private static final String HTML_FILE_FOOTER = "\n"; + "" + System.lineSeparator() + + "" + System.lineSeparator() + + "" + System.lineSeparator() + + "" + System.lineSeparator() + + "" + System.lineSeparator(); + + private static final String HTML_FILE_FOOTER = "" + System.lineSeparator(); private OTUtils() { throw new AssertionError("Constructor should never be invoked"); diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableASCIIWriter.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableASCIIWriter.java index 7640be44b3..e902357795 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableASCIIWriter.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableASCIIWriter.java @@ -140,7 +140,7 @@ private static void appendSeparatorRow(Appendable a, char sepChar, int[] colWidt a.append(sepChar).append('+').append(sepChar); appendRepeated(a, sepChar, colWidth[i]); } - a.append(sepChar).append("+\n"); + a.append(sepChar).append("+").append(System.lineSeparator()); } private static void appendContentRow(Appendable a, String[] content, int[] colWidth) throws IOException { @@ -150,7 +150,7 @@ private static void appendContentRow(Appendable a, String[] content, int[] colWi a.append(" | "); appendRightPadded(a, content[i], colWidth[i]); } - a.append(" |\n"); + a.append(" |").append(System.lineSeparator()); } private static void appendRepeated(Appendable a, char c, int count) throws IOException { diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableHTMLWriter.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableHTMLWriter.java index 16185a2e02..3d60f6f605 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableHTMLWriter.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/writer/ObservationTableHTMLWriter.java @@ -57,18 +57,18 @@ private void writeInternal(ObservationTable table, Appendable out) throws IOException { List> suffixes = table.getSuffixes(); - out.append("\n"); - out.append("\t\n"); + out.append("
").append(System.lineSeparator()); + out.append("\t").append(System.lineSeparator()); out.append("\t\t\n"); + .append("\" class=\"suffixes-header\">Suffixes").append(System.lineSeparator()); out.append("\t\t"); for (Word suffix : suffixes) { out.append(""); } - out.append("\n"); - out.append("\t\n"); - out.append("\t\n"); + out.append("").append(System.lineSeparator()); + out.append("\t").append(System.lineSeparator()); + out.append("\t").append(System.lineSeparator()); for (Row row : table.getShortPrefixRows()) { out.append("\t\t"); } - out.append("\n"); + out.append("").append(System.lineSeparator()); } - out.append("\t\t\n"); + out.append("\t\t").append(System.lineSeparator()); for (Row row : table.getLongPrefixRows()) { out.append("\t\t"); for (D value : table.rowContents(row)) { out.append(""); } - out.append("\n"); + out.append("").append(System.lineSeparator()); } - out.append("
PrefixSuffixes
").append(wordToString.apply(suffix)).append("
") @@ -77,20 +77,20 @@ private void writeInternal(ObservationTable table, for (D value : table.rowContents(row)) { out.append("").append(outputToString.apply(value)).append("
").append(wordToString.apply(row.getLabel())).append("").append(outputToString.apply(value)).append("
\n"); + out.append("").append(System.lineSeparator()); } } From ee1bb8f80c2c86a14b7f7479d7c9b70da2fa60d7 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 27 Jul 2018 16:34:08 +0200 Subject: [PATCH 064/125] add initial AppVeyor support --- .appveyor.yml | 35 +++++++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 36 insertions(+) create mode 100644 .appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000000..ff5b36df0d --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,35 @@ +version: '{build}' + +branches: + only: + - master + - develop + - release + +init: + - cmd: git config --global core.autocrlf true + - cmd: mvn --version + +environment: + matrix: + - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 + - JAVA_HOME: C:\Program Files\Java\jdk9 + - JAVA_HOME: C:\Program Files\Java\jdk10 + +install: + - IF DEFINED AUTOMATALIB_BRANCH (SET AL_BRANCH=%AUTOMATALIB_BRANCH%) ELSE (SET AL_BRANCH=%APPVEYOR_REPO_BRANCH%) + - IF DEFINED AUTOMATALIB_FORK (SET AL_FORK=%AUTOMATALIB_FORK%) ELSE (SET AL_FORK=LearnLib) + - cmd: git clone -b %AL_BRANCH% --single-branch https://github.com/%AL_FORK%/automatalib.git automatalib-checkout + - cmd: pushd automatalib-checkout + - cmd: mvn install -DskipTests + - cmd: popd + +cache: + - C:\Users\appveyor\.m2\ + +build_script: + - cmd: mvn install -B -Pintegration-tests + +test: off + +deploy: off \ No newline at end of file diff --git a/README.md b/README.md index 9ba64f2238..498ef7f005 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # LearnLib [![Build Status](https://travis-ci.org/LearnLib/learnlib.svg?branch=develop)](https://travis-ci.org/LearnLib/learnlib) +[![Build Status](https://ci.appveyor.com/api/projects/status/bc0co2w6vu58c2pr?svg=true)](https://ci.appveyor.com/project/mtf90/learnlib) [![Coverage Status](https://coveralls.io/repos/github/LearnLib/learnlib/badge.svg?branch=develop)](https://coveralls.io/github/LearnLib/learnlib?branch=develop) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/de.learnlib/learnlib-parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/de.learnlib/learnlib-parent) From ef1f073d06b788ec50c9a1c2760f9e1568e458a3 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 27 Jul 2018 16:34:29 +0200 Subject: [PATCH 065/125] travis: drop OracleJDK builds - these are now covered by AppVeyor --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 62fe15fdb8..2ed2064778 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,11 +45,8 @@ jobs: env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=10 -Dmaven.compiler.target=10" include: - jdk: openjdk8 - - jdk: oraclejdk8 - jdk: openjdk9 - - jdk: oraclejdk9 - jdk: openjdk10 - - jdk: oraclejdk10 - jdk: openjdk9 env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=9 -Dmaven.compiler.target=9" - jdk: openjdk10 From 554ab5fd3bbccc2121bd35bb7434d0cf96fecff2 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 27 Jul 2018 18:52:04 +0200 Subject: [PATCH 066/125] AppVeyor: update config - try to fix directory switching when build AutomataLib - copy documentation from .travis.yml regarding custom AutomataLib builds --- .appveyor.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index ff5b36df0d..a63d0a8172 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -17,12 +17,15 @@ environment: - JAVA_HOME: C:\Program Files\Java\jdk10 install: + # set environment variables "AUTOMATALIB_FORK" and "AUTOMATALIB_BRANCH" to build custom AutomataLib versions. + # Defaults are "LearnLib" and the current/targeted LearnLib branch (%APPVEYOR_REPO_BRANCH%, relies on the same + # naming conventions between AutomataLib and LearnLib branches). - IF DEFINED AUTOMATALIB_BRANCH (SET AL_BRANCH=%AUTOMATALIB_BRANCH%) ELSE (SET AL_BRANCH=%APPVEYOR_REPO_BRANCH%) - IF DEFINED AUTOMATALIB_FORK (SET AL_FORK=%AUTOMATALIB_FORK%) ELSE (SET AL_FORK=LearnLib) - cmd: git clone -b %AL_BRANCH% --single-branch https://github.com/%AL_FORK%/automatalib.git automatalib-checkout - - cmd: pushd automatalib-checkout + - cmd: cd automatalib-checkout - cmd: mvn install -DskipTests - - cmd: popd + - cmd: cd %APPVEYOR_BUILD_FOLDER% cache: - C:\Users\appveyor\.m2\ From 42347b19249f0aff0935c545f1c8e14ba6b95148 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 28 Jul 2018 21:40:09 +0200 Subject: [PATCH 067/125] git: ignore another Eclipse artifact [skip ci] --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fb081efc4e..c616ec0381 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ bin/ .settings/ .classpath .project +.factorypath #Intellij settings *.iml From 32019e745ddfc45530e4e9f36508146601c9d89d Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 20 Aug 2018 01:10:31 +0200 Subject: [PATCH 068/125] add .gitattributes mainly to deal with automatic newline encoding on different platforms --- .gitattributes | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..a29bf7823a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,36 @@ +# config based on https://github.com/alexkaratarakis/gitattributes + +# Handle line endings automatically for files detected as text +# and leave all files detected as binary untouched. +* text=auto + +# +# The above will handle all files NOT found below +# +# These files are text and should be normalized (Convert crlf => lf) +*.css text +*.dot text +*.htm text +*.html text +*.java text +*.properties text +*.py text +*.sh text +*.txt text +*.xml text +*.yml text + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.class binary +*.dll binary +*.dylib binary +*.ear binary +*.gif binary +*.ico binary +*.jar binary +*.jpg binary +*.jpeg binary +*.png binary +*.so binary +*.war binary From 4e16813f5427be2d9ab38e5da9420dfb959f211b Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 20 Aug 2018 01:12:17 +0200 Subject: [PATCH 069/125] update CI configs - drop JDK9 builds as it is EOL - travis: do not allow failure on target language level 10 - AppVeyor: set clone_depth to 50 commits --- .appveyor.yml | 3 ++- .travis.yml | 8 -------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index a63d0a8172..0c922a8b1f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,6 +6,8 @@ branches: - develop - release +clone_depth: 50 + init: - cmd: git config --global core.autocrlf true - cmd: mvn --version @@ -13,7 +15,6 @@ init: environment: matrix: - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - - JAVA_HOME: C:\Program Files\Java\jdk9 - JAVA_HOME: C:\Program Files\Java\jdk10 install: diff --git a/.travis.yml b/.travis.yml index 2ed2064778..e969bacee1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,17 +38,9 @@ script: jobs: fast_finish: true - allow_failures: - - jdk: openjdk9 - env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=9 -Dmaven.compiler.target=9" - - jdk: openjdk10 - env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=10 -Dmaven.compiler.target=10" include: - jdk: openjdk8 - - jdk: openjdk9 - jdk: openjdk10 - - jdk: openjdk9 - env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=9 -Dmaven.compiler.target=9" - jdk: openjdk10 env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=10 -Dmaven.compiler.target=10" - stage: coverage From ccfd4188ec485aede24d4f9df51e7d6e1367eae0 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 20 Aug 2018 09:33:22 +0200 Subject: [PATCH 070/125] bump javadoc plugin version - fixes error with fetching (not yet existing SNAPSHOT) AutomataLib javadoc links --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 32a647e326..c72a1ff163 100644 --- a/pom.xml +++ b/pom.xml @@ -204,7 +204,7 @@ limitations under the License. 1.6 2.9 0.8.0 - 3.0.0 + 3.0.1 1.0.0 3.10.0 2.5.3 From bb292702ca04de030883d068112e6c91fa651566 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 22 Aug 2018 13:01:43 +0200 Subject: [PATCH 071/125] travis: fixing connection timeouts in builds It seems, by default, travis adds sonatype and apache snapshot repositories to the maven build process, which results in build failures due to connection timeouts. Since we don't rely on any artifacts from these repositories, globally use a custom settings.xml that does not have these repositories configured. --- .travis.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index e969bacee1..e4588daabb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,12 @@ branches: - develop - release -before_install: +install: + # install LTSmin + - build-tools/install-ltsmin.sh + - PATH="$PATH:$HOME/ltsmin/v3.0.0/bin" + # override any "sane" defaults of Travis VMs + - cp ${TRAVIS_BUILD_DIR}/build-tools/travis-settings.xml ${HOME}/.m2/settings.xml # set Travis environment variables "AUTOMATALIB_FORK" and "AUTOMATALIB_BRANCH" to build custom AutomataLib versions. # Defaults are "LearnLib" and the current/targeted LearnLib branch ($TRAVIS_BRANCH, relies on the same naming # conventions between AutomataLib and LearnLib branches). @@ -28,11 +33,6 @@ before_install: - mvn install -DskipTests - popd -install: - # install LTSmin - - build-tools/install-ltsmin.sh - - PATH="$PATH:$HOME/ltsmin/v3.0.0/bin" - script: - mvn install -B -Pintegration-tests,code-analysis,bundles @@ -50,12 +50,10 @@ jobs: - mvn coveralls:report - stage: deploy jdk: openjdk8 # use openjdk build - before_install: true # skip building AutomataLib, because we actually want to link against the deployed artifacts. - install: true # skip the normal build script: skip # skip the normal build deploy: # define deployment in deploy phase, which is skipped for pull-requests provider: script - script: mvn --settings build-tools/travis-settings.xml -DskipTests=true deploy + script: mvn -DskipTests=true deploy on: branch: develop # only auto deploy snapshots From d70302434b53319f616c19e112354828844b7dad Mon Sep 17 00:00:00 2001 From: Jeroen Meijer Date: Tue, 25 Sep 2018 09:45:29 +0200 Subject: [PATCH 072/125] Improvements to black-box checking. (#59) * Travis: use latest official LTSmin release. * Several improvements related to black-box checking. - Remove the concept of a black-box oracle, instead implement an equivalent as an EquivalenceOracle (via an InclusionOracle). This avoids the need for a BBCExperiment. - The LassoOracle will now perform multiple omegaqueries for a single lasso. - Rename BlackBoxProperty to PropertyOracle, since in fact, it is an oracle. And place it in module learnlib-property-oracles. Now there is a clearer distinction between a property (typically indicated with parameter P), and an oracle for a property. - Since the module for black box oracles does not exist anymore, create a new module learnlib-emptiness-oracles, and move emptiness oracles there. Also inclusion oracles have been moved to learnlib-equivalence-oracles. - Move tests for lassos to AutomataLib. - Skip some PMD checks * oracles: refactor to match AutomataLib changes * various small cleanups - removed lombok dependency for now - removed wildcards in return types - cleanup dependency declarations (removed explicit versions/added source artifacts in distribution module) - removed obsolete PMD artifacts * travis: use global variable for LTSMIN_VERSION * Some generic cleanups - remove some redundant variables - fix typos in Javadoc - simplify method for answering OmegaQueries * some OmegaQuery related refactorings - replaced the 'states' attribute with a simple integer (periodicity) that describes the number of times, the loop has to be unrolled until a same state has been observed. - determine this value in the OmegaMembershipOracles and therefore remove #isSameState in AutomatonOracle. * api: fix OmegaQuery javadoc --- .travis.yml | 6 +- api/pom.xml | 4 - ...operty.java => LoggingPropertyOracle.java} | 79 ++--- .../learnlib/api/oracle/AutomatonOracle.java | 303 ++++++------------ .../learnlib/api/oracle/BlackBoxOracle.java | 167 +--------- .../learnlib/api/oracle/EmptinessOracle.java | 51 +-- .../learnlib/api/oracle/InclusionOracle.java | 49 ++- .../api/oracle/LassoEmptinessOracle.java | 46 +++ .../de/learnlib/api/oracle/LassoOracle.java | 111 +++++++ .../api/oracle/OmegaMembershipOracle.java | 30 +- .../api/oracle/OmegaQueryAnswerer.java | 11 +- .../learnlib/api/oracle/PropertyOracle.java | 105 ++++++ .../api/oracle/SingleQueryOmegaOracle.java | 14 +- .../api/oracle/SymbolQueryOracle.java | 2 +- .../de/learnlib/api/query/OmegaQuery.java | 118 ++++--- .../counterexample/AbstractLassoTest.java | 96 ------ .../counterexample/DFALassoTest.java | 92 ------ .../counterexample/MealyLassoTest.java | 100 ------ build-tools/install-ltsmin.sh | 3 +- .../de/learnlib/util/AbstractBFOracle.java | 111 +++++++ .../java/de/learnlib/util/BBCExperiment.java | 183 ----------- .../main/java/de/learnlib/util/MQUtil.java | 32 +- distribution/pom.xml | 16 +- examples/pom.xml | 12 +- .../examples/bbc/example1/Example.java | 48 ++- .../examples/bbc/example2/Example.java | 45 ++- .../examples/bbc/example3/Example.java | 50 ++- .../oracle/AbstractBreadthFirstOracle.java | 139 -------- .../blackbox/AbstractBlackBoxOracle.java | 76 ----- .../oracle/blackbox/CExFirstBBOracle.java | 121 ------- .../blackbox/DisproveFirstBBOracle.java | 121 ------- .../blackbox/ModelCheckingBBProperty.java | 279 ---------------- .../AbstractBreadthFirstEmptinessOracle.java | 64 ---- ...AbstractLassoAutomatonEmptinessOracle.java | 138 -------- .../AbstractBreadthFirstInclusionOracle.java | 61 ---- .../blackbox/AbstractBlackBoxOracleTest.java | 57 ---- .../oracle/blackbox/CExFirstBBOracleTest.java | 94 ------ .../blackbox/DisproveFirstBBOracleTest.java | 85 ----- .../blackbox/ModelCheckingBBPropertyTest.java | 129 -------- .../AbstractLassoAutomatonEmptinessTest.java | 61 ---- .../emptiness/DFABFEmptinessOracleTest.java | 83 ----- .../DFALassoDFAEmptinessOracleTest.java | 95 ------ .../emptiness/MealyBFEmptinessOracleTest.java | 86 ----- .../MealyLassoMealyEmptinessOracleTest.java | 97 ------ ...stractBreadthFirstInclusionOracleTest.java | 64 ---- .../DFABreadthFirstInclusionOracleTest.java | 83 ----- .../MealyBreadthFirstInclusionOracleTest.java | 87 ----- .../pom.xml | 46 +-- .../emptiness/AbstractBFEmptinessOracle.java | 56 ++++ .../emptiness/DFABFEmptinessOracle.java | 29 ++ .../DFALassoEmptinessOracleImpl.java | 30 ++ .../emptiness/LassoEmptinessOracleImpl.java | 70 ++++ .../emptiness/MealyBFEmptinessOracle.java | 30 ++ .../MealyLassoEmptinessOracleImpl.java | 31 ++ .../AbstractBFEmptinessOracleTest.java} | 40 ++- .../AbstractLassoEmptinessOracleImplTest.java | 112 +++++++ .../emptiness/DFABFEmptinessOracleTest.java | 67 ++++ .../DFALassoEmptinessOracleImplTest.java | 79 +++++ .../emptiness/MealyBFEmptinessOracleTest.java | 68 ++++ .../MealyLassoEmptinessOracleImplTest.java | 80 +++++ oracles/equivalence-oracles/pom.xml | 21 +- .../AbstractBFInclusionOracle.java | 53 +++ .../oracle/equivalence/CExFirstOracle.java | 117 +++++++ .../equivalence/DFABFInclusionOracle.java | 29 ++ .../equivalence/DisproveFirstOracle.java | 121 +++++++ .../oracle/equivalence/EQOracleChain.java | 4 + .../equivalence/MealyBFInclusionOracle.java | 30 ++ .../AbstractBFInclusionOracleTest.java | 73 +++++ .../equivalence/CExFirstOracleTest.java | 86 +++++ .../equivalence/DFABFInclusionOracleTest.java | 64 ++++ .../equivalence/DisproveFirstOracleTest.java | 86 +++++ .../MealyBFInclusionOracleTest.java | 65 ++++ .../membership/AbstractSULOmegaOracle.java | 68 ++-- .../membership/SimulatorOmegaOracle.java | 80 +++-- .../membership/SimulatorOmegaOracleTest.java | 33 +- oracles/pom.xml | 5 +- oracles/property-oracles/pom.xml | 36 +++ .../property/AbstractPropertyOracle.java | 97 ++++++ .../property/DFAFinitePropertyOracle.java | 51 +++ .../property/DFALassoPropertyOracle.java | 52 +++ .../property/MealyFinitePropertyOracle.java | 56 ++++ .../property/MealyLassoPropertyOracle.java | 56 ++++ pom.xml | 29 +- test-support/oracle-support/pom.xml | 46 +++ .../learnlib/oracle/AbstractBFOracleTest.java | 34 +- test-support/pom.xml | 1 + 86 files changed, 2752 insertions(+), 3283 deletions(-) rename api/src/main/java/de/learnlib/api/logging/{LoggingBlackBoxProperty.java => LoggingPropertyOracle.java} (51%) create mode 100644 api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/LassoOracle.java create mode 100644 api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java delete mode 100644 api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java delete mode 100644 api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java delete mode 100644 api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java create mode 100644 commons/util/src/main/java/de/learnlib/util/AbstractBFOracle.java delete mode 100644 commons/util/src/main/java/de/learnlib/util/BBCExperiment.java delete mode 100644 oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java delete mode 100644 oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java delete mode 100644 oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java delete mode 100644 oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java delete mode 100644 oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java delete mode 100644 oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java delete mode 100644 oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java delete mode 100644 oracles/bbc-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoDFAEmptinessOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoMealyEmptinessOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/DFABreadthFirstInclusionOracleTest.java delete mode 100644 oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/MealyBreadthFirstInclusionOracleTest.java rename oracles/{bbc-oracles => emptiness-oracles}/pom.xml (62%) create mode 100644 oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracle.java create mode 100644 oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracle.java create mode 100644 oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java create mode 100644 oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java create mode 100644 oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracle.java create mode 100644 oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java rename oracles/{bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java => emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java} (56%) create mode 100644 oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java create mode 100644 oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java create mode 100644 oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java create mode 100644 oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java create mode 100644 oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracle.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DFABFInclusionOracle.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracle.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DFABFInclusionOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracleTest.java create mode 100644 oracles/property-oracles/pom.xml create mode 100644 oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java create mode 100644 oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java create mode 100644 oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java create mode 100644 oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java create mode 100644 oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java create mode 100644 test-support/oracle-support/pom.xml rename oracles/bbc-oracles/src/test/java/de/learnlib/oracle/AbstractBreadthFirstOracleTest.java => test-support/oracle-support/src/main/java/de/learnlib/oracle/AbstractBFOracleTest.java (65%) diff --git a/.travis.yml b/.travis.yml index e4588daabb..b53d31b683 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,10 +19,14 @@ branches: - develop - release +env: + global: + - LTSMIN_VERSION=v3.0.2 + install: # install LTSmin - build-tools/install-ltsmin.sh - - PATH="$PATH:$HOME/ltsmin/v3.0.0/bin" + - PATH="$PATH:$HOME/ltsmin/$LTSMIN_VERSION/bin" # override any "sane" defaults of Travis VMs - cp ${TRAVIS_BUILD_DIR}/build-tools/travis-settings.xml ${HOME}/.m2/settings.xml # set Travis environment variables "AUTOMATALIB_FORK" and "AUTOMATALIB_BRANCH" to build custom AutomataLib versions. diff --git a/api/pom.xml b/api/pom.xml index 94a424bfdf..3d390a22d5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -82,10 +82,6 @@ limitations under the License. logback-classic test - - net.automatalib - automata-core - org.mockito mockito-core diff --git a/api/src/main/java/de/learnlib/api/logging/LoggingBlackBoxProperty.java b/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java similarity index 51% rename from api/src/main/java/de/learnlib/api/logging/LoggingBlackBoxProperty.java rename to api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java index 0beac3522b..0c341b10ba 100644 --- a/api/src/main/java/de/learnlib/api/logging/LoggingBlackBoxProperty.java +++ b/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java @@ -19,9 +19,7 @@ import javax.annotation.Nullable; -import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; -import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxProperty; -import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; +import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; @@ -29,66 +27,66 @@ import net.automatalib.words.Word; /** - * A BlackBoxProperty that performs logging. + * A PropertyOracle that performs logging. * - * This class will log whenever this property is disproved, or when a counterexample to an automaton is found (i.e. a + * This class will log whenever the property is disproved, or when a counterexample to an automaton is found (i.e. a * spurious counterexample is found). * * @author Jeroen Meijer * - * @param

the property type * @param the output type */ -public class LoggingBlackBoxProperty implements BlackBoxProperty { +public class LoggingPropertyOracle implements PropertyOracle { - private static final LearnLogger LOGGER = LearnLogger.getLogger(LoggingBlackBoxProperty.class); + private static final LearnLogger LOGGER = LearnLogger.getLogger(LoggingPropertyOracle.class); /** - * The wrapped {@link BlackBoxProperty}. + * The wrapped {@link PropertyOracle}. */ - private final BlackBoxProperty blackBoxProperty; + private final PropertyOracle propertyOracle; /** - * Constructs a new LogginBlackBoxProperty. + * Constructs a new LoggingPropertyOracle. * - * @param blackBoxProperty the {@link BlackBoxProperty} to wrap around. + * @param propertyOracle the {@link PropertyOracle} to wrap around. */ - public LoggingBlackBoxProperty(BlackBoxProperty blackBoxProperty) { - this.blackBoxProperty = blackBoxProperty; + public LoggingPropertyOracle(PropertyOracle propertyOracle) { + this.propertyOracle = propertyOracle; } @Override public boolean isDisproved() { - return blackBoxProperty.isDisproved(); + return propertyOracle.isDisproved(); } @Override public void setProperty(P property) { - blackBoxProperty.setProperty(property); + this.propertyOracle.setProperty(property); } @Override public P getProperty() { - return blackBoxProperty.getProperty(); + return propertyOracle.getProperty(); } @Nullable @Override public DefaultQuery getCounterExample() { - return blackBoxProperty.getCounterExample(); + return propertyOracle.getCounterExample(); } /** - * Try to disprove this property, and log whenever it is disproved. + * Try to disprove this propertyOracle, and log whenever it is disproved. * - * @see BlackBoxProperty#disprove(Object, Collection) + * @see PropertyOracle#disprove(Object, Collection) */ @Nullable @Override public DefaultQuery disprove(A hypothesis, Collection inputs) throws ModelCheckingException { - final DefaultQuery result = blackBoxProperty.disprove(hypothesis, inputs); + final DefaultQuery result = propertyOracle.disprove(hypothesis, inputs); if (result != null) { LOGGER.logEvent("Property violated: '" + toString() + "'"); LOGGER.logQuery("Counter example for property: " + getCounterExample()); @@ -100,12 +98,13 @@ public DefaultQuery disprove(A hypothesis, Collection inputs) /** * Try to find a counterexample to the given hypothesis, and log whenever such a spurious counterexample is found. * - * @see BlackBoxProperty#findCounterExample(Object, Collection) + * @see PropertyOracle#findCounterExample(Object, Collection) */ @Nullable @Override - public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { - final DefaultQuery result = blackBoxProperty.findCounterExample(hypothesis, inputs); + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws + ModelCheckingException { + final DefaultQuery result = propertyOracle.findCounterExample(hypothesis, inputs); if (result != null) { LOGGER.logEvent("Spurious counterexample found for property: '" + toString() + "'"); LOGGER.logCounterexample("Spurious counterexample: " + result); @@ -113,35 +112,25 @@ public DefaultQuery findCounterExample(A hypothesis, Collection extends LoggingBlackBoxProperty, I, Boolean> - implements DFABlackBoxProperty { + public static class DFALoggingPropertyOracle extends LoggingPropertyOracle, P, Boolean> + implements DFAPropertyOracle { - public DFALoggingBlackBoxProperty(DFABlackBoxProperty blackBoxProperty) { - super(blackBoxProperty); + public DFALoggingPropertyOracle(DFAPropertyOracle property) { + super(property); } } - public static class MealyLoggingBlackBoxProperty - extends LoggingBlackBoxProperty, I, Word> - implements MealyBlackBoxProperty { + public static class MealyLoggingPropertyOracle + extends LoggingPropertyOracle, P, Word> + implements MealyPropertyOracle { - public MealyLoggingBlackBoxProperty(MealyBlackBoxProperty blackBoxProperty) { - super(blackBoxProperty); + public MealyLoggingPropertyOracle(MealyPropertyOracle property) { + super(property); } } } diff --git a/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java b/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java index da4b76ea34..d0e6502493 100644 --- a/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java @@ -16,285 +16,194 @@ package de.learnlib.api.oracle; import java.util.Collection; +import java.util.Queue; +import java.util.Stack; import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.OmegaQuery; -import de.learnlib.api.query.Query; +import net.automatalib.automata.DeterministicAutomaton; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.modelchecking.Lasso; -import net.automatalib.modelchecking.Lasso.DFALasso; -import net.automatalib.modelchecking.Lasso.MealyLasso; -import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Word; /** - * Finds counterexamples (to particular claims), while generating words that are in a given hypothesis. - * - * @author Jeroen Meijer + * Finds counterexamples (to particular claims) to an hypothesis, while generating words that are in the given + * hypothesis. * * @param the automaton type * @param the input type * @param the output type - * @param the Query type + * + * @author Jeroen Meijer */ -public interface AutomatonOracle, I, D, Q extends Query> { +@ParametersAreNonnullByDefault +public interface AutomatonOracle, I, D> { /** - * Returns whether the given {@code query} is a counterexample to the given {@code hypothesis}. + * Returns whether the given input and output is a counter example for the given hypothesis. * - * @param hypothesis the hypothesis to check. - * @param query the query to check. + * @param hypothesis + * the hypothesis + * @param inputs + * the input sequence + * @param output + * the output corresponding to the input. * - * @return whether it is a counterexample. + * @return whether the given input and output is a counter example. */ - boolean isCounterExample(A hypothesis, Q query); + boolean isCounterExample(A hypothesis, Iterable inputs, @Nullable D output); /** - * Returns whether the given input word is a word in the given {@code hypthesis}. - * - * @param hypothesis the hypothesis to check. - * @param input the input to check. + * Returns the next input word, or {@code null} if there is no next input. + *

+ * Implementations could for example return words in a breadth-first, or depth-first manner. * - * @return whether the {@code input} is a word in the {@code hypothesis}. + * @return the next input word, or {@code null} if t here is no next input. */ - boolean isWord(A hypothesis, Word input); + @Nullable + Word nextInput(); /** - * Converts the given {@code query} to a {@link DefaultQuery}. - * - * @param query the {@link Query} to convert. + * Add a new input word. + *

+ * Implementations could add words to e.g. a {@link Stack}, or {@link Queue}. * - * @return the converted query. + * @param input + * the input word to add. */ - DefaultQuery asDefaultQuery(Q query); + void addWord(Word input); /** - * Returns the maximum number of words to generate. - * - * @return the maximum. + * Setup method which is called immediately before + * {@link #findCounterExample(DeterministicAutomaton, Collection, int)} is called. */ - int getMaxWords(); + void pre(); /** - * Process the given {@code input} word by returning an answered {@link Query}. - * - * @param hypothesis the hypothesis for which the {@code input} word is generated. - * @param input the input word for which the query needs to be answered. + * Returns the multiplier used to compute the number of queries this automaton oracle should perform to + * decide whether a given hypothesis is a counter example. * - * @return the answered query. + * @return the multiplier */ - Q processInput(A hypothesis, Word input); + double getMultiplier(); /** - * Returns the next input word. + * @see #getMultiplier() + * @param multiplier + * the multiplier + */ + void setMultiplier(double multiplier); + + /** + * Processes the given input. Implementations could use membership oracles to process the query. * - * Implementations could for example return words in a breadth-first, or depth-first manner. + * @param hypothesis + * the hypothesis. + * @param input + * the input to process. * - * @return the next input word. + * @return the processed query. */ - Word nextInput(); + DefaultQuery processInput(A hypothesis, Word input); /** - * Adds more input words given a {@code prefix} input word. - * - * @param hypothesis the hypothesis to add words for. - * @param inputs the alphabet. - * @param prefix the prefix to compute more words for. + * Adds words to a datastructure. The key part of the implementation is that undefined inputs will be skipped. + * + * @param hypothesis + * the automaton to add words for. + * @param inputs + * the input alphabet. + * @param prefix + * the current prefix to extend. */ default void addWords(A hypothesis, Collection inputs, Word prefix) { - for (I input: inputs) { - final Word word = prefix.append(input); + for (I i : inputs) { + final Word word = prefix.append(i); // skip undefined inputs - if (hypothesis.getState(word) != null) { + if (!hypothesis.getStates(word).isEmpty()) { addWord(word); } } } /** - * Add a new input word. + * Returns whether the given input is accepted by the given hypothesis. * - * Implementations could add words to e.g. a {@link java.util.Stack}, or {@link java.util.Queue}. + * @param hypothesis + * the hypothesis automaton. + * @param input + * the input. + * @param length + * the length of the input. * - * @param input the input word to add. + * @return whether the given input is accepted. */ - void addWord(Word input); + boolean accepts(A hypothesis, Iterable input, int length); /** - * Setup method which is called immediately before {@link #findCounterExample(SimpleDTS, Collection)} is called. - */ - void pre(); - - /** - * Find a counterexample for a given {@code hypothesis}, by trying up to {@link #getMaxWords()} input words. + * Find a counterexample for a given {@code hypothesis}. * - * @param hypothesis the hypothesis to find a counterexample for. - * @param inputs the alphabet. + * @param hypothesis + * the hypothesis to find a counter example to. + * @param inputs + * the alphabet. + * @param maxQueries + * the maximum number of queries. * - * @return the counterexample, or {@code null} if a counterexample does not exist. + * @return the counterexample, or {@code null} if a counter example does not exist. */ @Nullable - default DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + default DefaultQuery findCounterExample(A hypothesis, Collection inputs, int maxQueries) { pre(); - addWords(hypothesis, inputs, Word.epsilon()); - DefaultQuery ce = null; - for (int i = 0; i != getMaxWords() && ce == null; i++) { - - Word input; - do { - input = nextInput(); - addWords(hypothesis, inputs, input); - } while (!isWord(hypothesis, input)); - - final Q query = processInput(hypothesis, input); - if (isCounterExample(hypothesis, query)) { - ce = asDefaultQuery(query); + int queries = 0; + for (Word input = nextInput(); input != null && ce == null && queries != maxQueries; input = nextInput()) { + addWords(hypothesis, inputs, input); + if (accepts(hypothesis, input, input.length())) { + final DefaultQuery query = processInput(hypothesis, input); + if (query != null) { + ce = isCounterExample(hypothesis, input, query.getOutput()) ? query : null; + } + queries++; } } return ce; } - /** - * Generates words for a given DFA. + * Finds a counter example to the given hypothesis. By default the maximum number of queries performed are + * {@code hypothesis.size() * getMultiplier()}. * - * @param the type of DFA. - * @param the type of input. - * @param the type of Query. - */ - interface DFAOracle, I, Q extends Query> extends - AutomatonOracle { - - /** - * Returns whether the given {@code input} is a word in the given {@code hypothesis}. - * - * In a DFA {@code input} is a word in the {@code hypothesis} if it is an access sequence to an accepting state. - * - * @see AutomatonOracle#isWord(SimpleDTS, Word) - */ - @Override - default boolean isWord(A hypothesis, Word input) { - return hypothesis.computeOutput(input); - } - } - - /** - * Generates words for a given Mealy machine. + * @param hypothesis + * the hypothesis automaton. + * @param inputs + * the input alphabet. * - * @param the type of MealyMachine. - * @param the type of input. - * @param the type of output. - * @param the type of Query. + * @return the counter example, or {@code null} if a counter example does not exist */ - interface MealyOracle, I, O, Q extends Query>> extends - AutomatonOracle, Q> { - - /** - * Returns whether the given {@code input} is a word in the given {@code hypothesis}. - * - * In a Mealy machine {@code input} is a word in the {@code hypothesis} if the length of the input word is - * equal to the length of the output word. - * - * @see AutomatonOracle#isWord(SimpleDTS, Word) - */ - @Override - default boolean isWord(A hypothesis, Word input) { - return input.length() == hypothesis.computeOutput(input).length(); - } + @Nullable + default DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + return findCounterExample(hypothesis, inputs, (int) (hypothesis.size() * getMultiplier())); } - /** - * Processes input words by means of {@link DefaultQuery}. - * - * @param the type of automaton. - * @param the type of input. - * @param the typoe of output. - */ - interface DefaultOracle, I, D> - extends AutomatonOracle> { - - /** - * Returns the {@link MembershipOracle}, that answers {@link DefaultQuery}. - * - * @return the {@link MembershipOracle}. - */ - MembershipOracle getMembershipOracle(); + interface DFAOracle extends AutomatonOracle, I, Boolean> { - /** - * Processes the given {@code input}, by returning an answered {@link DefaultQuery}. - * - * @see AutomatonOracle#processInput(SimpleDTS, Word) - */ @Override - default DefaultQuery processInput(A hypothesis, Word input){ - final DefaultQuery query = new DefaultQuery<>(input); - getMembershipOracle().processQuery(query); - return query; - } - - @Override - default DefaultQuery asDefaultQuery(DefaultQuery query) { - return query; + default boolean accepts(DFA hypothesis, Iterable input, int length) { + return hypothesis.accepts(input); } } - interface DFADefaultOracle extends - DFAOracle, I, DefaultQuery>, - DefaultOracle, I, Boolean> {} - - interface MealyDefaultOracle extends - MealyOracle, I, O, DefaultQuery>>, - DefaultOracle, I, Word> {} - - /** - * Processes input words by means of {@link OmegaQuery}. - * - * @param the type of Lasso. - * @param the type of state. - * @param the type of input. - * @param the type of output. - */ - interface LassoOracle, S, I, D> - extends AutomatonOracle> { - - /** - * Returns the {@link OmegaMembershipOracle} that answers {@link OmegaQuery}. - * - * @return the {@link OmegaMembershipOracle}. - */ - OmegaMembershipOracle getOmegaMembershipOracle(); - - /** - * Processes input words by returning answered {@link OmegaQuery}. - * - * @see AutomatonOracle#processInput(SimpleDTS, Word) - */ - @Override - default OmegaQuery processInput(L lasso, Word input) { - final OmegaQuery query = new OmegaQuery<>(input, lasso.getLoopBeginIndices()); - getOmegaMembershipOracle().processQuery(query); - return query; - } + interface MealyOracle extends AutomatonOracle, I, Word> { @Override - default DefaultQuery asDefaultQuery(OmegaQuery query) { - return query; + default boolean accepts(MealyMachine hypothesis, Iterable input, int length) { + return hypothesis.computeOutput(input) != null; } } - - interface DFALassoOracle extends - DFAOracle, I, OmegaQuery>, - LassoOracle, S, I, Boolean> {} - - interface MealyLassoOracle extends - MealyOracle, I, O, OmegaQuery>>, - LassoOracle, S, I, Word> {} - } diff --git a/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java b/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java index e2dfda39df..678fa7dd04 100644 --- a/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java @@ -16,183 +16,36 @@ package de.learnlib.api.oracle; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; -import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; -import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.exception.ModelCheckingException; import net.automatalib.words.Word; /** - * A wrapper around anything that involves black-box checking. - * - * The key component is a set of properties that may be disproved or used to find counterexamples to hypotheses. + * Decides whether some words that do not satisfy properties evaluated by {@link #getPropertyOracles()} on a given + * hypothesis, are included in a language. + * If there is such a word not included, it serves as a counter example for the given hypothesis. * * @author Jeroen Meijer * * @param the automaton type * @param the input type * @param the output type - * @param

the BlackBoxProperty type */ @ParametersAreNonnullByDefault -public interface BlackBoxOracle> { - - /** - * Find a counterexample to the given {@code hypotheses} in a set of properties, and try to disprove all properties - * with the given {@code hypothesis}. - * - * @param hypothesis the hypothesis to find a counterexample to - * @param inputs the alphabet - * - * @return a counterexample, or {@code null} if a counterexample could not be found. - * - * @throws ModelCheckingException when a property can not be checked. - */ - @Nullable - DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException; - - /** - * Retuns the set of {@link BlackBoxProperty}s. - * - * @return the set of {@link BlackBoxProperty}s. - */ - Set

getProperties(); - - /** - * Returns the set of violated {@link BlackBoxProperty}s. - * - * @return the set of violated {@link BlackBoxProperty}s. - */ - default Set

getViolatedProperties() { - final Set

violated = new HashSet<>(); - for (P p : getProperties()) { - if (p.isDisproved()) { - violated.add(p); - } - } - return Collections.unmodifiableSet(violated); - } - - /** - * Returns whether all {@link BlackBoxProperty} are violated. - * - * @return whether all {@link BlackBoxProperty} are violated. - */ - default boolean allPropertiesViolated() { - return getViolatedProperties().size() == getProperties().size(); - } - - interface DFABlackBoxOracle - extends BlackBoxOracle, I, Boolean, DFABlackBoxProperty> {} - - interface MealyBlackBoxOracle - extends BlackBoxOracle, I, Word, MealyBlackBoxProperty> {} - +public interface BlackBoxOracle, I, D> extends InclusionOracle { /** - * A BlackBoxProperty can be disproved or used to find a counterexample to the property. - * - * An implementation should keep track of whether the property is already disproved. - * - * Furthermore, an implementation could implement a cache. A cache could for example cache a call to the model - * checker in between calls to {@link #disprove(Object, Collection)}, or - * {@link #findCounterExample(Object, Collection)}. The cache should be invalidated when - * {@link #disprove(Object, Collection)}, or {@link #findCounterExample(Object, Collection)} is called with a - * different alphabet. A client of this class is responsible for clearing the cache (with {@link #clearCache()}, - * before it calls {@link #disprove(Object, Collection)}, or {@link #findCounterExample(Object, Collection)}, - * with a different hypothesis than the previous call. + * Returns the property oracles that this black-box oracle uses to evaluate properties. * - * @param

the property type - * @param the automaton type - * @param the input type - * @param the output type + * @return the property oracles. */ - @ParametersAreNonnullByDefault - interface BlackBoxProperty { - - /** - * Returns whether this property is disproved. - * - * @return whether this property is disproved. - */ - boolean isDisproved(); - - /** - * Set the property. - * - * @param property the property to set. - */ - void setProperty(P property); - - /** - * Returns the property. - * - * @return the property. - */ - P getProperty(); - - /** - * Returns the counterexample for this property if {@link #isDisproved()}, {@code null} otherwise. - * - * If this method does not return {@code null}, a previous call to {@link #disprove(Object, Collection)} must - * have returned a {@link DefaultQuery}. - * - * @return the counterexample for this property if {@link #isDisproved()}, {@code null} otherwise. - */ - @Nullable - DefaultQuery getCounterExample(); - - /** - * Try to disprove this property with the given {@code hypothesis}. - * - * @param hypothesis the hypothesis. - * @param inputs the alphabet. - * - * @return the {@link DefaultQuery} that is a counterexample this property, or {@code null}, if the property - * could not be disproved. - * - * @throws ModelCheckingException when this property can not be checked. - */ - @Nullable - DefaultQuery disprove(A hypothesis, Collection inputs) throws ModelCheckingException; - - /** - * Try to find a counterexample to the given {@code hypothesis}. - * - * @param hypothesis the hypothesis to find a counterexample to. - * @param inputs the alphabet. - * @return the {@link DefaultQuery} that is a counterexample to the given {@code hypothesis}, or {@code - * null}, a counterexample could not be found. - * - * @throws ModelCheckingException when this property can not be checked. - */ - @Nullable - DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException; - - /** - * Clears a cache. - * - * @see BlackBoxProperty - */ - void clearCache(); - - /** - * Use a cache. - * - * @see BlackBoxProperty - */ - void useCache(); - } + Collection> getPropertyOracles(); - interface DFABlackBoxProperty extends BlackBoxProperty, I, Boolean> {} + interface DFABlackBoxOracle extends BlackBoxOracle, I, Boolean> {} - interface MealyBlackBoxProperty extends BlackBoxProperty, I, Word> {} + interface MealyBlackBoxOracle extends BlackBoxOracle, I, Word> {} } diff --git a/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java index a5dac5ccd5..bb8d92ec08 100644 --- a/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java @@ -15,27 +15,23 @@ */ package de.learnlib.api.oracle; +import java.util.Collection; +import java.util.Objects; + +import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import de.learnlib.api.SUL; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.OmegaQuery; -import de.learnlib.api.query.Query; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.modelchecking.Lasso; -import net.automatalib.modelchecking.Lasso.DFALasso; -import net.automatalib.modelchecking.Lasso.MealyLasso; -import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Word; /** * Decides whether the intersection of the language of a given hypothesis and some other language (e.g. from a {@link - * de.learnlib.api.SUL} is empty. If the intersection is not empty it provides a counterexample, such that is a word in - * the intersection. - *

- * A {@link DFAEmptinessOracle}, and {@link MealyEmptinessOracle} use {@link DefaultQuery}s, while {@link - * DFALassoEmptinessOracle}, and {@link MealyLassoEmptinessOracle} use {@link OmegaQuery}s. + * SUL} is empty. If the intersection is not empty it provides a counterexample, such that it is a word in the + * intersection. More precisely an emptiness oracle decides whether L(H) ∩ L(SUL) = ∅. * * @param * the automaton type @@ -43,39 +39,20 @@ * the input type * @param * the output type - * @param - * the DefaultQuery type * * @author Jeroen Meijer */ @ParametersAreNonnullByDefault -public interface EmptinessOracle & SimpleDTS, I, D, Q extends DefaultQuery> - extends AutomatonOracle { +public interface EmptinessOracle, I, D> { - /** - * Returns whether the given (answered) {@code query} indicates the word is in the language of the given {@code - * hypothesis}. - * - * @see AutomatonOracle#isCounterExample(SimpleDTS, Query) - */ - @Override - default boolean isCounterExample(A hypothesis, Q query) { - return query.getOutput().equals(hypothesis.computeOutput(query.getInput())); + default boolean isCounterExample(A hypothesis, Iterable input, @Nullable D output) { + return Objects.equals(hypothesis.computeOutput(input), output); } - interface DFAEmptinessOracle - extends EmptinessOracle, I, Boolean, DefaultQuery>, DFADefaultOracle {} - - interface MealyEmptinessOracle - extends EmptinessOracle, I, Word, DefaultQuery>>, - MealyDefaultOracle {} - - interface LassoEmptinessOracle, S, I, D> - extends EmptinessOracle>, LassoOracle {} + @Nullable + DefaultQuery findCounterExample(A hypothesis, Collection inputs); - interface DFALassoEmptinessOracle - extends LassoEmptinessOracle, S, I, Boolean>, DFALassoOracle {} + interface DFAEmptinessOracle extends EmptinessOracle, I, Boolean> {} - interface MealyLassoEmptinessOracle - extends LassoEmptinessOracle, S, I, Word>, MealyLassoOracle {} + interface MealyEmptinessOracle extends EmptinessOracle, I, Word> {} } diff --git a/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java b/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java index 16e9027cc4..7b544b2091 100644 --- a/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java @@ -15,46 +15,43 @@ */ package de.learnlib.api.oracle; +import java.util.Objects; + +import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.Query; +import de.learnlib.api.SUL; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Word; /** - * Decides whether the language of a given hypothesis is included in some other language (e.g. from a - * {@link de.learnlib.api.SUL}. If the whole language is not included, it provides a counterexample, such that is - * a word in the given hypothesis, and not in the other language. + * Decides whether the language of a given hypothesis is included in some other language (e.g. from a {@link SUL}. If + * the whole language is not included, it provides a counterexample, such that it is a word in the given hypothesis, and + * not in the other language. * - * @author Jeroen Meijer + * Note that from the perspective of a learner an inclusion oracle is also an equivalence oracle, but a poor one, i.e. + * an inclusion oracle only implements L(H) ⊆ L(SUL), not L(H) ⊇ L(SUL). * - * @param the automaton type - * @param the input type - * @param the output type - * @param the DefaultQuery type + * @param + * the automaton type + * @param + * the input type + * @param + * the output type + * + * @author Jeroen Meijer */ @ParametersAreNonnullByDefault -public interface InclusionOracle & SimpleDTS, I, D, Q extends DefaultQuery> - extends AutomatonOracle { +public interface InclusionOracle, I, D> extends EquivalenceOracle { - /** - * Returns whether the given (answered) {@code query} indicates the word is not in the language of the given {@code - * hypothesis}. - * - * @see AutomatonOracle#isCounterExample(SimpleDTS, Query) - */ - @Override - default boolean isCounterExample(A hypothesis, Q query) { - return !query.getOutput().equals(hypothesis.computeOutput(query.getInput())); + default boolean isCounterExample(A hypothesis, Iterable input, @Nullable D output) { + return !Objects.equals(hypothesis.computeOutput(input), output); } - interface DFAInclusionOracle - extends InclusionOracle, I, Boolean, DefaultQuery>, DFADefaultOracle {} + interface DFAInclusionOracle extends InclusionOracle, I, Boolean>, DFAEquivalenceOracle {} - interface MealyInclusionOracle extends - InclusionOracle, I, Word, DefaultQuery>>, MealyDefaultOracle {} + interface MealyInclusionOracle + extends InclusionOracle, I, Word>, MealyEquivalenceOracle {} } diff --git a/api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java b/api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java new file mode 100644 index 0000000000..dc2d6e265f --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java @@ -0,0 +1,46 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api.oracle; + +import java.util.Objects; + +import javax.annotation.Nullable; + +import net.automatalib.modelchecking.Lasso; +import net.automatalib.words.Word; + +/** + * An emptiness oracle for lassos. + * + * @see EmptinessOracle + * + * @param the lasso type + * @param the input type + * @param the output type + * + * @author Jeroen Meijer + */ +public interface LassoEmptinessOracle, I, D> extends EmptinessOracle { + + @Override + default boolean isCounterExample(L hypothesis, Iterable inputs, @Nullable D output) { + return Objects.equals(hypothesis.getAutomaton().computeOutput(inputs), output); + } + + interface DFALassoEmptinessOracle extends LassoEmptinessOracle, I, Boolean> {} + + interface MealyLassoEmptinessOracle extends LassoEmptinessOracle, I, Word> {} +} diff --git a/api/src/main/java/de/learnlib/api/oracle/LassoOracle.java b/api/src/main/java/de/learnlib/api/oracle/LassoOracle.java new file mode 100644 index 0000000000..7d27fc1021 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/LassoOracle.java @@ -0,0 +1,111 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api.oracle; + +import java.util.Collection; + +import javax.annotation.Nullable; + +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import net.automatalib.automata.DeterministicAutomaton; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.Lasso.DFALasso; +import net.automatalib.modelchecking.Lasso.MealyLasso; +import net.automatalib.words.Word; + +/** + * An automaton oracle for lassos. + * + * @see AutomatonOracle + * + * @param the type of Lasso. + * @param the type of input. + * @param the type of output. + * + * @author Jeroen Meijer + */ +public interface LassoOracle, I, D> extends AutomatonOracle { + + /** + * Processes the given omega query. + * + * @param query the omega query to process. + * + * @return the processed omega query. + */ + OmegaQuery processOmegaQuery(OmegaQuery query); + + /** + * Processes the given input word. The default implementation will check if the processed query actually loops. + * + * @see AutomatonOracle#processInput(DeterministicAutomaton, Word) + * + * @param lassoHypothesis + * the hypothesis lasso. + * @param input + * the input to process. + */ + @Nullable + @Override + default DefaultQuery processInput(L lassoHypothesis, Word input) { + final Word prefix = lassoHypothesis.getPrefix(); + final Word loop = lassoHypothesis.getLoop(); + + assert prefix.isPrefixOf(input); + assert loop.isSuffixOf(input); + + int repeat = (input.length() - prefix.length()) / loop.length(); + + final OmegaQuery omegaQuery = processOmegaQuery(new OmegaQuery<>(prefix, loop, repeat)); + + return omegaQuery.isUltimatelyPeriodic() ? omegaQuery.asDefaultQuery() : null; + } + + /** + * The default implementation accepts an input if it loops at least once and if it makes exactly a loop. + * This behavior is fine for a {@link DFALasso}, because they are assumed to be prefix-closed. + * + * @see AutomatonOracle#accepts(DeterministicAutomaton, Iterable, int) + * + * @param hypothesis + * the hypothesis automaton. + * @param input + * the input. + * @param length + * the length of the input. + * + * @return whether the given lasso accepts the given input. + */ + @Override + default boolean accepts(L hypothesis, Iterable input, int length) { + return length >= hypothesis.getPrefix().length() + hypothesis.getLoop().length() + && (length - hypothesis.getPrefix().length()) % hypothesis.getLoop().length() == 0; + } + + @Nullable + @Override + default DefaultQuery findCounterExample(L hypothesis, Collection inputs) { + final int maxQueries = hypothesis.getUnfolds(); + + return findCounterExample(hypothesis, inputs, maxQueries); + } + + interface DFALassoOracle extends LassoOracle, I, Boolean> {} + + interface MealyLassoOracle extends LassoOracle, I, Word> {} + +} diff --git a/api/src/main/java/de/learnlib/api/oracle/OmegaMembershipOracle.java b/api/src/main/java/de/learnlib/api/oracle/OmegaMembershipOracle.java index f77771e0c5..065bffd229 100644 --- a/api/src/main/java/de/learnlib/api/oracle/OmegaMembershipOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/OmegaMembershipOracle.java @@ -17,8 +17,6 @@ import java.util.Collection; import java.util.Collections; -import java.util.List; -import java.util.Set; import javax.annotation.ParametersAreNonnullByDefault; @@ -43,28 +41,30 @@ public interface OmegaMembershipOracle extends OmegaQueryAnswerer { @Override - default Pair> answerQuery(Word input, Set indices) { - return answerQuery(Word.epsilon(), input, indices); - } - - @Override - default Pair> answerQuery(Word prefix, Word suffix, Set indices) { - final OmegaQuery query = new OmegaQuery<>(prefix, suffix, indices); + default Pair answerQuery(Word prefix, Word loop, int repeat) { + final OmegaQuery query = new OmegaQuery<>(prefix, loop, repeat); processQuery(query); - return query.getOutputStates(); + return Pair.of(query.getOutput(), query.getPeriodicity()); } - default void processQuery(OmegaQuery query) { + default void processQuery(OmegaQuery query) { processQueries(Collections.singleton(query)); } - void processQueries(Collection> queries); + void processQueries(Collection> queries); @Override default OmegaMembershipOracle asOracle() { return this; } + /** + * Returns a regular membership oracle. + * + * @return a regular membership oracle. + */ + MembershipOracle getMembershipOracle(); + /** * Returns whether two states are equal, or if both access sequences {@code w1}, and {@code w2} end up in the * same state. If both access sequences end up in the same state then {@code s1.equals(s2)} must hold. @@ -82,11 +82,13 @@ default OmegaMembershipOracle asOracle() { interface DFAOmegaMembershipOracle extends OmegaMembershipOracle { - DFAMembershipOracle getDFAMembershipOracle(); + @Override + DFAMembershipOracle getMembershipOracle(); } interface MealyOmegaMembershipOracle extends OmegaMembershipOracle> { - MealyMembershipOracle getMealyMembershipOracle(); + @Override + MealyMembershipOracle getMembershipOracle(); } } diff --git a/api/src/main/java/de/learnlib/api/oracle/OmegaQueryAnswerer.java b/api/src/main/java/de/learnlib/api/oracle/OmegaQueryAnswerer.java index 015f07229e..86e500767f 100644 --- a/api/src/main/java/de/learnlib/api/oracle/OmegaQueryAnswerer.java +++ b/api/src/main/java/de/learnlib/api/oracle/OmegaQueryAnswerer.java @@ -15,9 +15,6 @@ */ package de.learnlib.api.oracle; -import java.util.List; -import java.util.Set; - import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -28,19 +25,13 @@ * Answers {@link de.learnlib.api.query.OmegaQuery}s. * * @author Jeroen Meijer - * * @see OmegaMembershipOracle * @see QueryAnswerer */ public interface OmegaQueryAnswerer { @Nullable - default Pair> answerQuery(Word input, Set indices) { - return answerQuery(Word.epsilon(), input, indices); - } - - @Nullable - Pair> answerQuery(Word prefix, Word suffix, Set indices); + Pair answerQuery(Word prefix, Word loop, int repeat); @Nonnull OmegaMembershipOracle asOracle(); diff --git a/api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java b/api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java new file mode 100644 index 0000000000..1af9ef5277 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java @@ -0,0 +1,105 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api.oracle; + +import java.util.Collection; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +/** + * A {@link PropertyOracle} can disprove a property, and used to find a counter example to an hypothesis. + * + * An implementation should keep track of whether the property is already disproved. + * + * @param the input type + * @param the automaton type + * @param

the property type + * @param the output type + * + * @author Jeroen Meijer + */ +@ParametersAreNonnullByDefault +public interface PropertyOracle { + + /** + * Returns whether the property is disproved. + * + * @return whether the property is disproved. + */ + default boolean isDisproved() { + return getCounterExample() != null; + } + + /** + * Set the property. + * + * @param property the property to set. + */ + void setProperty(P property); + + /** + * Returns the property. + * + * @return the property. + */ + P getProperty(); + + /** + * Returns the counterexample for the property if {@link #isDisproved()}, {@code null} otherwise. + * + * If this method does not return {@code null}, a previous call to {@link #disprove(Object, Collection)} must + * have returned a {@link DefaultQuery}. + * + * @return the counterexample for the property if {@link #isDisproved()}, {@code null} otherwise. + */ + @Nullable + DefaultQuery getCounterExample(); + + /** + * Try to disprove the property with the given {@code hypothesis}. + * + * @param hypothesis the hypothesis. + * @param inputs the inputs + * + * @return the {@link DefaultQuery} that is a counterexample the property, or {@code null}, if the property + * could not be disproved. + */ + @Nullable + DefaultQuery disprove(A hypothesis, Collection inputs); + + /** + * Try to find a counterexample to the given {@code hypothesis}. + * + * @param hypothesis the hypothesis to find a counterexample to. + * @param inputs the input alphabet. + * + * @return the {@link DefaultQuery} that is a counterexample to the given {@code hypothesis}, or {@code + * null}, a counterexample could not be found. + */ + @Nullable + DefaultQuery findCounterExample(A hypothesis, Collection inputs); + + interface DFAPropertyOracle extends PropertyOracle, P, Boolean> {} + + interface MealyPropertyOracle extends PropertyOracle, P, Word> {} +} + diff --git a/api/src/main/java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java b/api/src/main/java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java index a337db433a..c81a1dba31 100644 --- a/api/src/main/java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java @@ -16,8 +16,6 @@ package de.learnlib.api.oracle; import java.util.Collection; -import java.util.List; -import java.util.Set; import de.learnlib.api.query.OmegaQuery; import net.automatalib.commons.util.Pair; @@ -34,20 +32,16 @@ public interface SingleQueryOmegaOracle extends OmegaMembershipOracle { @Override - default void processQuery(OmegaQuery query) { - Pair> output = answerQuery(query.getPrefix(), query.getSuffix(), query.getIndices()); - query.answer(output.getFirst()); - query.setStates(output.getSecond()); + default void processQuery(OmegaQuery query) { + Pair output = answerQuery(query.getPrefix(), query.getLoop(), query.getRepeat()); + query.answer(output.getFirst(), output.getSecond()); } @Override - default void processQueries(Collection> queries) { + default void processQueries(Collection> queries) { queries.forEach(this::processQuery); } - @Override - Pair> answerQuery(Word prefix, Word suffix, Set indices); - interface SingleQueryOmegaOracleDFA extends SingleQueryOmegaOracle, DFAOmegaMembershipOracle {} interface SingleQueryOmegaOracleMealy extends SingleQueryOmegaOracle>, MealyOmegaMembershipOracle {} diff --git a/api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java b/api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java index c8314fd78b..b79fa442c8 100644 --- a/api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java @@ -35,7 +35,7 @@ * @author frohme */ @ParametersAreNonnullByDefault -public interface SymbolQueryOracle extends MembershipOracle> { +public interface SymbolQueryOracle extends MembershipOracle.MealyMembershipOracle { /** * Query the system under learning for a new symbol. This is a stateful operation. diff --git a/api/src/main/java/de/learnlib/api/query/OmegaQuery.java b/api/src/main/java/de/learnlib/api/query/OmegaQuery.java index e169abfa82..0d5cc55240 100644 --- a/api/src/main/java/de/learnlib/api/query/OmegaQuery.java +++ b/api/src/main/java/de/learnlib/api/query/OmegaQuery.java @@ -15,87 +15,111 @@ */ package de.learnlib.api.query; -import java.util.List; -import java.util.Set; +import java.util.Objects; import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; import de.learnlib.api.ObservableSUL; -import net.automatalib.commons.util.Pair; import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; /** - * A query that contains information about infinite words. + * A query that represents information about infinite words in an ultimately periodic pattern. That is, for two finite + * strings u, v, this class represents the query of the infinite word uvω. + *

+ * When answering OmegaQueries, one needs to specify the periodicity p of the looping suffix v, i.e. for + * what p the answer contains information about the response to the query uvp (which can then + * be generalized to the infinite case since u(vp)ω = uvω. + *

+ * If one cannot determine this value (e.g. because the response exhibits a non periodic pattern), one may specify a + * negative value for p. {@link #isUltimatelyPeriodic()} then consequently returns {@code false}. In this case + * the output of the query ({@link #getOutput()}) may be undefined. * - * In addition to the behavior of {@link DefaultQuery}, an {@link OmegaQuery} contains information about which states - * have been visited. So that an oracle can decide whether an infinite word is in a language or not. - * - * States that need to be recorded are given in {@link #getIndices()}. Every index therein is the ith state - * obtained after the ith symbol. Actual states in {@link #getStates()} correspond to those indices in - * {@link #getIndices()}. - * - * Invariant: {@code ({@link #getStates()} == null) == ({@link #getOutput()} == null)}. - * - * Every constructor in this class accepts a set of integers, that can later be retrieved with {@code - * {@link #getIndices()}}. - * - * Answering this query with output is done obviously via {@link DefaultQuery#answer(Object)}, but additionally one - * has to call {@link #setStates(List)} to satisfy the invariant. + * @param + * the input type + * @param + * the output type * * @see DefaultQuery * @see Query * @see ObservableSUL#getState() - * - * @param the state type - * @param the input type - * @param the output type */ -public class OmegaQuery extends DefaultQuery { +@ParametersAreNonnullByDefault +public final class OmegaQuery { - private Set indices; + private final Word prefix; + private final Word loop; + private final int repeat; - private List states; + private D output; + private int periodicity; - public OmegaQuery(Word prefix, Word suffix, @Nullable D output, Set indices) { - super(prefix, suffix, output); - this.indices = indices; + public OmegaQuery(Word prefix, Word loop, int repeat) { + this.prefix = prefix; + this.loop = loop; + this.repeat = repeat; } - public OmegaQuery(Word prefix, Word suffix, Set indices) { - this(prefix, suffix, null, indices); + public void answer(D output, int periodicity) { + this.output = output; + this.periodicity = periodicity; } - public OmegaQuery(Word input, Set indices) { - this(Word.epsilon(), input, null, indices); + public Word getPrefix() { + return prefix; } - public OmegaQuery(Word input, @Nullable D output, Set indices) { - this(Word.epsilon(), input, output, indices); + public Word getLoop() { + return loop; } - public OmegaQuery(Query query, Set indices) { - this(query.getPrefix(), query.getSuffix(), null, indices); + public int getRepeat() { + return repeat; } - public Pair> getOutputStates() { - return Pair.of(getOutput(), states); + @Nullable + public D getOutput() { + return output; } - @Override - public String toString() { - return "OmegaQuery[" + prefix + '|' + suffix + " / " + getOutput() + ", " + indices + " - " + states + ']'; + public int getPeriodicity() { + return periodicity; } - public Set getIndices() { - return indices; + public boolean isUltimatelyPeriodic() { + return periodicity > 0; } - public List getStates() { - return states; + public DefaultQuery asDefaultQuery() { + final WordBuilder wb = new WordBuilder<>(prefix.length() + loop.length() * periodicity); + wb.append(prefix); + wb.repeatAppend(periodicity, loop); + return new DefaultQuery<>(wb.toWord(), output); } - public void setStates(List states) { - this.states = states; + @Override + public String toString() { + return "OmegaQuery{" + "prefix=" + prefix + ", loop=" + loop + ", repeat=" + repeat + ", output=" + output + + ", periodicity=" + periodicity + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof OmegaQuery)) { + return false; + } + OmegaQuery that = (OmegaQuery) o; + return periodicity == that.periodicity && Objects.equals(prefix, that.prefix) && + Objects.equals(loop, that.loop) && Objects.equals(output, that.output); + } + + @Override + public int hashCode() { + return Objects.hash(prefix, loop, output, periodicity); } } diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java deleted file mode 100644 index 84d52d3094..0000000000 --- a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/AbstractLassoTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.api.modelchecking.counterexample; - -import java.util.SortedSet; -import java.util.TreeSet; - -import net.automatalib.modelchecking.AbstractLasso; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import net.automatalib.words.impl.Alphabets; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -/** - * Tests whether lassos are constructed correctly for any automaton. - * - * @param the {@link AbstractLasso} type to test. - * - * @author Jeroen Meijer - */ -public abstract class AbstractLassoTest> { - - private Alphabet alphabet = Alphabets.fromArray("a"); - - private L lasso1; - private L lasso2; - private L lasso3; - - protected abstract L getLasso(Word prefix, Word loop, int unfoldTimes); - - public Alphabet getAlphabet() { - return alphabet; - } - - @BeforeClass - public void setUp() { - lasso1 = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); - lasso2 = getLasso(Word.fromSymbols("a"), Word.fromSymbols("a"), 1); - lasso3 = getLasso(Word.fromSymbols("a"), Word.fromSymbols("a", "a"), 1); - } - - @Test - public void testGetWord() { - Assert.assertEquals(lasso1.getWord(), Word.fromSymbols("a")); - Assert.assertEquals(lasso2.getWord(), Word.fromSymbols("a", "a")); - Assert.assertEquals(lasso3.getWord(), Word.fromSymbols("a", "a", "a")); - } - - @Test - public void testGetLoop() { - Assert.assertEquals(lasso1.getLoop(), Word.fromSymbols("a")); - Assert.assertEquals(lasso2.getLoop(), Word.fromSymbols("a")); - Assert.assertEquals(lasso3.getLoop(), Word.fromSymbols("a", "a")); - } - - @Test - public void testGetPrefix() { - Assert.assertEquals(lasso1.getPrefix(), Word.epsilon()); - Assert.assertEquals(lasso2.getPrefix(), Word.fromSymbols("a")); - Assert.assertEquals(lasso3.getPrefix(), Word.fromSymbols("a")); - } - - @Test - public void testGetLoopBeginIndices() { - final SortedSet indices = new TreeSet<>(); - indices.add(0); - indices.add(1); - Assert.assertEquals(lasso1.getLoopBeginIndices(), indices); - - indices.clear(); - indices.add(1); - indices.add(2); - Assert.assertEquals(lasso2.getLoopBeginIndices(), indices); - - indices.clear(); - indices.add(1); - indices.add(3); - Assert.assertEquals(lasso3.getLoopBeginIndices(), indices); - } - -} diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java deleted file mode 100644 index baadd012d1..0000000000 --- a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/DFALassoTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.api.modelchecking.counterexample; - -import java.util.Collection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import net.automatalib.automata.fsa.DFA; -import net.automatalib.commons.util.collections.CollectionsUtil; -import net.automatalib.modelchecking.DFALassoImpl; -import net.automatalib.words.Word; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public class DFALassoTest extends AbstractLassoTest> { - - @Override - protected DFALassoImpl getLasso(Word prefix, Word loop, int unfoldTimes) { - return new DFALassoImpl<>(new DFAMock(prefix, loop), getAlphabet(), unfoldTimes); - } - - @Test - public void testGetOutput() { - final DFALassoImpl lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); - Assert.assertTrue(lasso.getOutput()); - } - - private class DFAMock implements DFA { - - private Word prefix; - private Word word; - - DFAMock(Word prefix, Word loop) { - this.prefix = prefix; - word = prefix.concat(loop); - } - - @Nonnull - @Override - public Collection getStates() { - return CollectionsUtil.intRange(0, word.length()); - } - - @Nullable - @Override - public Integer getTransition(Integer state, @Nullable String input) { - final Integer result; - - if (word.getSymbol(state).equals(input)) { - if (state < word.length() - 1) { - result = state + 1; - } else { - result = prefix.length(); - } - } else { - result = null; - } - - return result; - } - - @Override - public boolean isAccepting(Integer state) { - // dfa is prefix-closed; always return true - return true; - } - - @Nullable - @Override - public Integer getInitialState() { - return 0; - } - } -} diff --git a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java b/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java deleted file mode 100644 index 7cc6d426c2..0000000000 --- a/api/src/test/java/de/learnlib/api/modelchecking/counterexample/MealyLassoTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.api.modelchecking.counterexample; - -import java.util.Collection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealyTransition; -import net.automatalib.commons.util.collections.CollectionsUtil; -import net.automatalib.modelchecking.MealyLassoImpl; -import net.automatalib.words.Word; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public class MealyLassoTest extends AbstractLassoTest> { - - @Override - protected MealyLassoImpl getLasso(Word prefix, Word loop, int unfoldTimes) { - return new MealyLassoImpl<>(new MealyMachineMock(prefix, loop), getAlphabet(), 1); - } - - @Test - public void testGetOutput() { - final MealyLassoImpl lasso = getLasso(Word.epsilon(), Word.fromSymbols("a"), 1); - Assert.assertEquals(lasso.getOutput(), Word.fromSymbols(MealyMachineMock.OUTPUT)); - } - - private class MealyMachineMock implements MealyMachine, String> { - - public static final String OUTPUT = "test"; - - private final Word prefix; - private final Word word; - - MealyMachineMock(Word prefix, Word loop) { - this.prefix = prefix; - word = prefix.concat(loop); - } - - @Nullable - @Override - public String getTransitionOutput(CompactMealyTransition transition) { - return OUTPUT; - } - - @Nonnull - @Override - public Collection getStates() { - return CollectionsUtil.intRange(0, word.length()); - } - - @Nullable - @Override - public CompactMealyTransition getTransition(Integer state, @Nullable String input) { - final CompactMealyTransition result; - if (word.getSymbol(state).equals(input)) { - if (state < word.length() - 1) { - result = new CompactMealyTransition<>(state + 1, OUTPUT); - } else { - result = new CompactMealyTransition<>(prefix.length(), OUTPUT); - } - } else { - result = null; - } - - return result; - } - - @Nonnull - @Override - public Integer getSuccessor(CompactMealyTransition transition) { - return transition.getSuccId(); - } - - @Nullable - @Override - public Integer getInitialState() { - return 0; - } - } -} diff --git a/build-tools/install-ltsmin.sh b/build-tools/install-ltsmin.sh index 06c0e2c506..3b2112b618 100755 --- a/build-tools/install-ltsmin.sh +++ b/build-tools/install-ltsmin.sh @@ -1,8 +1,7 @@ #!/bin/bash -LTSMIN_VERSION=v3.0.0 LTSMIN_NAME="ltsmin-${LTSMIN_VERSION}-$TRAVIS_OS_NAME.tgz" -LTSMIN_URL="https://github.com/Meijuh/ltsmin/releases/download/v3.0.0/$LTSMIN_NAME" +LTSMIN_URL="https://github.com/utwente-fmt/ltsmin/releases/download/$LTSMIN_VERSION/$LTSMIN_NAME" # test if we have a cached version test -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/ltsmin-convert" -a -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/etf2lts-mc" && exit 0 diff --git a/commons/util/src/main/java/de/learnlib/util/AbstractBFOracle.java b/commons/util/src/main/java/de/learnlib/util/AbstractBFOracle.java new file mode 100644 index 0000000000..5a14027e2b --- /dev/null +++ b/commons/util/src/main/java/de/learnlib/util/AbstractBFOracle.java @@ -0,0 +1,111 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.util; + +import java.util.LinkedList; +import java.util.Queue; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.oracle.AutomatonOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.DeterministicAutomaton; +import net.automatalib.words.Word; + +/** + * An {@link AutomatonOracle} that processes words in a breadth-first manner. + * + * @param the automaton type + * @param the input type + * @param the output type + * + * @author Jeroen Meijer + */ +@ParametersAreNonnullByDefault +public abstract class AbstractBFOracle, I, D> + implements AutomatonOracle { + + /** + * The queue containing the words to find a counterexample with. + */ + private final Queue> queue = new LinkedList<>(); + + /** + * The {@link MembershipOracle} used to answer {@link DefaultQuery}s. + */ + private final MembershipOracle membershipOracle; + + private double multiplier; + + protected AbstractBFOracle(MembershipOracle membershipOracle, double multiplier) { + this.membershipOracle = membershipOracle; + this.multiplier = multiplier; + } + + @Override + public DefaultQuery processInput(A hypothesis, Word input) { + final DefaultQuery query = new DefaultQuery<>(input); + membershipOracle.processQuery(query); + + return query; + } + + @Override + public double getMultiplier() { + return multiplier; + } + + @Override + public void setMultiplier(double multiplier) { + this.multiplier = multiplier; + } + + public MembershipOracle getMembershipOracle() { + return membershipOracle; + } + + /** + * Returns the next input word, by popping from a queue. + * + * @see AutomatonOracle#nextInput() + */ + @Nullable + @Override + public Word nextInput() { + return queue.poll(); + } + + /** + * Adds a new input word to the queue. + * + * @see AutomatonOracle#addWord(Word) + */ + @Override + public void addWord(Word input) { + queue.add(input); + } + + /** + * Clears the queue. + */ + @Override + public void pre() { + queue.clear(); + addWord(Word.epsilon()); + } +} diff --git a/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java b/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java deleted file mode 100644 index d776903899..0000000000 --- a/commons/util/src/main/java/de/learnlib/util/BBCExperiment.java +++ /dev/null @@ -1,183 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.util; - -import javax.annotation.Nonnull; - -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.logging.LearnLogger; -import de.learnlib.api.oracle.BlackBoxOracle; -import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.filter.statistic.Counter; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * A black-box checking experiment. The experiment can be started with {@link #run()}. - * - * @author Jeroen Meijer - * - * @param the automaton type - * @param the input type - * @param the output type - */ -public class BBCExperiment extends Experiment { - - public static final String PROPERTY_VIOLATION_PROFILE_KEY = "Searching for property violation"; - - private static final LearnLogger LOGGER = LearnLogger.getLogger(BBCExperiment.class); - - /** - * @see #getRoundsBBC() - */ - private final Counter roundsBBC = new Counter("BBC rounds", "#"); - - /** - * @see #getRoundsPropertyViolation() - */ - private final Counter roundsPropertyViolation = new Counter("property violation detection rounds", "#"); - - /** - * @see #getBlackBoxOracle() - */ - private final BlackBoxOracle> blackBoxOracle; - - /** - * Indicates whether the {@link BlackBoxOracle} should continue learning when all properties have been violated. - */ - private final boolean keepLearning; - - /** - * Constructs a new BBCExperiment. - * - * @param learningAlgorithm the learner. - * @param equivalenceAlgorithm the equivalence oracle. - * @param inputs the alphabet. - * @param blackBoxOracle the black-box oracle. - * @param keepLearning whether to keep learning the hypothesis when all properties have been violated. - */ - protected BBCExperiment( - LearningAlgorithm learningAlgorithm, - EquivalenceOracle equivalenceAlgorithm, - Alphabet inputs, - BlackBoxOracle> blackBoxOracle, - boolean keepLearning) { - super(learningAlgorithm, equivalenceAlgorithm, inputs); - this.blackBoxOracle = blackBoxOracle; - this.keepLearning = keepLearning; - } - - /** - * Returns a {@link Counter} that indicates how many main iterations where done. - * - * @return the Counter. - */ - public Counter getRoundsBBC() { - return roundsBBC; - } - - /** - * Returns a {@link Counter} that indicates how many nested iterations where done. - * - * @return the Counter. - */ - public Counter getRoundsPropertyViolation() { - return roundsPropertyViolation; - } - - /** - * Gets the {@link BlackBoxOracle} for this experiment. - * - * @return the {@link BlackBoxOracle} - */ - public BlackBoxOracle> getBlackBoxOracle() { - return blackBoxOracle; - } - - /** - * Runs a black-box checking experiment. - * - * @return the final hypothesis. - */ - @Nonnull - @Override - public A run() { - if (isRun()) { - throw new IllegalStateException("Experiment has already been run"); - } - - init(); - - do { - roundsBBC.increment(); - DefaultQuery ce; - do { - roundsPropertyViolation.increment(); - LOGGER.logPhase("Searching for property violation"); - - profileStart(PROPERTY_VIOLATION_PROFILE_KEY); - ce = blackBoxOracle.findCounterExample(getLearningAlgorithm().getHypothesisModel(), getInputs()); - profileStop(PROPERTY_VIOLATION_PROFILE_KEY); - assert blackBoxOracle.allPropertiesViolated() == (ce == null); - } while (!blackBoxOracle.allPropertiesViolated() && ce != null && getLearningAlgorithm().refineHypothesis(ce)); - } while ((keepLearning || !blackBoxOracle.allPropertiesViolated()) && refineHypothesis()); - - final A finalHyp = getLearningAlgorithm().getHypothesisModel(); - setFinalHypothesis(finalHyp); - - return finalHyp; - } - - public static class DFABBCExperiment extends BBCExperiment, I, Boolean> { - - public DFABBCExperiment(LearningAlgorithm, I, Boolean> learningAlgorithm, - EquivalenceOracle, I, Boolean> equivalenceAlgorithm, - Alphabet inputs, - BlackBoxOracle.DFABlackBoxOracle blackBoxOracle, - boolean keepLearning) { - super(learningAlgorithm, equivalenceAlgorithm, inputs, blackBoxOracle, keepLearning); - } - - public DFABBCExperiment(LearningAlgorithm, I, Boolean> learningAlgorithm, - EquivalenceOracle, I, Boolean> equivalenceAlgorithm, - Alphabet inputs, - BlackBoxOracle.DFABlackBoxOracle blackBoxOracle) { - this(learningAlgorithm, equivalenceAlgorithm, inputs, blackBoxOracle, false); - } - } - - public static class MealyBBCExperiment extends BBCExperiment, I, Word> { - - public MealyBBCExperiment(LearningAlgorithm, I, Word> learningAlgorithm, - EquivalenceOracle, I, Word> equivalenceAlgorithm, - Alphabet inputs, - BlackBoxOracle.MealyBlackBoxOracle blackBoxOracle, - boolean keepLearning) { - super(learningAlgorithm, equivalenceAlgorithm, inputs, blackBoxOracle, keepLearning); - } - - public MealyBBCExperiment(LearningAlgorithm, I, Word> learningAlgorithm, - EquivalenceOracle, I, Word> equivalenceAlgorithm, - Alphabet inputs, - BlackBoxOracle.MealyBlackBoxOracle blackBoxOracle) { - this(learningAlgorithm, equivalenceAlgorithm, inputs, blackBoxOracle, false); - } - } -} diff --git a/commons/util/src/main/java/de/learnlib/util/MQUtil.java b/commons/util/src/main/java/de/learnlib/util/MQUtil.java index a36514089b..61e3dbf06e 100644 --- a/commons/util/src/main/java/de/learnlib/util/MQUtil.java +++ b/commons/util/src/main/java/de/learnlib/util/MQUtil.java @@ -16,9 +16,7 @@ package de.learnlib.util; import java.util.Collection; -import java.util.List; import java.util.Objects; -import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -91,7 +89,7 @@ public static void answerQueriesAuto(QueryAnswerer answerer, } public static void answerOmegaQueriesAuto(OmegaQueryAnswerer answerer, - Collection> queries) { + Collection> queries) { if (PARALLEL_THRESHOLD < 0 || queries.size() < PARALLEL_THRESHOLD) { answerOmegaQueries(answerer, queries); } else { @@ -109,14 +107,13 @@ public static void answerQueries(QueryAnswerer answerer, Collection } public static void answerOmegaQueries(OmegaQueryAnswerer answerer, - Collection> queries) { - for (OmegaQuery query : queries) { - Word prefix = query.getPrefix(); - Word suffix = query.getSuffix(); - Set indices = query.getIndices(); - Pair> answer = answerer.answerQuery(prefix, suffix, indices); - query.answer(answer.getFirst()); - query.setStates(answer.getSecond()); + Collection> queries) { + for (OmegaQuery query : queries) { + final Word prefix = query.getPrefix(); + final Word loop = query.getLoop(); + final int repeat = query.getRepeat(); + Pair answer = answerer.answerQuery(prefix, loop, repeat); + query.answer(answer.getFirst(), answer.getSecond()); } } @@ -131,14 +128,13 @@ public static void answerQueriesParallel(QueryAnswerer answerer, } public static void answerOmegaQueriesParallel(OmegaQueryAnswerer answerer, - Collection> queries) { + Collection> queries) { queries.parallelStream().forEach(q -> { - Word prefix = q.getPrefix(); - Word suffix = q.getSuffix(); - Set indices = q.getIndices(); - Pair> answer = answerer.answerQuery(prefix, suffix, indices); - q.answer(answer.getFirst()); - q.setStates(answer.getSecond()); + final Word prefix = q.getPrefix(); + final Word loop = q.getLoop(); + final int repeat = q.getRepeat(); + Pair answer = answerer.answerQuery(prefix, loop, repeat); + q.answer(answer.getFirst(), answer.getSecond()); }); } diff --git a/distribution/pom.xml b/distribution/pom.xml index 70450c5879..d2691c0b92 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -174,7 +174,7 @@ limitations under the License. de.learnlib - learnlib-bbc-oracles + learnlib-emptiness-oracles @@ -207,6 +207,11 @@ limitations under the License. learnlib-parallelism + + de.learnlib + learnlib-property-oracles + + net.automatalib.distribution @@ -426,7 +431,7 @@ limitations under the License. de.learnlib - learnlib-bbc-oracles + learnlib-emptiness-oracles ${project.version} sources @@ -472,6 +477,13 @@ limitations under the License. ${project.version} sources + + + de.learnlib + learnlib-property-oracles + ${project.version} + sources + diff --git a/examples/pom.xml b/examples/pom.xml index 052006b581..cc1448be60 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -64,10 +64,6 @@ limitations under the License. de.learnlib learnlib-ttt - - de.learnlib - learnlib-bbc-oracles - de.learnlib learnlib-equivalence-oracles @@ -131,6 +127,14 @@ limitations under the License. logback-classic runtime + + de.learnlib + learnlib-emptiness-oracles + + + de.learnlib + learnlib-property-oracles + diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java index 3239081bbe..1a6b5a8fdd 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java @@ -20,23 +20,23 @@ import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.ttt.dfa.TTTLearnerDFA; import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; -import de.learnlib.api.logging.LoggingBlackBoxProperty.DFALoggingBlackBoxProperty; -import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxOracle; -import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxProperty; -import de.learnlib.api.oracle.EmptinessOracle.DFALassoEmptinessOracle; +import de.learnlib.api.logging.LoggingPropertyOracle; import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.InclusionOracle.DFAInclusionOracle; +import de.learnlib.api.oracle.LassoEmptinessOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; +import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.examples.LearningExample.DFALearningExample; import de.learnlib.examples.dfa.ExampleTinyDFA; -import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstDFABBOracle; -import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.DFABBPropertyDFALasso; -import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.DFALassoDFAEmptinessOracle; +import de.learnlib.oracle.emptiness.DFALassoEmptinessOracleImpl; +import de.learnlib.oracle.equivalence.CExFirstOracle; +import de.learnlib.oracle.equivalence.DFABFInclusionOracle; +import de.learnlib.oracle.equivalence.EQOracleChain; import de.learnlib.oracle.equivalence.WpMethodEQOracle.DFAWpMethodEQOracle; -import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.DFABreadthFirstInclusionOracle; import de.learnlib.oracle.membership.SimulatorOmegaOracle.DFASimulatorOmegaOracle; -import de.learnlib.util.BBCExperiment.DFABBCExperiment; +import de.learnlib.oracle.property.DFALassoPropertyOracle; +import de.learnlib.util.Experiment; import net.automatalib.automata.fsa.DFA; import net.automatalib.modelcheckers.ltsmin.LTSminLTLDFABuilder; import net.automatalib.modelchecking.ModelCheckerLasso.DFAModelCheckerLasso; @@ -71,10 +71,7 @@ public static void main(String[] args) { DFAOmegaMembershipOracle omqOracle = new DFASimulatorOmegaOracle<>(dfa); // create a regular membership oracle - DFAMembershipOracle mqOracle = omqOracle.getDFAMembershipOracle(); - - // create an equivalence oracle - DFAEquivalenceOracle eqOracle = new DFAWpMethodEQOracle<>(mqOracle, 3); + DFAMembershipOracle mqOracle = omqOracle.getMembershipOracle(); // create a learner DFALearner learner = new TTTLearnerDFA<>(sigma, mqOracle, AcexAnalyzers.LINEAR_FWD); @@ -84,23 +81,24 @@ public static void main(String[] args) { new LTSminLTLDFABuilder().withString2Input(EDGE_PARSER).create(); // create an emptiness oracle, that is used to disprove properties - DFALassoEmptinessOracle emptinessOracle = new DFALassoDFAEmptinessOracle<>(omqOracle); + LassoEmptinessOracle.DFALassoEmptinessOracle + emptinessOracle = new DFALassoEmptinessOracleImpl<>(omqOracle); // create an inclusion oracle, that is used to find counterexamples to hypotheses - DFAInclusionOracle inclusionOracle = new DFABreadthFirstInclusionOracle<>(1, mqOracle); + DFAInclusionOracle inclusionOracle = new DFABFInclusionOracle<>(mqOracle, 1.0); - // create an LTL formula - DFABlackBoxProperty ltl = new DFALoggingBlackBoxProperty<>( - new DFABBPropertyDFALasso<>(modelChecker, - emptinessOracle, - inclusionOracle, - "letter==\"b\"")); + // create an LTL property oracle, that also logs stuff + PropertyOracle.DFAPropertyOracle ltl = new LoggingPropertyOracle.DFALoggingPropertyOracle<>( + new DFALassoPropertyOracle<>("letter==\"b\"", inclusionOracle, emptinessOracle, modelChecker)); - // create a black-box oracle - DFABlackBoxOracle blackBoxOracle = new CExFirstDFABBOracle<>(ltl); + // create an equivalence oracle, that first searches for a counter example using the ltl properties, and next + // with the W-method. + DFAEquivalenceOracle eqOracle = new EQOracleChain.DFAEQOracleChain<>( + new CExFirstOracle.DFACExFirstOracle<>(ltl), + new DFAWpMethodEQOracle<>(mqOracle, 3)); - // create a black-box checking experiment - DFABBCExperiment experiment = new DFABBCExperiment<>(learner, eqOracle, sigma, blackBoxOracle); + // create an experiment + Experiment.DFAExperiment experiment = new Experiment.DFAExperiment<>(learner, eqOracle, sigma); // run the experiment experiment.run(); diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java index 8f14b0ccf9..29d96c8d86 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java @@ -20,22 +20,23 @@ import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; -import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxOracle; -import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; -import de.learnlib.api.oracle.EmptinessOracle.MealyLassoEmptinessOracle; +import de.learnlib.api.logging.LoggingPropertyOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; import de.learnlib.api.oracle.InclusionOracle.MealyInclusionOracle; +import de.learnlib.api.oracle.LassoEmptinessOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; +import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.examples.LearningExample.MealyLearningExample; import de.learnlib.examples.mealy.ExampleTinyMealy; -import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstMealyBBOracle; -import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.MealyBBPropertyMealyLasso; -import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; +import de.learnlib.oracle.emptiness.MealyLassoEmptinessOracleImpl; +import de.learnlib.oracle.equivalence.CExFirstOracle; +import de.learnlib.oracle.equivalence.EQOracleChain; +import de.learnlib.oracle.equivalence.MealyBFInclusionOracle; import de.learnlib.oracle.equivalence.WpMethodEQOracle.MealyWpMethodEQOracle; -import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; import de.learnlib.oracle.membership.SimulatorOmegaOracle.MealySimulatorOmegaOracle; -import de.learnlib.util.BBCExperiment.MealyBBCExperiment; +import de.learnlib.oracle.property.MealyLassoPropertyOracle; +import de.learnlib.util.Experiment; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.modelcheckers.ltsmin.LTSminLTLIOBuilder; import net.automatalib.modelchecking.ModelCheckerLasso.MealyModelCheckerLasso; @@ -74,10 +75,7 @@ public static void main(String[] args) { MealyOmegaMembershipOracle omqOracle = new MealySimulatorOmegaOracle<>(mealy); // create a regular membership oracle - MealyMembershipOracle mqOracle = omqOracle.getMealyMembershipOracle(); - - // create an equivalence oracle - MealyEquivalenceOracle eqOracle = new MealyWpMethodEQOracle<>(mqOracle, 3); + MealyMembershipOracle mqOracle = omqOracle.getMembershipOracle(); // create a learner MealyLearner learner = new TTTLearnerMealy<>(sigma, mqOracle, AcexAnalyzers.LINEAR_FWD); @@ -88,23 +86,24 @@ public static void main(String[] args) { withString2Output(EDGE_PARSER).create(); // create an emptiness oracle, that is used to disprove properties - MealyLassoEmptinessOracle emptinessOracle = new MealyLassoMealyEmptinessOracle<>(omqOracle); + LassoEmptinessOracle.MealyLassoEmptinessOracle + emptinessOracle = new MealyLassoEmptinessOracleImpl<>(omqOracle); // create an inclusion oracle, that is used to find counterexamples to hypotheses - MealyInclusionOracle inclusionOracle = new MealyBreadthFirstInclusionOracle<>(1, mqOracle); + MealyInclusionOracle inclusionOracle = new MealyBFInclusionOracle<>(mqOracle, 1.0); - // create an ltl formula - MealyBlackBoxProperty ltl = new MealyBBPropertyMealyLasso<>(modelChecker, - emptinessOracle, - inclusionOracle, - "X output==\"2\""); + // create an LTL property oracle, that also logs stuff + PropertyOracle.MealyPropertyOracle ltl = new LoggingPropertyOracle.MealyLoggingPropertyOracle<>( + new MealyLassoPropertyOracle<>("X output==\"2\"", inclusionOracle, emptinessOracle, modelChecker)); - // create a black-box oracle - MealyBlackBoxOracle blackBoxOracle = new CExFirstMealyBBOracle<>(ltl); + // create an equivalence oracle, that first searches for a counter example using the ltl properties, and next + // with the W-method. + MealyEquivalenceOracle eqOracle = new EQOracleChain.MealyEQOracleChain<>( + new CExFirstOracle.MealyCExFirstOracle<>(ltl), + new MealyWpMethodEQOracle<>(mqOracle, 3)); // create an experiment - MealyBBCExperiment experiment = new MealyBBCExperiment<>(learner, - eqOracle, sigma, blackBoxOracle); + Experiment.MealyExperiment experiment = new Experiment.MealyExperiment<>(learner, eqOracle, sigma); // run the experiment experiment.run(); diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java index d209dc933e..3f9a2c5198 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java @@ -20,22 +20,23 @@ import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; -import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxOracle; -import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; -import de.learnlib.api.oracle.EmptinessOracle.MealyLassoEmptinessOracle; +import de.learnlib.api.logging.LoggingPropertyOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; import de.learnlib.api.oracle.InclusionOracle.MealyInclusionOracle; +import de.learnlib.api.oracle.LassoEmptinessOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; +import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.examples.LearningExample.MealyLearningExample; import de.learnlib.examples.mealy.ExampleTinyMealy; -import de.learnlib.oracle.blackbox.CExFirstBBOracle.CExFirstMealyBBOracle; -import de.learnlib.oracle.blackbox.ModelCheckingBBProperty.MealyBBPropertyMealyLasso; -import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; +import de.learnlib.oracle.emptiness.MealyLassoEmptinessOracleImpl; +import de.learnlib.oracle.equivalence.CExFirstOracle; +import de.learnlib.oracle.equivalence.EQOracleChain; +import de.learnlib.oracle.equivalence.MealyBFInclusionOracle; import de.learnlib.oracle.equivalence.WpMethodEQOracle.MealyWpMethodEQOracle; -import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; import de.learnlib.oracle.membership.SimulatorOmegaOracle.MealySimulatorOmegaOracle; -import de.learnlib.util.BBCExperiment.MealyBBCExperiment; +import de.learnlib.oracle.property.MealyLassoPropertyOracle; +import de.learnlib.util.Experiment; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.modelcheckers.ltsmin.LTSminLTLAlternatingBuilder; import net.automatalib.modelchecking.ModelCheckerLasso.MealyModelCheckerLasso; @@ -67,33 +68,48 @@ public static void main(String[] args) { // define the Mealy machine to be verified/learned MealyMachine mealy = le.getReferenceAutomaton(); + // create an omega membership oracle MealyOmegaMembershipOracle omqOracle = new MealySimulatorOmegaOracle<>(mealy); - MealyMembershipOracle mqOracle = omqOracle.getMealyMembershipOracle(); - - MealyEquivalenceOracle eqOracle = new MealyWpMethodEQOracle<>(mqOracle, 3); + // create a regular membership oracle + MealyMembershipOracle mqOracle = omqOracle.getMembershipOracle(); + // create a learner MealyLearner learner = new TTTLearnerMealy<>(sigma, mqOracle, AcexAnalyzers.LINEAR_FWD); + // create a model checker MealyModelCheckerLasso modelChecker = new LTSminLTLAlternatingBuilder().withString2Input(EDGE_PARSER). withString2Output(EDGE_PARSER).create(); - MealyLassoEmptinessOracle emptinessOracle = new MealyLassoMealyEmptinessOracle<>(omqOracle); + // create an emptiness oracle, that is used to disprove properties + LassoEmptinessOracle.MealyLassoEmptinessOracle + emptinessOracle = new MealyLassoEmptinessOracleImpl<>(omqOracle); - MealyInclusionOracle inclusionOracle = new MealyBreadthFirstInclusionOracle<>(1, mqOracle); + // create an inclusion oracle, that is used to find counterexamples to hypotheses + MealyInclusionOracle inclusionOracle = new MealyBFInclusionOracle<>(mqOracle, 1.0); - MealyBlackBoxProperty ltl = - new MealyBBPropertyMealyLasso<>(modelChecker, emptinessOracle, inclusionOracle, "X X X letter==\"2\""); + // create an LTL property oracle, that also logs stuff + PropertyOracle.MealyPropertyOracle ltl = new LoggingPropertyOracle.MealyLoggingPropertyOracle<>( + new MealyLassoPropertyOracle<>("X X X letter==\"2\"", inclusionOracle, emptinessOracle, modelChecker)); - MealyBlackBoxOracle blackBoxOracle = new CExFirstMealyBBOracle<>(ltl); + // create an equivalence oracle, that first searches for a counter example using the ltl properties, and next + // with the W-method. + MealyEquivalenceOracle eqOracle = new EQOracleChain.MealyEQOracleChain<>( + new CExFirstOracle.MealyCExFirstOracle<>(ltl), + new MealyWpMethodEQOracle<>(mqOracle, 3)); - MealyBBCExperiment experiment = new MealyBBCExperiment<>(learner, eqOracle, sigma, blackBoxOracle); + // create an experiment + Experiment.MealyExperiment + experiment = new Experiment.MealyExperiment<>(learner, eqOracle, sigma); + // run the experiment experiment.run(); + // get the final result MealyMachine result = experiment.getFinalHypothesis(); + // check we have the correct result assert DeterministicEquivalenceTest.findSeparatingWord(mealy, result, sigma) == null; } } diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java deleted file mode 100644 index 7710bdc2f0..0000000000 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/AbstractBreadthFirstOracle.java +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle; - -import java.util.LinkedList; -import java.util.Queue; - -import javax.annotation.ParametersAreNonnullByDefault; - -import de.learnlib.api.oracle.AutomatonOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.Query; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Word; - -/** - * Finds counterexamples to a given hypothesis by generating words in that hypothesis in a breadth-first manner. - * - * @author Jeroen Meijer - * - * @param the automaton type - * @param the input type - * @param the output type - * @param the Query type - */ -@ParametersAreNonnullByDefault -public abstract class AbstractBreadthFirstOracle, I, D, Q extends Query> - implements AutomatonOracle { - - /** - * The queue containing the words to find a counterexample with. - */ - private final Queue> queue = new LinkedList<>(); - - /** - * The maximum number of words to generate. - */ - private final int maxWords; - - /** - * Constructs a new AbstractBreadthFirstOracle. - * - * @param maxWords the maximum number of words to generate. - */ - protected AbstractBreadthFirstOracle(int maxWords) { - this.maxWords = maxWords; - } - - /** - * Returns the maximum number of words to generate. - * - * @return the maximum number of words to generate. - */ - @Override - public int getMaxWords() { - return maxWords; - } - - /** - * Returns the next input word, by popping from a queue. - * - * @see AutomatonOracle#nextInput() - */ - @Override - public Word nextInput() { - return queue.remove(); - } - - /** - * Adds a new input word to the queue. - * - * @see AutomatonOracle#addWord(Word) - */ - @Override - public void addWord(Word input) { - queue.add(input); - } - - /** - * Clears the queue. - */ - @Override - public void pre() { - queue.clear(); - } - - /** - * An implementation of a {@link AbstractBreadthFirstOracle}, that uses {@link DefaultQuery}s, and a - * {@link MembershipOracle}. - * - * @param the automaton type - * @param the input type - * @param the output type - */ - public abstract static class AbstractDefaultBFOracle, I, D> - extends AbstractBreadthFirstOracle> - implements DefaultOracle { - - /** - * The {@link MembershipOracle} used to answer {@link DefaultQuery}s. - */ - private final MembershipOracle membershipOracle; - - /** - * Constructs a new AbstractDefaultBFOracle. - * - * @param maxWords the maximum number of words to generate. - * @param membershipOracle the membership oracle to answer {@link DefaultQuery}s. - */ - protected AbstractDefaultBFOracle(int maxWords, MembershipOracle membershipOracle) { - super(maxWords); - this.membershipOracle = membershipOracle; - } - - /** - * Returns the membership oracle used to answer {@link DefaultQuery}s. - * - * @return the MembershipOracle. - */ - @Override - public MembershipOracle getMembershipOracle() { - return membershipOracle; - } - } -} diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java deleted file mode 100644 index 6174d4d257..0000000000 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracle.java +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.blackbox; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import de.learnlib.api.oracle.BlackBoxOracle; -import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; - -/** - * A {@link BlackBoxOracle} that contains a set of {@link BlackBoxProperty}s. - * - * @author Jeroen Meijer - * - * @param the automaton type - * @param the input type - * @param the output type - * @param

the BlackBoxProperty type - */ -public abstract class AbstractBlackBoxOracle> - implements BlackBoxOracle { - - /** - * The set of properties that need to be verified. - */ - private final Set

properties; - - /** - * Constructs a new {@link AbstractBlackBoxOracle} with a set of properties. - * - * @param properties the set of {@link BlackBoxProperty}s that need to be verified. - */ - protected AbstractBlackBoxOracle(Set

properties) { - this.properties = new HashSet<>(); - this.properties.addAll(properties); - for (P p : this.properties) { - p.useCache(); - } - } - - /** - * Constructs a new {@link AbstractBlackBoxOracle} with a single property. - * - * @param property the {@link BlackBoxProperty}. - */ - protected AbstractBlackBoxOracle(P property) { - this(Collections.singleton(property)); - } - - /** - * Constructs a new {@link AbstractBlackBoxOracle} with no properties. - */ - protected AbstractBlackBoxOracle() { - this(Collections.emptySet()); - } - - @Override - public Set

getProperties() { - return properties; - } -} diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java deleted file mode 100644 index c8d2f64a8e..0000000000 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/CExFirstBBOracle.java +++ /dev/null @@ -1,121 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.blackbox; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; - -import javax.annotation.Nullable; - -import de.learnlib.api.oracle.BlackBoxOracle; -import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.exception.ModelCheckingException; -import net.automatalib.words.Word; - -/** - * A {@link de.learnlib.api.oracle.BlackBoxOracle} that first tries to disprove a property, but before trying to - * disprove the next property, first try to find a counterexample to the current hypothesis. - * - * This implementation may be used when refining a hypothesis is inexpensive compared to disproving properties. - * - * This oracle will use a cache on each {@link BlackBoxProperty}. - * - * @author Jeroen Meijer - * - * @see DisproveFirstBBOracle - * - * @param the automaton type. - * @param the input type. - * @param the output type. - * @param

the {@link BlackBoxProperty} type. - */ -public class CExFirstBBOracle> - extends AbstractBlackBoxOracle { - - public CExFirstBBOracle(Set

properties) { - super(properties); - } - - public CExFirstBBOracle(P property) { - super(property); - } - - public CExFirstBBOracle() { - super(); - } - - /** - * Find a counterexample to the given hypothesis according to strategy described at {@link CExFirstBBOracle}. - * - * @see de.learnlib.api.oracle.BlackBoxOracle#findCounterExample(Object, Collection) - */ - @Nullable - @Override - public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { - DefaultQuery result = null; - final List

properties = new ArrayList<>(getProperties()); - for (int i = 0; i < properties.size() && result == null; i++) { - final P p = properties.get(i); - if (!p.isDisproved()) { - final DefaultQuery ce = p.disprove(hypothesis, inputs); - if (ce == null) { - result = p.findCounterExample(hypothesis, inputs); - } - p.clearCache(); - } - } - - return result; - } - - public static class CExFirstDFABBOracle - extends CExFirstBBOracle, I, Boolean, DFABlackBoxProperty> - implements DFABlackBoxOracle { - - public CExFirstDFABBOracle(Set> properties) { - super(properties); - } - - public CExFirstDFABBOracle(DFABlackBoxProperty property) { - super(property); - } - - public CExFirstDFABBOracle() { - super(); - } - } - - public static class CExFirstMealyBBOracle - extends CExFirstBBOracle, I, Word, MealyBlackBoxProperty> - implements MealyBlackBoxOracle { - - public CExFirstMealyBBOracle(Set> properties) { - super(properties); - } - - public CExFirstMealyBBOracle(MealyBlackBoxProperty property) { - super(property); - } - - public CExFirstMealyBBOracle() { - super(); - } - } -} diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java deleted file mode 100644 index 00040932fc..0000000000 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracle.java +++ /dev/null @@ -1,121 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.blackbox; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; - -import javax.annotation.Nullable; - -import de.learnlib.api.oracle.BlackBoxOracle; -import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.exception.ModelCheckingException; -import net.automatalib.words.Word; - -/** - * A {@link de.learnlib.api.oracle.BlackBoxOracle} that first tries to disprove all properties before finding a - * counterexample to the current hypothesis. - * - * One may favor this implementation if refining a hypothesis is expensive compared to trying to disprove properties. - * - * @author Jeroen Meijer - * - * @param the automaton type. - * @param the input type. - * @param the output type. - * @param

the {@link BlackBoxProperty} type. - */ -public class DisproveFirstBBOracle> - extends AbstractBlackBoxOracle { - - public DisproveFirstBBOracle(Set

properties) { - super(properties); - } - - public DisproveFirstBBOracle(P property) { - super(property); - } - - public DisproveFirstBBOracle() { - super(); - } - - /** - * Find a counterexample to the current hypothesis according to the strategy described at - * {@link DisproveFirstBBOracle}. - * - * @see de.learnlib.api.oracle.BlackBoxOracle#findCounterExample(Object, Collection) - */ - @Nullable - @Override - public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { - for (P p : getProperties()) { - if (!p.isDisproved()) { - p.disprove(hypothesis, inputs); - } - } - - DefaultQuery ce = null; - final List

properties = new ArrayList<>(getProperties()); - for (int i = 0; i < properties.size() && ce == null; i++) { - final P p = properties.get(i); - if (!p.isDisproved()) { - ce = p.findCounterExample(hypothesis, inputs); - p.clearCache(); - } - } - - return ce; - } - - public static class DisproveFirstDFABBOracle - extends DisproveFirstBBOracle, I, Boolean, DFABlackBoxProperty> - implements DFABlackBoxOracle { - - public DisproveFirstDFABBOracle(Set> properties) { - super(properties); - } - - public DisproveFirstDFABBOracle(DFABlackBoxProperty property) { - super(property); - } - - public DisproveFirstDFABBOracle() { - super(); - } - } - - public static class DisproveFirstMealyBBOracle - extends DisproveFirstBBOracle, I, Word, MealyBlackBoxProperty> - implements MealyBlackBoxOracle { - - public DisproveFirstMealyBBOracle(Set> properties) { - super(properties); - } - - public DisproveFirstMealyBBOracle(MealyBlackBoxProperty property) { - super(property); - } - - public DisproveFirstMealyBBOracle() { - super(); - } - } -} diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java deleted file mode 100644 index d9c61f22f4..0000000000 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/blackbox/ModelCheckingBBProperty.java +++ /dev/null @@ -1,279 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.blackbox; - -import java.util.Collection; - -import javax.annotation.Nullable; - -import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; -import de.learnlib.api.oracle.BlackBoxOracle.DFABlackBoxProperty; -import de.learnlib.api.oracle.BlackBoxOracle.MealyBlackBoxProperty; -import de.learnlib.api.oracle.EmptinessOracle; -import de.learnlib.api.oracle.EmptinessOracle.DFAEmptinessOracle; -import de.learnlib.api.oracle.EmptinessOracle.DFALassoEmptinessOracle; -import de.learnlib.api.oracle.EmptinessOracle.MealyEmptinessOracle; -import de.learnlib.api.oracle.EmptinessOracle.MealyLassoEmptinessOracle; -import de.learnlib.api.oracle.InclusionOracle; -import de.learnlib.api.oracle.InclusionOracle.DFAInclusionOracle; -import de.learnlib.api.oracle.InclusionOracle.MealyInclusionOracle; -import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.concepts.Output; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.exception.ModelCheckingException; -import net.automatalib.modelchecking.Lasso.DFALasso; -import net.automatalib.modelchecking.Lasso.MealyLasso; -import net.automatalib.modelchecking.ModelChecker; -import net.automatalib.modelchecking.ModelChecker.DFAModelChecker; -import net.automatalib.modelchecking.ModelChecker.MealyModelChecker; -import net.automatalib.modelchecking.ModelCheckerLasso.DFAModelCheckerLasso; -import net.automatalib.modelchecking.ModelCheckerLasso.MealyModelCheckerLasso; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Word; - -/** - * A {@link BlackBoxProperty} that needs a {@link ModelChecker} to verify. - * - * The main part of the implementation involves caching results in between calls to - * {@link #disprove(Output, Collection)} {@link #findCounterExample(Output, Collection)}. - * - * @author Jeroen Meijer - * - * @param

the property type. - * @param the automaton type. - * @param the input type. - * @param the output type. - * @param the result type of the {@link ModelChecker}. - */ -public class ModelCheckingBBProperty & SimpleDTS, I, D, R extends A> - implements BlackBoxProperty { - - /** - * The property to check. - */ - private P property; - - private ModelChecker modelChecker; - - private EmptinessOracle emptinessOracle; - - private InclusionOracle inclusionOracle; - - /** - * The cached result of a model checking counterexample. - */ - private R cacheResult; - - /** - * The inputs used to find the cached result. - */ - private Collection cacheInputs; - - /** - * The counterexample for this property. - */ - private R modelCheckingResult; - - /** - * The counterexample for this property as a {@link DefaultQuery}. - */ - private DefaultQuery counterExample; - - /** - * Whether to use the cache. - */ - private boolean cache; - - public ModelCheckingBBProperty( - ModelChecker modelChecker, - EmptinessOracle emptinessOracle, - InclusionOracle inclusionOracle, - P property) { - this.modelChecker = modelChecker; - this.emptinessOracle = emptinessOracle; - this.inclusionOracle = inclusionOracle; - this.property = property; - } - - public ModelChecker getModelChecker() { - return modelChecker; - } - - public void setModelChecker(ModelChecker modelChecker) { - this.modelChecker = modelChecker; - } - - public EmptinessOracle getEmptinessOracle() { - return emptinessOracle; - } - - public void setEmptinessOracle(EmptinessOracle emptinessOracle) { - this.emptinessOracle = emptinessOracle; - } - - public InclusionOracle getInclusionOracle() { - return inclusionOracle; - } - - public void setInclusionOracle(InclusionOracle inclusionOracle) { - this.inclusionOracle = inclusionOracle; - } - - @Override - public P getProperty() { - return property; - } - - @Override - public void setProperty(P property) { - this.property = property; - } - - @Override - public boolean isDisproved() { - assert (modelCheckingResult == null) == (counterExample == null); - return counterExample != null; - } - - @Override - @Nullable - public DefaultQuery getCounterExample() { - assert (modelCheckingResult == null) == (counterExample == null); - return counterExample; - } - - /** - * Finds a counterexample for the given {@code hypothesis} to this property. - * - * The model checker will only be invoked in case of a cache-miss. - * - * @param hypothesis the hypothesis. - * @param inputs the alphabet. - * @return the counterexample, or {@code null} if a counterexample could not be found. - * - * @throws ModelCheckingException see ModelChecker{@link #findCounterExample(Output, Collection)}. - */ - @Nullable - private R findCachedCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { - if (!cache || !inputs.equals(cacheInputs)) { - cacheInputs = inputs; - cacheResult = modelChecker.findCounterExample(hypothesis, inputs, property); - } - - return cacheResult; - } - - @Override - public void useCache() { - cache = true; - } - - @Override - public void clearCache() { - cacheInputs = null; - } - - /** - * Try to disprove this property given a {@code hypothesis} by means of an {@link EmptinessOracle}. - * - * @see BlackBoxProperty#disprove(Object, Collection) - */ - @Override - @Nullable - public DefaultQuery disprove(A hypothesis, Collection inputs) throws ModelCheckingException { - modelCheckingResult = findCachedCounterExample(hypothesis, inputs); - if (modelCheckingResult != null) { - counterExample = emptinessOracle.findCounterExample(modelCheckingResult, inputs); - } - return counterExample; - } - - /** - * Try to find a counterexample to the given {@code hypothesis}. - * - * @see BlackBoxProperty#findCounterExample(Object, Collection) - */ - @Override - @Nullable - public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { - final R ce = findCachedCounterExample(hypothesis, inputs); - final DefaultQuery result; - if (ce != null) { - result = inclusionOracle.findCounterExample(ce, inputs); - } else { - result = null; - } - return result; - } - - @Override - public String toString() { - return property.toString(); - } - - public static class DFABBPropertyDFA - extends ModelCheckingBBProperty, I, Boolean, DFA> - implements DFABlackBoxProperty { - - public DFABBPropertyDFA( - DFAModelChecker> modelChecker, - DFAEmptinessOracle emptinessOracle, - DFAInclusionOracle inclusionOracle, - P property) { - super(modelChecker, emptinessOracle, inclusionOracle, property); - } - } - - public static class MealyBBPropertyMealy - extends ModelCheckingBBProperty, I, Word, MealyMachine> - implements MealyBlackBoxProperty { - - public MealyBBPropertyMealy( - MealyModelChecker> modelChecker, - MealyEmptinessOracle emptinessOracle, - MealyInclusionOracle inclusionOracle, - P property) { - super(modelChecker, emptinessOracle, inclusionOracle, property); - } - } - - public static class DFABBPropertyDFALasso - extends ModelCheckingBBProperty, I, Boolean, DFALasso> - implements DFABlackBoxProperty { - - public DFABBPropertyDFALasso( - DFAModelCheckerLasso modelChecker, - DFALassoEmptinessOracle emptinessOracle, - DFAInclusionOracle inclusionOracle, - P property) { - super(modelChecker, emptinessOracle, inclusionOracle, property); - } - } - - public static class MealyBBPropertyMealyLasso - extends ModelCheckingBBProperty, I, Word, MealyLasso> - implements MealyBlackBoxProperty { - - public MealyBBPropertyMealyLasso( - MealyModelCheckerLasso modelChecker, - MealyLassoEmptinessOracle emptinessOracle, - MealyInclusionOracle inclusionOracle, - P property) { - super(modelChecker, emptinessOracle, inclusionOracle, property); - } - } -} diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java deleted file mode 100644 index 3922ed8209..0000000000 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracle.java +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.emptiness; - -import javax.annotation.ParametersAreNonnullByDefault; - -import de.learnlib.api.oracle.EmptinessOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import net.automatalib.automata.concepts.Output; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Word; - -/** - * An {@link EmptinessOracle} that generates words in a breadth-first manner. - * - * @author Jeroen Meijer - * - * @see EmptinessOracle - * @see AbstractBreadthFirstOracle - */ -@ParametersAreNonnullByDefault -public abstract class AbstractBreadthFirstEmptinessOracle & SimpleDTS, I, D> - extends AbstractBreadthFirstOracle.AbstractDefaultBFOracle - implements EmptinessOracle> { - - protected AbstractBreadthFirstEmptinessOracle(int maxWords, MembershipOracle membershipOracle) { - super(maxWords, membershipOracle); - } - - public static class DFABFEmptinessOracle - extends AbstractBreadthFirstEmptinessOracle, I, Boolean> - implements DFAEmptinessOracle { - - public DFABFEmptinessOracle(int maxWords, MembershipOracle membershipOracle) { - super(maxWords, membershipOracle); - } - } - - public static class MealyBreadthFirstEmptinessOracle - extends AbstractBreadthFirstEmptinessOracle, I, Word> - implements MealyEmptinessOracle { - - public MealyBreadthFirstEmptinessOracle(int maxWords, MembershipOracle> membershipOracle) { - super(maxWords, membershipOracle); - } - } -} diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java deleted file mode 100644 index 45df15bd94..0000000000 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessOracle.java +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.emptiness; - -import java.util.ArrayList; -import java.util.List; -import java.util.SortedSet; - -import de.learnlib.api.oracle.EmptinessOracle.LassoEmptinessOracle; -import de.learnlib.api.oracle.OmegaMembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.OmegaQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import net.automatalib.automata.concepts.Output; -import net.automatalib.modelchecking.Lasso; -import net.automatalib.modelchecking.Lasso.DFALasso; -import net.automatalib.modelchecking.Lasso.MealyLasso; -import net.automatalib.words.Word; - -/** - * A {@link LassoEmptinessOracle}, where the {@link Lasso} is given as an automaton. - * - * @author Jeroen Meijer - * - * @param the Lasso type - * @param the state type - * @param the input type - * @param the output type - */ -public abstract class AbstractLassoAutomatonEmptinessOracle, S, I, D> - extends AbstractBreadthFirstOracle> - implements LassoEmptinessOracle { - - /** - * The omega membership oracle used to answer {@link OmegaQuery}s. - */ - private final OmegaMembershipOracle omegaMembershipOracle; - - /** - * Constructs a new {@link AbstractLassoAutomatonEmptinessOracle}. - * - * @param omegaMembershipOracle the {@link OmegaMembershipOracle} used to answer {@link OmegaQuery}s. - */ - protected AbstractLassoAutomatonEmptinessOracle(OmegaMembershipOracle omegaMembershipOracle) { - super(1); - this.omegaMembershipOracle = omegaMembershipOracle; - } - - @Override - public OmegaMembershipOracle getOmegaMembershipOracle() { - return omegaMembershipOracle; - } - - /** - * Checks whether the answered {@link OmegaQuery} is a counterexample for the given {@code lasso}. - * - * @see LassoEmptinessOracle#isCounterExample(Output, DefaultQuery) - * - * @return whether the two conditions hold: - * 1. {@link LassoEmptinessOracle#isCounterExample(Output, DefaultQuery)}, and - * 2. The {@code query} contains a closed-loop, i.e. there exists {@code 0 <= i < j < query.getStates().size()}, - * such that {@code query.getStates().get(i).equals(query.getStates().get(j))}. - */ - @Override - public boolean isCounterExample(L lasso, OmegaQuery query) { - final boolean result; - // check condition 1 - if (!LassoEmptinessOracle.super.isCounterExample(lasso, query)) { - result = false; - } else { - // the states the SUL evolved through. - final List states = query.getStates(); - - // get the indices in the Lasso where the loop begins - final SortedSet indices = lasso.getLoopBeginIndices(); - - assert indices.size() > 1; - - final List indexList = new ArrayList<>(indices); - - boolean loopClosed = false; - - // check whether the loop is closed - for (int i = 0; i < indexList.size() && !loopClosed; i++) { - final S s1 = states.get(i); - final int i1 = indexList.get(i); - - // compute the first access sequence - final Word w1 = lasso.getWord().prefix(i1); - - for (int j = i + 1; j < indexList.size() && !loopClosed; j++) { - final S s2 = states.get(j); - final int i2 = indexList.get(j); - - // compute the second access sequence - final Word w2 = lasso.getWord().prefix(i2); - - loopClosed = omegaMembershipOracle.isSameState(w1, s1, w2, s2); - } - } - - result = loopClosed; - } - - return result; - } - - public static class DFALassoDFAEmptinessOracle - extends AbstractLassoAutomatonEmptinessOracle, S, I, Boolean> - implements DFALassoEmptinessOracle { - - public DFALassoDFAEmptinessOracle(OmegaMembershipOracle membershipOracle) { - super(membershipOracle); - } - } - - public static class MealyLassoMealyEmptinessOracle - extends AbstractLassoAutomatonEmptinessOracle, S, I, Word> - implements MealyLassoEmptinessOracle { - - public MealyLassoMealyEmptinessOracle(OmegaMembershipOracle> membershipOracle) { - super(membershipOracle); - } - } -} diff --git a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java b/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java deleted file mode 100644 index 654c13cebb..0000000000 --- a/oracles/bbc-oracles/src/main/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracle.java +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.inclusion; - -import de.learnlib.api.oracle.InclusionOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import net.automatalib.automata.concepts.Output; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Word; - -/** - * An {@link InclusionOracle} that generates words in a breadth-first manner. - * - * @author Jeroen Meijer - * - * @see InclusionOracle - * @see AbstractBreadthFirstOracle - */ -public abstract class AbstractBreadthFirstInclusionOracle & SimpleDTS, I, D> - extends AbstractBreadthFirstOracle.AbstractDefaultBFOracle - implements InclusionOracle> { - - public AbstractBreadthFirstInclusionOracle(int maxWords, MembershipOracle membershipOracle) { - super(maxWords, membershipOracle); - } - - public static class DFABreadthFirstInclusionOracle - extends AbstractBreadthFirstInclusionOracle, I, Boolean> - implements DFAInclusionOracle { - - public DFABreadthFirstInclusionOracle(int maxWords, MembershipOracle membershipOracle) { - super(maxWords, membershipOracle); - } - } - - public static class MealyBreadthFirstInclusionOracle - extends AbstractBreadthFirstInclusionOracle, I, Word> - implements MealyInclusionOracle { - - public MealyBreadthFirstInclusionOracle(int maxWords, MembershipOracle> membershipOracle) { - super(maxWords, membershipOracle); - } - } -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java deleted file mode 100644 index 14a4504837..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/AbstractBlackBoxOracleTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.blackbox; - -import java.util.Set; - -import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; -import net.automatalib.automata.concepts.Output; -import net.automatalib.ts.simple.SimpleDTS; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public abstract class AbstractBlackBoxOracleTest { - - public abstract AbstractBlackBoxOracle> - getBaseBlackBoxOracle(); - - @BeforeMethod - public void setUp() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testAmount() { - final Set> bbps = getBaseBlackBoxOracle().getProperties(); - Assert.assertEquals(bbps.size(), 2); - } - - @Test - public void testCache() { - final Set> bbps = getBaseBlackBoxOracle().getProperties(); - for (BlackBoxProperty bbp : bbps) { - Mockito.verify(bbp).useCache(); - } - } - - interface AutomatonMock extends SimpleDTS, Output {} -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java deleted file mode 100644 index 2d40425aa0..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/CExFirstBBOracleTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.blackbox; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; -import de.learnlib.api.query.DefaultQuery; -import net.automatalib.words.Alphabet; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public class CExFirstBBOracleTest extends AbstractBlackBoxOracleTest { - - private CExFirstBBOracle> oracle; - - @Mock - private BlackBoxProperty blackBoxProperty1; - - @Mock - private BlackBoxProperty blackBoxProperty2; - - @Mock - private DefaultQuery defaultQuery; - - @Mock - private AutomatonMock automaton; - - @Mock - private Alphabet alphabet; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.when(blackBoxProperty1.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); - Mockito.when(blackBoxProperty2.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); - - final Set> bbps = new HashSet<>(); - bbps.add(blackBoxProperty1); - bbps.add(blackBoxProperty2); - oracle = new CExFirstBBOracle<>(bbps); - } - - @Override - public AbstractBlackBoxOracle> - getBaseBlackBoxOracle() { - return oracle; - } - - /** - * Tests: - * 1. whether the correct counterexample is given by the {@link CExFirstBBOracle}, and - * 2. whether {@link BlackBoxProperty#disprove(Object, Collection)} is called only on {@link #blackBoxProperty2}. - * - * This method assumes an order on the {@link BlackBoxProperty}s, i.e.: - * {@code oracle.getProperties().iterator().next().equals(blackBoxProperty2}. - */ - @Test - public void testFindCounterExample() { - final DefaultQuery cex = oracle.findCounterExample(automaton, alphabet); - - Assert.assertEquals(cex, defaultQuery); - - final Iterator> it = oracle.getProperties().iterator(); - - final BlackBoxProperty p1 = it.next(); - final BlackBoxProperty p2 = it.next(); - - Mockito.verify(p1).disprove(automaton, alphabet); - Mockito.verify(p2, Mockito.never()).disprove(automaton, alphabet); - } -} \ No newline at end of file diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java deleted file mode 100644 index 2bc6eb5401..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/DisproveFirstBBOracleTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.blackbox; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import de.learnlib.api.oracle.BlackBoxOracle.BlackBoxProperty; -import de.learnlib.api.query.DefaultQuery; -import net.automatalib.words.Alphabet; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public class DisproveFirstBBOracleTest extends AbstractBlackBoxOracleTest { - - private DisproveFirstBBOracle> oracle; - - @Mock - private BlackBoxProperty blackBoxProperty1; - - @Mock - private BlackBoxProperty blackBoxProperty2; - - @Mock - private DefaultQuery defaultQuery; - - @Mock - private AutomatonMock automaton; - - @Mock - private Alphabet alphabet; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.when(blackBoxProperty1.findCounterExample(automaton, alphabet)).thenReturn(null); - Mockito.when(blackBoxProperty2.findCounterExample(automaton, alphabet)).thenReturn(defaultQuery); - - final Set> bbps = new HashSet<>(); - bbps.add(blackBoxProperty1); - bbps.add(blackBoxProperty2); - oracle = new DisproveFirstBBOracle<>(bbps); - } - - @Override - public AbstractBlackBoxOracle> - getBaseBlackBoxOracle() { - return oracle; - } - - /** - * Tests: - * 1. whether the correct counterexample is given by the {@link DisproveFirstBBOracle}, and - * 2. whether {@link BlackBoxProperty#disprove(Object, Collection)} is called on all {@link BlackBoxProperty}s. - */ - @Test - public void testFindCounterExample() { - final DefaultQuery cex = oracle.findCounterExample(automaton, alphabet); - - Assert.assertEquals(cex, defaultQuery); - - Mockito.verify(blackBoxProperty1).disprove(automaton, alphabet); - Mockito.verify(blackBoxProperty2).disprove(automaton, alphabet); - } -} \ No newline at end of file diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java deleted file mode 100644 index 6dba532778..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/blackbox/ModelCheckingBBPropertyTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.blackbox; - -import java.util.Collection; - -import de.learnlib.api.oracle.EmptinessOracle; -import de.learnlib.api.oracle.InclusionOracle; -import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.concepts.Output; -import net.automatalib.modelchecking.ModelChecker; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.Alphabets; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * Tests the cached, and uncached implementations of {@link ModelCheckingBBProperty#disprove(Output, Collection)}, and - * {@link ModelCheckingBBProperty#findCounterExample(Output, Collection)}. - * - * @author Jeroen Meijer - */ -public class ModelCheckingBBPropertyTest { - - private Alphabet alphabet = Alphabets.fromArray("a"); - - @Mock - private AutomatonMock automaton; - - @Mock - private ResultMock result; - - @Mock - private ModelChecker modelChecker; - - @Mock - private EmptinessOracle> emptinessOracle; - - @Mock - private InclusionOracle> inclusionOracle; - - private ModelCheckingBBProperty mcbbp; - - @BeforeMethod - public void setUp() { - MockitoAnnotations.initMocks(this); - mcbbp = new ModelCheckingBBProperty<>(modelChecker, emptinessOracle, inclusionOracle, ""); - Mockito.when(modelChecker.findCounterExample(automaton, alphabet, "")).thenReturn(result); - } - - @Test - public void testDisproveUncached() { - mcbbp.disprove(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - Mockito.verify(emptinessOracle, Mockito.times(1)).findCounterExample(result, alphabet); - mcbbp.disprove(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(2)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - } - - @Test - public void testDisproveCached() { - mcbbp.useCache(); - - mcbbp.disprove(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - Mockito.verify(emptinessOracle, Mockito.times(1)).findCounterExample(result, alphabet); - - mcbbp.disprove(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - - mcbbp.disprove(automaton, Alphabets.singleton("no-cache")); - Mockito.verify(modelChecker, Mockito.times(2)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - - mcbbp.clearCache(); - - mcbbp.disprove(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(3)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - } - - @Test - public void testFindCounterExampleUncached() { - mcbbp.findCounterExample(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - Mockito.verify(inclusionOracle, Mockito.times(1)).findCounterExample(result, alphabet); - mcbbp.findCounterExample(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(2)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - } - - @Test - public void testFindCounterExampleCached() { - mcbbp.useCache(); - - mcbbp.findCounterExample(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - Mockito.verify(inclusionOracle, Mockito.times(1)).findCounterExample(result, alphabet); - - mcbbp.findCounterExample(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(1)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - - mcbbp.findCounterExample(automaton, Alphabets.singleton("no-cache")); - Mockito.verify(modelChecker, Mockito.times(2)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - - mcbbp.clearCache(); - - mcbbp.findCounterExample(automaton, alphabet); - Mockito.verify(modelChecker, Mockito.times(3)).findCounterExample(Mockito.eq(automaton), Mockito.any(), Mockito.eq("")); - } - - interface AutomatonMock extends SimpleDTS, Output {} - - interface ResultMock extends AutomatonMock {} -} \ No newline at end of file diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java deleted file mode 100644 index a1dde3a3a9..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoAutomatonEmptinessTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.emptiness; - -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracleTest; -import net.automatalib.modelchecking.Lasso; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.Alphabets; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public abstract class AbstractLassoAutomatonEmptinessTest, D> extends - AbstractBreadthFirstOracleTest { - - public static final Alphabet ALPHABET = Alphabets.fromArray("a"); - - private AbstractLassoAutomatonEmptinessOracle laeo; - - private L lasso; - - private DefaultQuery query; - - protected abstract AbstractLassoAutomatonEmptinessOracle createLassoAutomatonEmptinessOracle(); - - protected abstract L createLasso(); - - protected abstract DefaultQuery createQuery(); - - @BeforeMethod - public void setUp() { - super.setUp(); - laeo = createLassoAutomatonEmptinessOracle(); - lasso = createLasso(); - query = createQuery(); - } - - @Test - public void testFindCounterExample() { - final DefaultQuery cex = laeo.findCounterExample(lasso, ALPHABET); - Assert.assertEquals(query, cex); - } - -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java deleted file mode 100644 index 2849e585de..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.emptiness; - -import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.examples.dfa.ExampleAngluin; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.DFABFEmptinessOracle; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.testng.annotations.BeforeMethod; - -/** - * @author Jeroen Meijer - */ -public class DFABFEmptinessOracleTest - extends AbstractBreadthFirstEmptinessOracleTest, Integer, Boolean> { - - @Mock - private DFAMembershipOracle dfaMembershipOracle; - - @Mock - private DFAMembershipOracle dfaMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final DefaultQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(0, 0))) { - q.answer(false); - } else { - q.answer(true); - } - return null; - }).when(dfaMembershipOracle).processQuery(ArgumentMatchers.any()); - } - - @Override - protected DFA createAutomaton() { - return ExampleAngluin.constructMachine(); - } - - @Override - protected AbstractBreadthFirstEmptinessOracle, Integer, Boolean> createBreadthFirstEmptinessOracle() { - return new DFABFEmptinessOracle<>(5, dfaMembershipOracle); - } - - @Override - protected Alphabet createAlphabet() { - return ExampleAngluin.createInputAlphabet(); - } - - @Override - protected DefaultQuery createQuery() { - return new DefaultQuery<>(Word.fromSymbols(1, 1), true); - } - - @Override - protected AbstractBreadthFirstOracle, Character, Boolean, DefaultQuery> createBreadthFirstOracle( - int maxWords) { - return new DFABFEmptinessOracle<>(maxWords, dfaMembershipOracle2); - } -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoDFAEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoDFAEmptinessOracleTest.java deleted file mode 100644 index 3a6f9d0de1..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoDFAEmptinessOracleTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.emptiness; - -import java.util.ArrayList; -import java.util.List; - -import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.OmegaQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.DFALassoDFAEmptinessOracle; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.fsa.impl.compact.CompactDFA; -import net.automatalib.modelchecking.DFALassoImpl; -import net.automatalib.modelchecking.Lasso.DFALasso; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.util.automata.builders.AutomatonBuilders; -import net.automatalib.words.Word; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.testng.annotations.BeforeMethod; - -/** - * @author Jeroen Meijer - */ -public class DFALassoDFAEmptinessOracleTest extends AbstractLassoAutomatonEmptinessTest, Boolean> { - - @Mock - private DFAOmegaMembershipOracle dfaOmegaMembershipOracle; - - @Mock - private DFAOmegaMembershipOracle dfaOmegaMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final OmegaQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { - q.answer(true); - final List states = new ArrayList<>(); - states.add(0); - states.add(0); - states.add(0); - states.add(0); - q.setStates(states); - } else { - q.answer(false); - } - return null; - }).when(dfaOmegaMembershipOracle).processQuery(ArgumentMatchers.any()); - Mockito.when(dfaOmegaMembershipOracle.isSameState(ArgumentMatchers.any(), - ArgumentMatchers.any(), - ArgumentMatchers.any(), - ArgumentMatchers.any())).thenReturn(true); - } - - @Override - protected AbstractLassoAutomatonEmptinessOracle, ?, String, ?> createLassoAutomatonEmptinessOracle() { - return new DFALassoDFAEmptinessOracle<>(dfaOmegaMembershipOracle); - } - - @Override - protected DFALassoImpl createLasso() { - final DFA dfa = AutomatonBuilders.forDFA(new CompactDFA<>(ALPHABET)). - from("q0").on("a").loop().withAccepting("q0").withInitial("q0").create(); - return new DFALassoImpl<>(dfa, ALPHABET, 3); - } - - @Override - protected DefaultQuery createQuery() { - return new DefaultQuery<>(Word.fromSymbols("a", "a", "a"), true); - } - - @Override - protected AbstractBreadthFirstOracle, Character, Boolean, OmegaQuery> createBreadthFirstOracle( - int maxWords) { - return new DFALassoDFAEmptinessOracle<>(dfaOmegaMembershipOracle2); - } -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java deleted file mode 100644 index 3936ce2057..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.emptiness; - -import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.examples.mealy.ExampleCoffeeMachine; -import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import de.learnlib.oracle.emptiness.AbstractBreadthFirstEmptinessOracle.MealyBreadthFirstEmptinessOracle; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.testng.annotations.BeforeMethod; - -/** - * @author Jeroen Meijer - */ -public class MealyBFEmptinessOracleTest - extends AbstractBreadthFirstEmptinessOracleTest, Input, Word> { - - @Mock - private MealyMembershipOracle mealyMembershipOracle; - - @Mock - private MealyMembershipOracle mealyMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final DefaultQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(Input.POD))) { - q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; - }).when(mealyMembershipOracle).processQuery(ArgumentMatchers.any()); - } - - @Override - protected AbstractBreadthFirstEmptinessOracle, Input, Word> createBreadthFirstEmptinessOracle() { - return new MealyBreadthFirstEmptinessOracle<>(5, mealyMembershipOracle); - } - - @Override - protected MealyMachine createAutomaton() { - return ExampleCoffeeMachine.constructMachine(); - } - - @Override - protected Alphabet createAlphabet() { - return ExampleCoffeeMachine.createInputAlphabet(); - } - - @Override - protected DefaultQuery> createQuery() { - return new DefaultQuery<>(Word.epsilon(), - Word.fromSymbols(Input.POD), - Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); - } - - @Override - protected AbstractBreadthFirstOracle, Character, Word, DefaultQuery>> createBreadthFirstOracle( - int maxWords) { - return new MealyBreadthFirstEmptinessOracle<>(maxWords, mealyMembershipOracle2); - } -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoMealyEmptinessOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoMealyEmptinessOracleTest.java deleted file mode 100644 index 657f2542ce..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoMealyEmptinessOracleTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.emptiness; - -import java.util.ArrayList; -import java.util.List; - -import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.OmegaQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import de.learnlib.oracle.emptiness.AbstractLassoAutomatonEmptinessOracle.MealyLassoMealyEmptinessOracle; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.modelchecking.Lasso.MealyLasso; -import net.automatalib.modelchecking.MealyLassoImpl; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.util.automata.builders.AutomatonBuilders; -import net.automatalib.words.Word; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.testng.annotations.BeforeMethod; - -/** - * @author Jeroen Meijer - */ -public class MealyLassoMealyEmptinessOracleTest - extends AbstractLassoAutomatonEmptinessTest, Word> { - - @Mock - private MealyOmegaMembershipOracle mealyOmegaMembershipOracle; - - @Mock - private MealyOmegaMembershipOracle mealyOmegaMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final OmegaQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols("a", "a", "a"))) { - q.answer(Word.fromSymbols("1", "1", "1")); - final List states = new ArrayList<>(); - states.add(0); - states.add(0); - states.add(0); - states.add(0); - q.setStates(states); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; - }).when(mealyOmegaMembershipOracle).processQuery(ArgumentMatchers.any()); - Mockito.when(mealyOmegaMembershipOracle.isSameState(ArgumentMatchers.any(), - ArgumentMatchers.any(), - ArgumentMatchers.any(), - ArgumentMatchers.any())).thenReturn(true); - } - - @Override - protected AbstractLassoAutomatonEmptinessOracle, ?, String, ?> createLassoAutomatonEmptinessOracle() { - return new MealyLassoMealyEmptinessOracle<>(mealyOmegaMembershipOracle); - } - - @Override - protected MealyLasso createLasso() { - final MealyMachine mealy = - AutomatonBuilders.forMealy(new CompactMealy(ALPHABET)). - from("q0").on("a").withOutput("1").loop().withInitial("q0").create(); - return new MealyLassoImpl<>(mealy, ALPHABET, 3); - } - - @Override - protected DefaultQuery> createQuery() { - return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols("a", "a", "a"), Word.fromSymbols("1", "1", "1")); - } - - @Override - protected AbstractBreadthFirstOracle, Character, Word, OmegaQuery>> createBreadthFirstOracle( - int maxWords) { - return new MealyLassoMealyEmptinessOracle<>(mealyOmegaMembershipOracle2); - } -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java deleted file mode 100644 index 057322e60f..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/AbstractBreadthFirstInclusionOracleTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.inclusion; - -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracleTest; -import net.automatalib.automata.concepts.Output; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * @author Jeroen Meijer - */ -public abstract class AbstractBreadthFirstInclusionOracleTest & Output, I, D> extends - AbstractBreadthFirstOracleTest { - - private AbstractBreadthFirstInclusionOracle bfeo; - - private A automaton; - - private Alphabet alphabet; - - private DefaultQuery query; - - protected abstract AbstractBreadthFirstInclusionOracle createBreadthFirstInclusionOracle(); - - protected abstract A createAutomaton(); - - protected abstract Alphabet createAlphabet(); - - protected abstract DefaultQuery createQuery(); - - @BeforeMethod - public void setUp() { - super.setUp(); - bfeo = createBreadthFirstInclusionOracle(); - automaton = createAutomaton(); - alphabet = createAlphabet(); - query = createQuery(); - } - - @Test - public void testFindCounterExample() { - final DefaultQuery cex = bfeo.findCounterExample(automaton, alphabet); - Assert.assertEquals(query, cex); - } - -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/DFABreadthFirstInclusionOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/DFABreadthFirstInclusionOracleTest.java deleted file mode 100644 index 90f54e58cc..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/DFABreadthFirstInclusionOracleTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.inclusion; - -import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.examples.dfa.ExampleAngluin; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.DFABreadthFirstInclusionOracle; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.testng.annotations.BeforeMethod; - -/** - * @author Jeroen Meijer - */ -public class DFABreadthFirstInclusionOracleTest - extends AbstractBreadthFirstInclusionOracleTest, Integer, Boolean> { - - @Mock - private DFAMembershipOracle dfaMembershipOracle; - - @Mock - private DFAMembershipOracle dfaMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final DefaultQuery q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(0, 0))) { - q.answer(true); - } else { - q.answer(false); - } - return null; - }).when(dfaMembershipOracle).processQuery(ArgumentMatchers.any()); - } - - @Override - protected DFA createAutomaton() { - return ExampleAngluin.constructMachine(); - } - - @Override - protected AbstractBreadthFirstInclusionOracle, Integer, Boolean> createBreadthFirstInclusionOracle() { - return new DFABreadthFirstInclusionOracle<>(5, dfaMembershipOracle); - } - - @Override - protected Alphabet createAlphabet() { - return ExampleAngluin.createInputAlphabet(); - } - - @Override - protected DefaultQuery createQuery() { - return new DefaultQuery<>(Word.fromSymbols(1, 1), false); - } - - @Override - protected AbstractBreadthFirstOracle, Character, Boolean, DefaultQuery> - createBreadthFirstOracle(int maxWords) { - return new DFABreadthFirstInclusionOracle<>(maxWords, dfaMembershipOracle2); - } -} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/MealyBreadthFirstInclusionOracleTest.java b/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/MealyBreadthFirstInclusionOracleTest.java deleted file mode 100644 index 8ec198b0e2..0000000000 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/inclusion/MealyBreadthFirstInclusionOracleTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.oracle.inclusion; - -import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.examples.mealy.ExampleCoffeeMachine; -import de.learnlib.examples.mealy.ExampleCoffeeMachine.Input; -import de.learnlib.oracle.AbstractBreadthFirstOracle; -import de.learnlib.oracle.inclusion.AbstractBreadthFirstInclusionOracle.MealyBreadthFirstInclusionOracle; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.testng.annotations.BeforeMethod; - -/** - * @author Jeroen Meijer - */ -public class MealyBreadthFirstInclusionOracleTest - extends AbstractBreadthFirstInclusionOracleTest, Input, Word> { - - @Mock - private MealyMembershipOracle mealyMembershipOracle; - - @Mock - private MealyMembershipOracle mealyMembershipOracle2; - - @BeforeMethod - public void setUp() { - super.setUp(); - Mockito.doAnswer(invocation -> { - final DefaultQuery> q = invocation.getArgument(0); - if (q.getInput().equals(Word.fromSymbols(Input.WATER))) { - q.answer(Word.fromSymbols(ExampleCoffeeMachine.OUT_OK)); - } else { - q.answer(Word.fromSymbols("not-an-output")); - } - return null; - }).when(mealyMembershipOracle).processQuery(ArgumentMatchers.any()); - - } - - @Override - protected AbstractBreadthFirstInclusionOracle, Input, Word> - createBreadthFirstInclusionOracle() { - return new MealyBreadthFirstInclusionOracle<>(5, mealyMembershipOracle); - } - - @Override - protected MealyMachine createAutomaton() { - return ExampleCoffeeMachine.constructMachine(); - } - - @Override - protected Alphabet createAlphabet() { - return ExampleCoffeeMachine.createInputAlphabet(); - } - - @Override - protected DefaultQuery> createQuery() { - return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols(Input.POD), Word.fromSymbols("not-an-output")); - } - - @Override - protected AbstractBreadthFirstOracle, - Character, Word, DefaultQuery>> - createBreadthFirstOracle(int maxWords) { - return new MealyBreadthFirstInclusionOracle<>(maxWords, mealyMembershipOracle2); - } -} diff --git a/oracles/bbc-oracles/pom.xml b/oracles/emptiness-oracles/pom.xml similarity index 62% rename from oracles/bbc-oracles/pom.xml rename to oracles/emptiness-oracles/pom.xml index 28b2d017aa..d842b3783a 100644 --- a/oracles/bbc-oracles/pom.xml +++ b/oracles/emptiness-oracles/pom.xml @@ -1,20 +1,4 @@ - 4.0.0 @@ -25,19 +9,24 @@ limitations under the License. ../pom.xml - learnlib-bbc-oracles + learnlib-emptiness-oracles - LearnLib :: Oracles :: BBC Oracles - - A collection of oracles required for block-box checking. Includes black-box, emptiness and language inclusion - oracles - + LearnLib :: Oracles :: Emptiness Oracles + A collection of emptiness oracles + + com.google.code.findbugs + jsr305 + de.learnlib learnlib-api + + de.learnlib + learnlib-util + net.automatalib automata-core @@ -50,21 +39,18 @@ limitations under the License. net.automatalib automata-api + - com.google.code.findbugs - jsr305 - - - de.learnlib.testsupport - learnlib-learning-examples + org.testng + testng org.mockito mockito-core - org.testng - testng + de.learnlib.testsupport + learnlib-oracle-support diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracle.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracle.java new file mode 100644 index 0000000000..8d50bf82f1 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracle.java @@ -0,0 +1,56 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import java.util.Collection; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.util.AbstractBFOracle; +import net.automatalib.automata.concepts.DetOutputAutomaton; + +/** + * An {@link EmptinessOracle} that tries words in a breadth-first manner. + * + * @param the automaton type + * @param the input type + * @param the output type + * + * @author Jeroen Meijer + */ +@ParametersAreNonnullByDefault +abstract class AbstractBFEmptinessOracle, I, D> + extends AbstractBFOracle implements EmptinessOracle { + + protected AbstractBFEmptinessOracle(MembershipOracle membershipOracle, double multiplier) { + super(membershipOracle, multiplier); + } + + @Override + public boolean isCounterExample(A hypothesis, Iterable inputs, @Nullable D output) { + return EmptinessOracle.super.isCounterExample(hypothesis, inputs, output); + } + + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + return super.findCounterExample(hypothesis, inputs); + } +} diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracle.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracle.java new file mode 100644 index 0000000000..dd79ed42c1 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracle.java @@ -0,0 +1,29 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.AutomatonOracle; +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.fsa.DFA; + +public class DFABFEmptinessOracle extends AbstractBFEmptinessOracle, I, Boolean> + implements EmptinessOracle.DFAEmptinessOracle, AutomatonOracle.DFAOracle { + + public DFABFEmptinessOracle(MembershipOracle membershipOracle, double multiplier) { + super(membershipOracle, multiplier); + } +} diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java new file mode 100644 index 0000000000..19de071f6d --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java @@ -0,0 +1,30 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.LassoEmptinessOracle; +import de.learnlib.api.oracle.LassoOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle; +import net.automatalib.modelchecking.Lasso; + +public class DFALassoEmptinessOracleImpl + extends LassoEmptinessOracleImpl, S, I, Boolean> + implements LassoEmptinessOracle.DFALassoEmptinessOracle, LassoOracle.DFALassoOracle { + + public DFALassoEmptinessOracleImpl(OmegaMembershipOracle omegaMembershipOracle) { + super(omegaMembershipOracle); + } +} diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java new file mode 100644 index 0000000000..4de67911f2 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java @@ -0,0 +1,70 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import java.util.Collection; + +import javax.annotation.Nullable; + +import de.learnlib.api.oracle.LassoEmptinessOracle; +import de.learnlib.api.oracle.LassoOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import de.learnlib.util.AbstractBFOracle; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.words.Word; + +public class LassoEmptinessOracleImpl, S, I, D> + extends AbstractBFOracle + implements LassoEmptinessOracle, LassoOracle { + + /** + * The {@link OmegaMembershipOracle} used to answer {@link OmegaQuery}s. + */ + private final OmegaMembershipOracle omegaMembershipOracle; + + public LassoEmptinessOracleImpl(OmegaMembershipOracle omegaMembershipOracle) { + super(omegaMembershipOracle.getMembershipOracle(), -1.0); + this.omegaMembershipOracle = omegaMembershipOracle; + } + + public OmegaMembershipOracle getOmegaMembershipOracle() { + return omegaMembershipOracle; + } + + @Override + public OmegaQuery processOmegaQuery(OmegaQuery query) { + omegaMembershipOracle.processQuery(query); + return query; + } + + @Override + public boolean isCounterExample(L hypothesis, Iterable inputs, @Nullable D output) { + return LassoEmptinessOracle.super.isCounterExample(hypothesis, inputs, output); + } + + @Nullable + @Override + public DefaultQuery findCounterExample(L hypothesis, Collection inputs) { + return LassoOracle.super.findCounterExample(hypothesis, inputs); + } + + @Override + public DefaultQuery processInput(L hypothesis, Word input) { + return LassoOracle.super.processInput(hypothesis, input); + } +} diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracle.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracle.java new file mode 100644 index 0000000000..591c7eb963 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracle.java @@ -0,0 +1,30 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.AutomatonOracle; +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +public class MealyBFEmptinessOracle extends AbstractBFEmptinessOracle, I, Word> + implements EmptinessOracle.MealyEmptinessOracle, AutomatonOracle.MealyOracle { + + public MealyBFEmptinessOracle(MembershipOracle> membershipOracle, double multiplier) { + super(membershipOracle, multiplier); + } +} diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java new file mode 100644 index 0000000000..aa4d8953d1 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java @@ -0,0 +1,31 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.LassoEmptinessOracle; +import de.learnlib.api.oracle.LassoOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.words.Word; + +public class MealyLassoEmptinessOracleImpl + extends LassoEmptinessOracleImpl, S, I, Word> + implements LassoEmptinessOracle.MealyLassoEmptinessOracle, LassoOracle.MealyLassoOracle { + + public MealyLassoEmptinessOracleImpl(OmegaMembershipOracle> omegaMembershipOracle) { + super(omegaMembershipOracle); + } +} diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java similarity index 56% rename from oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java rename to oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java index 17c8682bba..61c9bd3644 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBreadthFirstEmptinessOracleTest.java +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java @@ -16,49 +16,55 @@ package de.learnlib.oracle.emptiness; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.oracle.AbstractBreadthFirstOracleTest; -import net.automatalib.automata.concepts.Output; +import de.learnlib.oracle.AbstractBFOracleTest; +import de.learnlib.util.AbstractBFOracle; +import net.automatalib.automata.concepts.DetOutputAutomaton; import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.Alphabet; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** + * Tests any breadth-first emptiness oracle. + * * @author Jeroen Meijer */ -public abstract class AbstractBreadthFirstEmptinessOracleTest & Output, I, D> extends - AbstractBreadthFirstOracleTest { +public abstract class AbstractBFEmptinessOracleTest, D> + extends AbstractBFOracleTest { - private AbstractBreadthFirstEmptinessOracle bfeo; + private AbstractBFEmptinessOracle bfeo; private A automaton; - private Alphabet alphabet; - - private DefaultQuery query; + private DefaultQuery query; - protected abstract AbstractBreadthFirstEmptinessOracle createBreadthFirstEmptinessOracle(); + protected abstract AbstractBFEmptinessOracle createBreadthFirstEmptinessOracle(); protected abstract A createAutomaton(); - protected abstract Alphabet createAlphabet(); - - protected abstract DefaultQuery createQuery(); + protected abstract DefaultQuery createQuery(); @BeforeMethod public void setUp() { super.setUp(); bfeo = createBreadthFirstEmptinessOracle(); automaton = createAutomaton(); - alphabet = createAlphabet(); query = createQuery(); } + @Override + protected AbstractBFOracle, Character, D> createBreadthFirstOracle(double multiplier) { + return createBreadthFirstEmptinessOracle(); + } + @Test public void testFindCounterExample() { - final DefaultQuery cex = bfeo.findCounterExample(automaton, alphabet); - Assert.assertEquals(query, cex); + final DefaultQuery cex = bfeo.findCounterExample(automaton, ALPHABET); + Assert.assertEquals(cex, query); } -} + @Test + public void testIsCounterExample() throws Exception { + bfeo.isCounterExample(automaton, query.getInput(), query.getOutput()); + } +} \ No newline at end of file diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java new file mode 100644 index 0000000000..87ce61f58f --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java @@ -0,0 +1,112 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import de.learnlib.oracle.AbstractBFOracleTest; +import de.learnlib.util.AbstractBFOracle; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Tests the {@link LassoEmptinessOracleImpl} and all its subtypes. + * + * @author Jeroen Meijer + * + * @param the lasso type + * @param the output type + */ +public abstract class AbstractLassoEmptinessOracleImplTest, D> + extends AbstractBFOracleTest { + + private LassoEmptinessOracleImpl leo; + + private final Word prefix = Word.epsilon(); + + private final Word loop = Word.fromSymbols('a'); + + private D output; + + private L automaton; + + private DefaultQuery query; + + protected abstract LassoEmptinessOracleImpl createLassoEmptinessOracleImpl(); + + protected abstract D createOutput(); + + protected abstract L createAutomaton(); + + protected abstract DefaultQuery createQuery(); + + @BeforeMethod + public void setUp() { + super.setUp(); + leo = createLassoEmptinessOracleImpl(); + automaton = createAutomaton(); + query = createQuery(); + output = createOutput(); + } + + @Override + @Test + public void testGetMultiplier() { + Assert.assertEquals(leo.getMultiplier(), -1.0); + } + + @Test + public void testProcessOmegaQuery() throws Exception { + final OmegaQuery test = new OmegaQuery<>(prefix, loop, 1); + + Mockito.doAnswer(invocation -> { + final OmegaQuery q = invocation.getArgument(0); + if (q.getLoop().equals(Word.fromSymbols('a'))) { + q.answer(output, 1); + } else { + q.answer(null, -1); + } + return null; + }).when(leo.getOmegaMembershipOracle()).processQuery(ArgumentMatchers.any()); + + leo.processOmegaQuery(test); + + Assert.assertEquals(test.getOutput(), output); + Assert.assertEquals(test.getPeriodicity(), 1); + } + + @Override + protected AbstractBFOracle, Character, D> createBreadthFirstOracle(double multiplier) { + return createLassoEmptinessOracleImpl(); + } + + @Test + public void testFindCounterExample() { + final DefaultQuery cex = leo.findCounterExample(automaton, ALPHABET); + Assert.assertEquals(cex, query); + } + + @Test + public void testIsCounterExample() throws Exception { + leo.isCounterExample(automaton, query.getInput(), query.getOutput()); + } +} \ No newline at end of file diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java new file mode 100644 index 0000000000..cc96892a40 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java @@ -0,0 +1,67 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class DFABFEmptinessOracleTest extends AbstractBFEmptinessOracleTest, Boolean> { + + @Mock + private MembershipOracle.DFAMembershipOracle mo; + + @Override + protected AbstractBFEmptinessOracle, Character, Boolean> createBreadthFirstEmptinessOracle() { + return new DFABFEmptinessOracle<>(mo, MULTIPLIER); + } + + @Override + protected DFA createAutomaton() { + final DFA dfa = AutomatonBuilders.forDFA(new CompactDFA<>(ALPHABET)). + from("q0").on('a').loop().withAccepting("q0").withInitial("q0").create(); + return dfa; + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols('a'), true); + } + + @BeforeMethod + public void setUp() { + super.setUp(); + Mockito.doAnswer(invocation -> { + final DefaultQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols('a'))) { + q.answer(true); + } else { + q.answer(false); + } + return null; + }).when(mo).processQuery(ArgumentMatchers.any()); + } +} \ No newline at end of file diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java new file mode 100644 index 0000000000..7a9b0b3640 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java @@ -0,0 +1,79 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.OmegaMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.lasso.DFALassoImpl; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class DFALassoEmptinessOracleImplTest + extends AbstractLassoEmptinessOracleImplTest, Boolean> { + + @Mock + private OmegaMembershipOracle.DFAOmegaMembershipOracle omo; + + @BeforeMethod + public void setUp() { + super.setUp(); + + Mockito.doAnswer(invocation -> { + final OmegaQuery q = invocation.getArgument(0); + if (q.getLoop().equals(Word.fromSymbols('a'))) { + q.answer(true, 1); + } else { + q.answer(false, 1); + } + return null; + }).when(omo).processQuery(ArgumentMatchers.any()); + + Mockito.when(omo.isSameState(Word.epsilon(), 0, Word.fromSymbols('a'), 0)).thenReturn(true); + } + + @Override + protected LassoEmptinessOracleImpl, Integer, Character, Boolean> createLassoEmptinessOracleImpl() { + return new DFALassoEmptinessOracleImpl<>(omo); + } + + @Override + protected Boolean createOutput() { + return true; + } + + @Override + protected Lasso.DFALasso createAutomaton() { + final DFA dfa = AutomatonBuilders.forDFA(new CompactDFA<>(ALPHABET)). + from("q0").on('a').loop().withAccepting("q0").withInitial("q0").create(); + return new DFALassoImpl<>(dfa, ALPHABET, 3); + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols('a'), true); + } +} \ No newline at end of file diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java new file mode 100644 index 0000000000..c887d38c69 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java @@ -0,0 +1,68 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class MealyBFEmptinessOracleTest + extends AbstractBFEmptinessOracleTest, Word> { + + @Mock + private MembershipOracle.MealyMembershipOracle mo; + + @Override + protected AbstractBFEmptinessOracle, Character, Word> + createBreadthFirstEmptinessOracle() { + return new MealyBFEmptinessOracle<>(mo, MULTIPLIER); + } + + @Override + protected MealyMachine createAutomaton() { + return AutomatonBuilders.forMealy(new CompactMealy(ALPHABET)). + from("q0").on('a').withOutput('1').loop().withInitial("q0").create(); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols('a'), Word.fromSymbols('1')); + } + + @BeforeMethod + public void setUp() { + super.setUp(); + Mockito.doAnswer(invocation -> { + final DefaultQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols('a'))) { + q.answer(Word.fromSymbols('1')); + } else { + q.answer(null); + } + return null; + }).when(mo).processQuery(ArgumentMatchers.any()); + } +} \ No newline at end of file diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java new file mode 100644 index 0000000000..e0e12bdecc --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java @@ -0,0 +1,80 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.emptiness; + +import de.learnlib.api.oracle.OmegaMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.lasso.MealyLassoImpl; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +/** + * @author Jeroen Meijer + */ +public class MealyLassoEmptinessOracleImplTest + extends AbstractLassoEmptinessOracleImplTest, Word> { + + @Mock + private OmegaMembershipOracle.MealyOmegaMembershipOracle omo; + + @BeforeMethod + public void setUp() { + super.setUp(); + + Mockito.doAnswer(invocation -> { + final OmegaQuery> q = invocation.getArgument(0); + if (q.getLoop().equals(Word.fromSymbols('a'))) { + q.answer(Word.fromSymbols('1'), 1); + } else { + q.answer(Word.epsilon(), 1); + } + return null; + }).when(omo).processQuery(ArgumentMatchers.any()); + + Mockito.when(omo.isSameState(Word.epsilon(), 0, Word.fromSymbols('a'), 0)).thenReturn(true); + } + + @Override + protected LassoEmptinessOracleImpl, Integer, Character, Word> createLassoEmptinessOracleImpl() { + return new MealyLassoEmptinessOracleImpl<>(omo); + } + + @Override + protected Word createOutput() { + return Word.fromSymbols('1'); + } + + @Override + protected Lasso.MealyLasso createAutomaton() { + final MealyMachine mealy = + AutomatonBuilders.forMealy(new CompactMealy(ALPHABET)). + from("q0").on('a').withOutput('1').loop().withInitial("q0").create(); + return new MealyLassoImpl<>(mealy, ALPHABET, 3); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols('a'), Word.fromSymbols('1')); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/pom.xml b/oracles/equivalence-oracles/pom.xml index f3397f5977..5cf2c170a4 100644 --- a/oracles/equivalence-oracles/pom.xml +++ b/oracles/equivalence-oracles/pom.xml @@ -39,6 +39,11 @@ limitations under the License. learnlib-api + + de.learnlib + learnlib-util + + net.automatalib @@ -74,10 +79,6 @@ limitations under the License. --> - - org.testng - testng - de.learnlib learnlib-membership-oracles @@ -93,5 +94,17 @@ limitations under the License. automata-core test + + org.testng + testng + + + org.mockito + mockito-core + + + de.learnlib.testsupport + learnlib-oracle-support + diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracle.java new file mode 100644 index 0000000000..f66d54bbe7 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracle.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Collection; + +import javax.annotation.Nullable; + +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.util.AbstractBFOracle; +import net.automatalib.automata.concepts.DetOutputAutomaton; + +/** + * An {@link InclusionOracle} that generates words in a breadth-first manner. + * + * @author Jeroen Meijer + * + * @see InclusionOracle + * @see AbstractBFOracle + */ +public abstract class AbstractBFInclusionOracle, I, D> + extends AbstractBFOracle implements InclusionOracle { + + public AbstractBFInclusionOracle(MembershipOracle membershipOracle, double multiplier) { + super(membershipOracle, multiplier); + } + + @Override + public boolean isCounterExample(A hypothesis, Iterable inputs, @Nullable D output) { + return InclusionOracle.super.isCounterExample(hypothesis, inputs, output); + } + + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + return super.findCounterExample(hypothesis, inputs); + } +} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java new file mode 100644 index 0000000000..9661e7bcd6 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java @@ -0,0 +1,117 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Collection; +import java.util.Collections; + +import javax.annotation.Nullable; + +import de.learnlib.api.oracle.BlackBoxOracle; +import de.learnlib.api.oracle.PropertyOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +/** + * The strategy of this black-box oracle is to first try out a property, to see if it can be disproved. If it can not be + * disproved it tries the same property to find a counter example to the hypothesis, before continuing with the next + * property. + *

+ * This implementation may be used when refining a hypothesis is inexpensive compared to disproving propertyOracles. + * + * @author Jeroen Meijer + * + * @see DisproveFirstOracle + * + * @param the automaton type + * @param the input type + * @param the output type + */ +public class CExFirstOracle, I, D> implements BlackBoxOracle { + + private final Collection> propertyOracles; + + public CExFirstOracle() { + this(Collections.emptySet()); + } + + public CExFirstOracle(PropertyOracle propertyOracle) { + this(Collections.singleton(propertyOracle)); + } + + public CExFirstOracle(Collection> propertyOracles) { + this.propertyOracles = Collections.unmodifiableCollection(propertyOracles); + } + + @Override + public Collection> getPropertyOracles() { + return propertyOracles; + } + + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + for (PropertyOracle propertyOracle : propertyOracles) { + if (!propertyOracle.isDisproved()) { + final DefaultQuery ce = propertyOracle.disprove(hypothesis, inputs); + if (ce == null) { + final DefaultQuery result = propertyOracle.findCounterExample(hypothesis, inputs); + if (result != null) { + assert isCounterExample(hypothesis, result.getInput(), result.getOutput()); + return result; + } + } + } + } + + return null; + } + + public static class DFACExFirstOracle extends CExFirstOracle, I, Boolean> + implements DFABlackBoxOracle { + + public DFACExFirstOracle() { + super(); + } + + public DFACExFirstOracle(PropertyOracle, ?, Boolean> propertyOracle) { + super(propertyOracle); + } + + public DFACExFirstOracle(Collection, ?, Boolean>> propertyOracles) { + super(propertyOracles); + } + } + + public static class MealyCExFirstOracle extends CExFirstOracle, I, Word> + implements MealyBlackBoxOracle { + + public MealyCExFirstOracle() { + super(); + } + + public MealyCExFirstOracle(PropertyOracle, ?, Word> propertyOracle) { + super(propertyOracle); + } + + public MealyCExFirstOracle(Collection, ?, Word>> propertyOracles) { + super(propertyOracles); + } + } +} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DFABFInclusionOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DFABFInclusionOracle.java new file mode 100644 index 0000000000..23721edc35 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DFABFInclusionOracle.java @@ -0,0 +1,29 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import de.learnlib.api.oracle.AutomatonOracle; +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.fsa.DFA; + +public class DFABFInclusionOracle extends AbstractBFInclusionOracle, I, Boolean> + implements InclusionOracle.DFAInclusionOracle, AutomatonOracle.DFAOracle { + + public DFABFInclusionOracle(MembershipOracle membershipOracle, double multiplier) { + super(membershipOracle, multiplier); + } +} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java new file mode 100644 index 0000000000..985ceb92d9 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java @@ -0,0 +1,121 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Collection; +import java.util.Collections; + +import javax.annotation.Nullable; + +import de.learnlib.api.oracle.BlackBoxOracle; +import de.learnlib.api.oracle.PropertyOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +/** + * The strategy of this black-box oracle is to first try to disprove all properties before finding a counter example + * to the given hypothesis. + *

+ * One may favor this implementation if refining a hypothesis is expensive compared to trying to disprove properties. + * + * @author Jeroen Meijer + * + * @see CExFirstOracle + * + * @param the automaton type + * @param the input type + * @param the output type + */ +public class DisproveFirstOracle, I, D> implements BlackBoxOracle { + + private final Collection> propertyOracles; + + public DisproveFirstOracle() { + this(Collections.emptySet()); + } + + public DisproveFirstOracle(PropertyOracle propertyOracle) { + this(Collections.singleton(propertyOracle)); + } + + public DisproveFirstOracle(Collection> propertyOracles) { + this.propertyOracles = Collections.unmodifiableCollection(propertyOracles); + } + + @Override + public Collection> getPropertyOracles() { + return propertyOracles; + } + + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + for (PropertyOracle po : propertyOracles) { + if (!po.isDisproved()) { + po.disprove(hypothesis, inputs); + } + } + + DefaultQuery ce = null; + for (PropertyOracle po : propertyOracles) { + if (!po.isDisproved()) { + ce = po.findCounterExample(hypothesis, inputs); + if (ce != null) { + break; + } + } + } + + assert ce == null || isCounterExample(hypothesis, ce.getInput(), ce.getOutput()); + + return ce; + } + + public static class DFADisproveFirstOracle extends DisproveFirstOracle, I, Boolean> + implements DFABlackBoxOracle { + + public DFADisproveFirstOracle() { + super(); + } + + public DFADisproveFirstOracle(PropertyOracle, ?, Boolean> propertyOracle) { + super(propertyOracle); + } + + public DFADisproveFirstOracle(Collection, ?, Boolean>> propertyOracles) { + super(propertyOracles); + } + } + + public static class MealyDisproveFirstOracle extends DisproveFirstOracle, I, Word> + implements MealyBlackBoxOracle { + + public MealyDisproveFirstOracle() { + super(); + } + + public MealyDisproveFirstOracle(PropertyOracle, ?, Word> propertyOracle) { + super(propertyOracle); + } + + public MealyDisproveFirstOracle(Collection, ?, Word>> propertyOracles) { + super(propertyOracles); + } + } +} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EQOracleChain.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EQOracleChain.java index 9e78438ab6..8eab5a2b5b 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EQOracleChain.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EQOracleChain.java @@ -39,6 +39,10 @@ public EQOracleChain(List> oracles) this.oracles = new ArrayList<>(oracles); } + public void addOracle(EquivalenceOracle oracle) { + oracles.add(oracle); + } + @Override public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { for (EquivalenceOracle eqOracle : oracles) { diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracle.java new file mode 100644 index 0000000000..35c199506a --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracle.java @@ -0,0 +1,30 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import de.learnlib.api.oracle.AutomatonOracle; +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +public class MealyBFInclusionOracle extends AbstractBFInclusionOracle, I, Word> + implements InclusionOracle.MealyInclusionOracle, AutomatonOracle.MealyOracle { + + public MealyBFInclusionOracle(MembershipOracle> membershipOracle, double multiplier) { + super(membershipOracle, multiplier); + } +} diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java new file mode 100644 index 0000000000..599c7394c9 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java @@ -0,0 +1,73 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.oracle.AbstractBFOracleTest; +import de.learnlib.util.AbstractBFOracle; +import net.automatalib.automata.concepts.DetOutputAutomaton; +import net.automatalib.ts.simple.SimpleDTS; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Tests any breadth-first inclusion oracle. + * + * @author Jeroen Meijer + * + * @param the output type + */ +public abstract class AbstractBFInclusionOracleTest, D> + extends AbstractBFOracleTest { + + private DefaultQuery query; + + private AbstractBFInclusionOracle bfio; + + private A automaton; + + protected abstract DefaultQuery createQuery(); + + protected abstract AbstractBFInclusionOracle createBreadthFirstInclusionOracle(); + + protected abstract A createAutomaton(); + + @Override + protected AbstractBFOracle, Character, D> createBreadthFirstOracle(double multiplier) { + return createBreadthFirstInclusionOracle(); + } + + @BeforeMethod + public void setUp() { + super.setUp(); + + query = createQuery(); + bfio = createBreadthFirstInclusionOracle(); + automaton = createAutomaton(); + } + + @Test + public void testIsCounterExample() throws Exception { + Assert.assertTrue(bfio.isCounterExample(automaton, query.getInput(), query.getOutput())); + } + + @Test + public void testFindCounterExample() throws Exception { + final DefaultQuery cex = bfio.findCounterExample(automaton, ALPHABET); + Assert.assertEquals(cex, query); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java new file mode 100644 index 0000000000..3fd0833e79 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java @@ -0,0 +1,86 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Collection; + +import com.google.common.collect.Lists; +import de.learnlib.api.oracle.BlackBoxOracle; +import de.learnlib.api.oracle.PropertyOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; +import net.automatalib.words.Alphabet; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class CExFirstOracleTest { + + @Mock + private PropertyOracle, Boolean, Boolean> po1; + + @Mock + private PropertyOracle, Boolean, Boolean> po2; + + private BlackBoxOracle, Boolean, Boolean> oracle; + + @Mock + private DefaultQuery query; + + @Mock + private Output automaton; + + @Mock + private Alphabet inputs; + + @BeforeMethod + public void setUp() { + MockitoAnnotations.initMocks(this); + + // make sure the assertion check for InclusionOracle.isCounterExample passes + Mockito.when(query.getInput()).thenReturn(null); + Mockito.when(query.getOutput()).thenReturn(Boolean.TRUE); + Mockito.when(automaton.computeOutput(Mockito.any())).thenReturn(Boolean.FALSE); + + oracle = new CExFirstOracle<>(Lists.newArrayList(po1, po2)); + Mockito.when(po1.findCounterExample(automaton, inputs)).thenReturn(query); + Mockito.when(po2.findCounterExample(automaton, inputs)).thenReturn(query); + } + + @Test + public void testGetPropertyOracles() throws Exception { + Assert.assertEquals(oracle.getPropertyOracles().size(), 2); + } + + /** + * Tests: + * 1. whether the correct counterexample is given by the {@link CExFirstOracle}, and + * 2. whether {@link PropertyOracle#disprove(Object, Collection)} is called only on {@link #po2}. + */ + @Test + public void testFindCounterExample() throws Exception { + final DefaultQuery ce = oracle.findCounterExample(automaton, inputs); + + Assert.assertEquals(ce, query); + + Mockito.verify(po1).disprove(automaton, inputs); + Mockito.verify(po2, Mockito.never()).disprove(automaton, inputs); + Mockito.verify(po2, Mockito.never()).findCounterExample(automaton, inputs); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DFABFInclusionOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DFABFInclusionOracleTest.java new file mode 100644 index 0000000000..82a87ed002 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DFABFInclusionOracleTest.java @@ -0,0 +1,64 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +public class DFABFInclusionOracleTest extends AbstractBFInclusionOracleTest, Boolean> { + + @Mock + private MembershipOracle.DFAMembershipOracle mo; + + @BeforeMethod + public void setUp() { + super.setUp(); + + Mockito.doAnswer(invocation -> { + final DefaultQuery q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols('a'))) { + q.answer(false); + } else { + q.answer(true); + } + return null; + }).when(mo).processQuery(ArgumentMatchers.any()); + } + + @Override + protected DefaultQuery createQuery() { + return new DefaultQuery<>(Word.fromSymbols('a'), false); + } + + @Override + protected AbstractBFInclusionOracle, Character, Boolean> createBreadthFirstInclusionOracle() { + return new DFABFInclusionOracle<>(mo, MULTIPLIER); + } + + @Override + protected DFA createAutomaton() { + return AutomatonBuilders.forDFA(new CompactDFA<>(ALPHABET)). + from("q0").on('a').loop().withAccepting("q0").withInitial("q0").create(); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java new file mode 100644 index 0000000000..7f1eed1f6e --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java @@ -0,0 +1,86 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import java.util.Collection; + +import com.google.common.collect.Lists; +import de.learnlib.api.oracle.BlackBoxOracle; +import de.learnlib.api.oracle.PropertyOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; +import net.automatalib.words.Alphabet; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class DisproveFirstOracleTest { + + @Mock + private PropertyOracle, Boolean, Boolean> po1; + + @Mock + private PropertyOracle, Boolean, Boolean> po2; + + private BlackBoxOracle, Boolean, Boolean> oracle; + + @Mock + private DefaultQuery query; + + @Mock + private Output automaton; + + @Mock + private Alphabet inputs; + + @BeforeMethod + public void setUp() { + MockitoAnnotations.initMocks(this); + + // make sure the assertion check for InclusionOracle.isCounterExample passes + Mockito.when(query.getInput()).thenReturn(null); + Mockito.when(query.getOutput()).thenReturn(Boolean.TRUE); + Mockito.when(automaton.computeOutput(Mockito.any())).thenReturn(Boolean.FALSE); + + oracle = new DisproveFirstOracle<>(Lists.newArrayList(po1, po2)); + Mockito.when(po1.findCounterExample(automaton, inputs)).thenReturn(query); + Mockito.when(po2.findCounterExample(automaton, inputs)).thenReturn(query); + } + + @Test + public void testGetPropertyOracles() throws Exception { + Assert.assertEquals(oracle.getPropertyOracles().size(), 2); + } + + /** + * Tests: + * 1. whether the correct counterexample is given by the {@link DisproveFirstOracle}, and + * 2. whether {@link PropertyOracle#disprove(Object, Collection)} is called only on {@link #po2}. + */ + @Test + public void testFindCounterExample() throws Exception { + final DefaultQuery ce = oracle.findCounterExample(automaton, inputs); + + Assert.assertEquals(ce, query); + + Mockito.verify(po1).disprove(automaton, inputs); + Mockito.verify(po2).disprove(automaton, inputs); + Mockito.verify(po2, Mockito.never()).findCounterExample(automaton, inputs); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracleTest.java new file mode 100644 index 0000000000..e1758ec4f8 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracleTest.java @@ -0,0 +1,65 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.words.Word; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; + +public class MealyBFInclusionOracleTest extends AbstractBFInclusionOracleTest, Word> { + + @Mock + private MembershipOracle.MealyMembershipOracle mo; + + @BeforeMethod + public void setUp() { + super.setUp(); + + Mockito.doAnswer(invocation -> { + final DefaultQuery> q = invocation.getArgument(0); + if (q.getInput().equals(Word.fromSymbols('a'))) { + q.answer(Word.fromSymbols('2')); + } else { + q.answer(Word.epsilon()); + } + return null; + }).when(mo).processQuery(ArgumentMatchers.any()); + } + + @Override + protected DefaultQuery> createQuery() { + return new DefaultQuery<>(Word.epsilon(), Word.fromSymbols('a'), Word.fromSymbols('2')); + } + + @Override + protected AbstractBFInclusionOracle, Character, Word> + createBreadthFirstInclusionOracle() { + return new MealyBFInclusionOracle<>(mo, MULTIPLIER); + } + + @Override + protected MealyMachine createAutomaton() { + return AutomatonBuilders.forMealy(new CompactMealy(ALPHABET)). + from("q0").on('a').withOutput('1').loop().withInitial("q0").create(); + } +} \ No newline at end of file diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java index 7a3d2a53cb..16ba109bdf 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java @@ -18,7 +18,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Set; import javax.annotation.Nonnull; @@ -38,8 +37,8 @@ * * The behavior is similar to a {@link SULOracle}, except that this class answers {@link OmegaQuery}s. * - * After some symbols (as specified in {@link OmegaQuery#getIndices()}) in an input word the state of the {@link - * ObservableSUL} is retrieved, and used to answer the query. + * After some symbols (i.e. after {@link OmegaQuery#getPrefix()}, and after each {@link OmegaQuery#getLoop()}) the state + * of the {@link ObservableSUL} is retrieved, and used to answer the query. * * Like {@link SULOracle} this class is thread-safe. * @@ -74,7 +73,7 @@ public ObservableSUL getSul() { } @Override - public void processQueries(Collection>> queries) { + public void processQueries(Collection>> queries) { if (localSul != null) { processQueries(localSul.get(), queries); } else { @@ -84,52 +83,55 @@ public void processQueries(Collection>> queri } } - private void processQueries(ObservableSUL sul, Collection>> queries) { - for (OmegaQuery> q : queries) { - final Pair, List> output = answerQuery(sul, q.getPrefix(), q.getSuffix(), q.getIndices()); - q.answer(output.getFirst()); - q.setStates(output.getSecond()); + private void processQueries(ObservableSUL sul, Collection>> queries) { + for (OmegaQuery> q : queries) { + final Pair, Integer> output = answerQuery(sul, q.getPrefix(), q.getLoop(), q.getRepeat()); + q.answer(output.getFirst(), output.getSecond()); } } protected abstract Q getQueryState(ObservableSUL sul); @Nonnull - private Pair, List> answerQuery(ObservableSUL sul, - Word prefix, - Word suffix, - Set indices) throws SULException { + private Pair, Integer> answerQuery(ObservableSUL sul, Word prefix, Word loop, int repeat) + throws SULException { + assert repeat > 0; sul.pre(); try { - int index = 0; - final List states = new ArrayList<>(); + final int traceLength = prefix.length() + loop.length() * repeat; + final WordBuilder inputBuilder = new WordBuilder<>(traceLength, prefix); + final WordBuilder outputBuilder = new WordBuilder<>(traceLength); + final List states = new ArrayList<>(repeat + 1); - // Prefix: Execute symbols, don't record output - for (I sym : prefix) { - sul.step(sym); + for (int i = 0; i < prefix.length(); i++) { + outputBuilder.append(sul.step(prefix.getSymbol(i))); } + states.add(getQueryState(sul)); - if (indices.contains(index++)) { - states.add(getQueryState(sul)); - } + for (int i = 0; i < repeat; i++) { + inputBuilder.append(loop); + for (int j = 0; j < loop.length(); j++) { + outputBuilder.append(sul.step(loop.getSymbol(j))); + } + final Q nextState = getQueryState(sul); - // Suffix: Execute symbols, outputs constitute output word - WordBuilder wb = new WordBuilder<>(suffix.length()); - for (I sym : suffix) { - wb.add(sul.step(sym)); - if (indices.contains(index++)) { - states.add(getQueryState(sul)); + int prefixLength = prefix.length(); + for (Q q: states) { + if (isSameState(inputBuilder.toWord(0, prefixLength), q, inputBuilder.toWord(), nextState)) { + return Pair.of(outputBuilder.toWord(), i + 1); + } + prefixLength += loop.length(); } } - return Pair.of(wb.toWord(), states); + return Pair.of(null, -1); } finally { sul.post(); } } @Override - public MealyMembershipOracle getMealyMembershipOracle() { + public MealyMembershipOracle getMembershipOracle() { return new SULOracle<>(sul); } @@ -236,9 +238,8 @@ protected Integer getQueryState(ObservableSUL sul) { */ @Override public boolean isSameState(Word input1, Integer s1, Word input2, Integer s2) { - final boolean result; if (!s1.equals(s2)) { - result = false; + return false; } else { // in this case the hash codes are equal, now we must check if we accidentally had a hash-collision. final ObservableSUL sul1 = getSul(); @@ -261,17 +262,14 @@ public boolean isSameState(Word input1, Integer s1, Word input2, Integer s assert s2.equals(sul2.getState().hashCode()); // check for state equivalence - result = sul1.getState().equals(sul2.getState()); + return sul1.getState().equals(sul2.getState()); } finally { sul2.post(); } - } finally { sul1.post(); } } - - return result; } } diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java index 55dec7bf75..6932bfdb26 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java @@ -18,14 +18,15 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Set; +import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.api.oracle.OmegaMembershipOracle; import de.learnlib.api.oracle.OmegaQueryAnswerer; import de.learnlib.api.oracle.SingleQueryOmegaOracle; import de.learnlib.api.query.OmegaQuery; +import de.learnlib.api.query.Query; import de.learnlib.oracle.membership.SimulatorOracle.DFASimulatorOracle; import de.learnlib.oracle.membership.SimulatorOracle.MealySimulatorOracle; import de.learnlib.util.MQUtil; @@ -35,6 +36,7 @@ import net.automatalib.commons.util.Pair; import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; /** * Answers {@link OmegaQuery}s by simulating an automaton. @@ -46,9 +48,8 @@ * @param the state type. * @param the input type. * @param the output type. - * @param the SimulatorOracle type. */ -public class SimulatorOmegaOracle> +public class SimulatorOmegaOracle implements SingleQueryOmegaOracle { /** @@ -57,18 +58,18 @@ public class SimulatorOmegaOracle> private final SimpleDTS simpleDTS; /** - * @see #getSimulatorOracle() + * @see #getMembershipOracle() */ - private final SO simulatorOracle; + private final SimulatorOracle simulatorOracle; /** * Constructs a new {@link SimulatorOmegaOracle}. * * @param automaton the automaton to simulate. - * @param simulatorOracle the {@link SimulatorOracle} used to answer {@link de.learnlib.api.query.Query}s. + * @param simulatorOracle the {@link SimulatorOracle} used to answer {@link Query}s. * @param the automaton type. */ - public & SimpleDTS> SimulatorOmegaOracle(A automaton, SO simulatorOracle) { + public & SimpleDTS> SimulatorOmegaOracle(A automaton, SimulatorOracle simulatorOracle) { this.simpleDTS = automaton; this.simulatorOracle = simulatorOracle; } @@ -78,7 +79,8 @@ public & SimpleDTS> SimulatorOmegaOracle(A a * * @return the SimulatorOracle. */ - public SO getSimulatorOracle() { + @Override + public MembershipOracle getMembershipOracle() { return simulatorOracle; } @@ -93,7 +95,7 @@ public boolean isSameState(Word input1, S s1, Word input2, S s2) { } @Override - public void processQueries(Collection> queries) { + public void processQueries(Collection> queries) { MQUtil.answerOmegaQueriesAuto(this, queries); } @@ -101,46 +103,80 @@ public void processQueries(Collection> queries) { * Returns an answer for an {@link OmegaQuery}. * * The output is obtained through the {@link SimulatorOracle}, while the states are obtained by means of creating - * several access sequences to states in the simulated automaton. + * two access sequences to states in the simulated automaton. * - * @see OmegaQueryAnswerer#answerQuery(Word, Word, Set) + * @see OmegaQueryAnswerer#answerQuery(Word, Word, int) */ @Override - public Pair> answerQuery(Word prefix, Word suffix, Set indices) { - final List states = new ArrayList<>(); + public Pair answerQuery(Word prefix, Word loop, int repeat) { + assert repeat > 0; + + final List states = new ArrayList<>(repeat + 1); + final WordBuilder wb = new WordBuilder<>(prefix.length() + loop.length() * repeat, prefix); + + S stateIter = simpleDTS.getState(wb); + + if (stateIter == null) { + return Pair.of(null, -1); + } + + states.add(stateIter); - for (int i : indices) { - states.add(simpleDTS.getState(prefix.concat(suffix).prefix(i))); + for (int i = 0; i < repeat; i++) { + final S nextState = simpleDTS.getSuccessor(stateIter, loop); + + if (nextState == null) { + return Pair.of(null, -1); + } + + wb.append(loop); + + int prefixLength = prefix.length(); + for (S s : states) { + if (isSameState(wb.toWord(0, prefixLength), s, wb.toWord(), nextState)) { + return Pair.of(simulatorOracle.answerQuery(wb.toWord()), i + 1); + } + prefixLength += loop.length(); + } + + states.add(nextState); + stateIter = nextState; } - return Pair.of(simulatorOracle.answerQuery(prefix, suffix), states); + return Pair.of(null, -1); } public static class DFASimulatorOmegaOracle - extends SimulatorOmegaOracle> + extends SimulatorOmegaOracle implements DFAOmegaMembershipOracle { + private final DFA automaton; + public DFASimulatorOmegaOracle(DFA automaton) { super(automaton, new DFASimulatorOracle<>(automaton)); + this.automaton = automaton; } @Override - public DFAMembershipOracle getDFAMembershipOracle() { - return getSimulatorOracle(); + public DFAMembershipOracle getMembershipOracle() { + return new DFASimulatorOracle<>(automaton); } } public static class MealySimulatorOmegaOracle - extends SimulatorOmegaOracle, MealySimulatorOracle> + extends SimulatorOmegaOracle> implements MealyOmegaMembershipOracle { + private final MealyMachine automaton; + public MealySimulatorOmegaOracle(MealyMachine automaton) { super(automaton, new MealySimulatorOracle<>(automaton)); + this.automaton = automaton; } @Override - public MealyMembershipOracle getMealyMembershipOracle() { - return getSimulatorOracle(); + public MealyMembershipOracle getMembershipOracle() { + return new MealySimulatorOracle<>(automaton); } } } diff --git a/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java index 2e4b19a2da..96746ba110 100644 --- a/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java +++ b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java @@ -16,8 +16,6 @@ package de.learnlib.oracle.membership; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; import de.learnlib.api.query.OmegaQuery; @@ -44,32 +42,31 @@ public void testDFASimulatorOmegaOracle() { DFASimulatorOmegaOracle oracle = new DFASimulatorOmegaOracle<>(dfa); - List> queries = new ArrayList<>(); + List> queries = new ArrayList<>(); - OmegaQuery q1 = new OmegaQuery<>(Word.fromSymbols(ExamplePaulAndMary.IN_PAUL, - ExamplePaulAndMary.IN_LOVES, - ExamplePaulAndMary.IN_MARY), - new HashSet<>(Arrays.asList(0, 1, 2, 3))); - OmegaQuery q2 = new OmegaQuery<>(Word.fromSymbols(ExamplePaulAndMary.IN_MARY, - ExamplePaulAndMary.IN_LOVES, - ExamplePaulAndMary.IN_PAUL), - new HashSet<>(Arrays.asList(0, 1, 2, 3))); + OmegaQuery q1 = new OmegaQuery<>(Word.epsilon(), + Word.fromSymbols(ExamplePaulAndMary.IN_PAUL, + ExamplePaulAndMary.IN_LOVES, + ExamplePaulAndMary.IN_MARY), + 1); + OmegaQuery q2 = new OmegaQuery<>(Word.fromSymbols(ExamplePaulAndMary.IN_MARY), + Word.fromSymbols(ExamplePaulAndMary.IN_MARY, + ExamplePaulAndMary.IN_LOVES, + ExamplePaulAndMary.IN_PAUL), + 1); queries.add(q1); queries.add(q2); - Assert.assertEquals(queries.get(0).getInput().size(), 3); - Assert.assertEquals(queries.get(0).getIndices().size(), 4); - Assert.assertEquals(queries.get(1).getInput().size(), 3); - Assert.assertEquals(queries.get(1).getIndices().size(), 4); + Assert.assertEquals(queries.get(0).getLoop().size(), 3); + Assert.assertEquals(queries.get(1).getLoop().size(), 3); oracle.processQueries(queries); // Paul loves Mary... - Assert.assertEquals(queries.get(0).getOutput(), Boolean.TRUE); - Assert.assertEquals(queries.get(0).getStates(), Arrays.asList(0, 1, 3, 4)); + Assert.assertFalse(queries.get(0).isUltimatelyPeriodic()); // ... but Mary does not love Paul :-( + Assert.assertTrue(queries.get(1).isUltimatelyPeriodic()); Assert.assertEquals(queries.get(1).getOutput(), Boolean.FALSE); - Assert.assertEquals(queries.get(1).getStates(), Arrays.asList(0, 2, 2, 2)); } } diff --git a/oracles/pom.xml b/oracles/pom.xml index 18f0316f39..9a92e14750 100644 --- a/oracles/pom.xml +++ b/oracles/pom.xml @@ -32,10 +32,11 @@ limitations under the License. Parent module for oracles and oracle-related modules - bbc-oracles + emptiness-oracles + equivalence-oracles filters membership-oracles - equivalence-oracles parallelism + property-oracles diff --git a/oracles/property-oracles/pom.xml b/oracles/property-oracles/pom.xml new file mode 100644 index 0000000000..1f4c6e35ae --- /dev/null +++ b/oracles/property-oracles/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + + de.learnlib + learnlib-oracles-parent + 0.14.0-SNAPSHOT + ../pom.xml + + + learnlib-property-oracles + + LearnLib :: Oracles :: Property Oracles + A collection of property oracles + + + + com.google.code.findbugs + jsr305 + + + net.automatalib + automata-api + + + de.learnlib + learnlib-api + + + + org.testng + testng + + + diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java new file mode 100644 index 0000000000..f8b58db8ed --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java @@ -0,0 +1,97 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.property; + +import java.util.Collection; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.PropertyOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; + +/** + * A {@link PropertyOracle} that uses {@link InclusionOracle}s and {@link EmptinessOracle}s to find counter examples + * and disprove properties. + * + * @author Jeroen Meijer + * + * @param the input type + * @param the automaton type + * @param

the property type + * @param the output type + * @param the result type of a model checker + */ +@ParametersAreNonnullByDefault +abstract class AbstractPropertyOracle, P, D, R extends A> + implements PropertyOracle { + + private final InclusionOracle inclusionOracle; + private final EmptinessOracle emptinessOracle; + private P property; + private DefaultQuery counterExample; + + protected AbstractPropertyOracle(P property, + InclusionOracle inclusionOracle, + EmptinessOracle emptinessOracle) { + this.property = property; + this.inclusionOracle = inclusionOracle; + this.emptinessOracle = emptinessOracle; + } + + @Nullable + protected DefaultQuery setCounterExample(@Nullable DefaultQuery counterExample) { + this.counterExample = counterExample; + assert this.counterExample == null || counterExample != null; + return this.counterExample; + } + + @Override + public void setProperty(P property) { + this.property = property; + } + + @Override + public P getProperty() { + return property; + } + + @Nullable + @Override + public DefaultQuery getCounterExample() { + return counterExample; + } + + protected abstract R doFindCounterExample(A hypothesis, Collection inputs); + + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + final A result = doFindCounterExample(hypothesis, inputs); + return result != null ? inclusionOracle.findCounterExample(result, inputs) : null; + } + + @Nullable + @Override + public DefaultQuery disprove(A hypothesis, Collection inputs) { + final R ce = doFindCounterExample(hypothesis, inputs); + + return ce != null ? setCounterExample(emptinessOracle.findCounterExample(ce, inputs)) : null; + } +} diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java new file mode 100644 index 0000000000..01132a2786 --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java @@ -0,0 +1,51 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.property; + +import java.util.Collection; + +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.PropertyOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.modelchecking.ModelChecker; + +/** + * A property oracle for DFAs where it is fine to only check finite words from the model checker. + * + * @author Jeroen Meijer + * + * @param the input type + * @param

the property type + */ +public class DFAFinitePropertyOracle extends AbstractPropertyOracle, P, Boolean, DFA> + implements PropertyOracle.DFAPropertyOracle { + + private final ModelChecker.DFAModelChecker> modelChecker; + + public DFAFinitePropertyOracle(P property, + InclusionOracle.DFAInclusionOracle inclusionOracle, + EmptinessOracle.DFAEmptinessOracle emptinessOracle, + ModelChecker.DFAModelChecker> modelChecker) { + super(property, inclusionOracle, emptinessOracle); + this.modelChecker = modelChecker; + } + + @Override + protected DFA doFindCounterExample(DFA hypothesis, Collection inputs) { + return modelChecker.findCounterExample(hypothesis, inputs, getProperty()); + } +} diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java new file mode 100644 index 0000000000..fa115f0139 --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java @@ -0,0 +1,52 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.property; + +import java.util.Collection; + +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.LassoEmptinessOracle; +import de.learnlib.api.oracle.PropertyOracle; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.ModelCheckerLasso; + +/** + * A property oracle for DFAs that can check lassos from the model checker. + * + * @author Jeroen Meijer + * + * @param the input type + * @param

the property type + */ +public class DFALassoPropertyOracle extends AbstractPropertyOracle, P, Boolean, Lasso.DFALasso> + implements PropertyOracle.DFAPropertyOracle { + + private final ModelCheckerLasso.DFAModelCheckerLasso modelChecker; + + public DFALassoPropertyOracle(P property, + InclusionOracle.DFAInclusionOracle inclusionOracle, + LassoEmptinessOracle.DFALassoEmptinessOracle emptinessOracle, + ModelCheckerLasso.DFAModelCheckerLasso modelChecker) { + super(property, inclusionOracle, emptinessOracle); + this.modelChecker = modelChecker; + } + + @Override + protected Lasso.DFALasso doFindCounterExample(DFA hypothesis, Collection inputs) { + return modelChecker.findCounterExample(hypothesis, inputs, getProperty()); + } +} diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java new file mode 100644 index 0000000000..f4d324bb0c --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java @@ -0,0 +1,56 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.property; + +import java.util.Collection; + +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.PropertyOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.modelchecking.ModelChecker; +import net.automatalib.words.Word; + +/** + * A property oracle for Mealy Machines where it is fine to only check finite words from the model checker. + * + * @author Jeroen Meijer + * + * @param the input type + * @param the output type + * @param

the property type + */ +public class MealyFinitePropertyOracle + extends AbstractPropertyOracle, P, Word, MealyMachine> + implements PropertyOracle.MealyPropertyOracle { + + private final ModelChecker.MealyModelChecker> modelChecker; + + public MealyFinitePropertyOracle(P property, + InclusionOracle.MealyInclusionOracle inclusionOracle, + EmptinessOracle.MealyEmptinessOracle emptinessOracle, + ModelChecker.MealyModelChecker> modelChecker) { + super(property, inclusionOracle, emptinessOracle); + this.modelChecker = modelChecker; + } + + @Override + protected MealyMachine doFindCounterExample(MealyMachine hypothesis, + Collection inputs) { + + return modelChecker.findCounterExample(hypothesis, inputs, getProperty()); + } +} diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java new file mode 100644 index 0000000000..6980eb8266 --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java @@ -0,0 +1,56 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.property; + +import java.util.Collection; + +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.LassoEmptinessOracle; +import de.learnlib.api.oracle.PropertyOracle; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.ModelCheckerLasso; +import net.automatalib.words.Word; + +/** + * A property oracle for Mealy machines that can check lassos from the model checker. + * + * @author Jeroen Meijer + * + * @param the input type + * @param the output type + * @param

the property type + */ +public class MealyLassoPropertyOracle + extends AbstractPropertyOracle, P, Word, Lasso.MealyLasso> + implements PropertyOracle.MealyPropertyOracle { + + private final ModelCheckerLasso.MealyModelCheckerLasso modelChecker; + + public MealyLassoPropertyOracle(P property, + InclusionOracle.MealyInclusionOracle inclusionOracle, + LassoEmptinessOracle.MealyLassoEmptinessOracle emptinessOracle, + ModelCheckerLasso.MealyModelCheckerLasso modelChecker) { + super(property, inclusionOracle, emptinessOracle); + this.modelChecker = modelChecker; + } + + @Override + protected Lasso.MealyLasso doFindCounterExample(MealyMachine hypothesis, + Collection inputs) { + return modelChecker.findCounterExample(hypothesis, inputs, getProperty()); + } +} diff --git a/pom.xml b/pom.xml index c72a1ff163..ff25283dc4 100644 --- a/pom.xml +++ b/pom.xml @@ -226,6 +226,7 @@ limitations under the License. 1.7 1.7.25 6.11 + 2.18.3 http://docs.oracle.com/javase/8/docs/api/ @@ -456,13 +457,6 @@ limitations under the License. ${project.version} - - - de.learnlib - learnlib-model-checkers - ${project.version} - - de.learnlib @@ -472,7 +466,7 @@ limitations under the License. de.learnlib - learnlib-bbc-oracles + learnlib-emptiness-oracles ${project.version} @@ -510,6 +504,11 @@ limitations under the License. learnlib-parallelism ${project.version} + + de.learnlib + learnlib-property-oracles + ${project.version} + @@ -530,6 +529,12 @@ limitations under the License. ${project.version} test + + de.learnlib.testsupport + learnlib-oracle-support + ${project.version} + test + @@ -548,6 +553,14 @@ limitations under the License. test + + + org.mockito + mockito-core + ${mockito.version} + test + + com.google.guava diff --git a/test-support/oracle-support/pom.xml b/test-support/oracle-support/pom.xml new file mode 100644 index 0000000000..12c639fc52 --- /dev/null +++ b/test-support/oracle-support/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + + de.learnlib.testsupport + learnlib-test-support-parent + 0.14.0-SNAPSHOT + ../pom.xml + + + learnlib-oracle-support + jar + + LearnLib :: Test Support :: Oracle Support + Support classes for easily writing integration test cases for oracle algorithms + + + + net.automatalib + automata-api + + + net.automatalib + automata-core + + + de.learnlib + learnlib-util + + + + + org.testng + testng + compile + + + + org.mockito + mockito-core + compile + + + + diff --git a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/AbstractBreadthFirstOracleTest.java b/test-support/oracle-support/src/main/java/de/learnlib/oracle/AbstractBFOracleTest.java similarity index 65% rename from oracles/bbc-oracles/src/test/java/de/learnlib/oracle/AbstractBreadthFirstOracleTest.java rename to test-support/oracle-support/src/main/java/de/learnlib/oracle/AbstractBFOracleTest.java index a2f4e801cd..77d9168f06 100644 --- a/oracles/bbc-oracles/src/test/java/de/learnlib/oracle/AbstractBreadthFirstOracleTest.java +++ b/test-support/oracle-support/src/main/java/de/learnlib/oracle/AbstractBFOracleTest.java @@ -15,40 +15,41 @@ */ package de.learnlib.oracle; -import java.util.NoSuchElementException; - -import de.learnlib.api.query.Query; +import de.learnlib.util.AbstractBFOracle; import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; import org.mockito.MockitoAnnotations; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** - * Class to test any {@link AbstractBreadthFirstOracle}. + * Class to test any {@link AbstractBFOracle}. * * @author Jeroen Meijer */ -public abstract class AbstractBreadthFirstOracleTest { +public abstract class AbstractBFOracleTest { + + public static final Alphabet ALPHABET = Alphabets.singleton('a'); - public static final int MAX_WORDS = 1; + public static final double MULTIPLIER = 2.0; - private AbstractBreadthFirstOracle, Character, D, ? extends Query> - bfo; + private AbstractBFOracle, Character, D> bfo; - protected abstract AbstractBreadthFirstOracle, Character, D, ? extends Query> createBreadthFirstOracle( - int maxWords); + protected abstract AbstractBFOracle, Character, D> createBreadthFirstOracle( + double multiplier); @BeforeMethod public void setUp() { MockitoAnnotations.initMocks(this); - bfo = createBreadthFirstOracle(MAX_WORDS); + bfo = createBreadthFirstOracle(MULTIPLIER); } @Test - public void testGetMaxWords() { - Assert.assertEquals(bfo.getMaxWords(), MAX_WORDS); + public void testGetMultiplier() { + Assert.assertEquals(bfo.getMultiplier(), MULTIPLIER); } /** @@ -59,6 +60,7 @@ public void testNextInput() { bfo.pre(); bfo.addWord(Word.fromLetter('a')); bfo.addWord(Word.fromLetter('b')); + Assert.assertEquals(bfo.nextInput(), Word.epsilon()); Assert.assertEquals(bfo.nextInput(), Word.fromLetter('a')); Assert.assertEquals(bfo.nextInput(), Word.fromLetter('b')); } @@ -70,11 +72,11 @@ public void testAddWord() { Assert.assertEquals(bfo.nextInput(), Word.epsilon()); } - @Test(expectedExceptions = NoSuchElementException.class) + @Test public void testPre() { bfo.pre(); bfo.addWord(Word.epsilon()); bfo.pre(); - bfo.nextInput(); + Assert.assertEquals(bfo.nextInput(), Word.epsilon()); } -} \ No newline at end of file +} diff --git a/test-support/pom.xml b/test-support/pom.xml index e67b283f1a..ded3174450 100644 --- a/test-support/pom.xml +++ b/test-support/pom.xml @@ -35,6 +35,7 @@ limitations under the License. learning-examples learner-it-support + oracle-support From 036d8e974c1d643f0b94940029bf3909ac3810ba Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 25 Sep 2018 16:23:33 +0200 Subject: [PATCH 073/125] adjust to AutomataLib refactorings --- .../de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java | 4 ++-- .../test/java/de/learnlib/mapper/MapperCompositionTest.java | 3 +-- .../learnlib/oracle/equivalence/AbstractTestWordEQOracle.java | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java index d68b6043fb..105901d68e 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java @@ -17,6 +17,7 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import de.learnlib.api.algorithm.feature.ResumableLearner; @@ -26,7 +27,6 @@ import de.learnlib.datastructure.observationtable.Row; import net.automatalib.automata.GrowableAlphabetAutomaton; import net.automatalib.automata.MutableDeterministic; -import net.automatalib.commons.util.collections.CollectionsUtil; import net.automatalib.words.Alphabet; import net.automatalib.words.impl.SymbolHidingAlphabet; @@ -97,7 +97,7 @@ protected void updateInternalHypothesis() { int newStates = numDistinct - oldStates; - stateInfos.addAll(CollectionsUtil.nullList(newStates)); + stateInfos.addAll(Collections.nCopies(newStates, null)); // TODO: Is there a quicker way than iterating over *all* rows? // FIRST PASS: Create new hypothesis states diff --git a/drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java b/drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java index 40f1777c5b..21c1e193bc 100644 --- a/drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java +++ b/drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java @@ -27,14 +27,13 @@ public class MapperCompositionTest { private ToUpperCaseMapper toUpperCaseMapper; - private StringMapper toCharacterMapper; private Mapper mapper; @BeforeClass public void setUp() { toUpperCaseMapper = new ToUpperCaseMapper(); - toCharacterMapper = new StringMapper<>(Alphabets.characters('A', 'z')); + StringMapper toCharacterMapper = new StringMapper<>(Alphabets.characters('A', 'z')); mapper = Mappers.compose(toCharacterMapper, toUpperCaseMapper); } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java index 86cdc24382..fd270d2b44 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java @@ -23,12 +23,12 @@ import javax.annotation.Nullable; import com.google.common.base.Preconditions; +import com.google.common.collect.Iterators; import com.google.common.collect.Streams; import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.concepts.Output; -import net.automatalib.commons.util.collections.BatchingIterator; import net.automatalib.words.Word; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -108,7 +108,7 @@ private Stream> answerQueries(final Stream * FIXME: currently necessary because of a bug in the JDK * see https://bugs.openjdk.java.net/browse/JDK-8075939 */ - return Streams.stream(Streams.stream(new BatchingIterator<>(stream.iterator(), this.batchSize)) + return Streams.stream(Streams.stream(Iterators.partition(stream.iterator(), this.batchSize)) .peek(membershipOracle::processQueries) .flatMap(List::stream) .iterator()); From ba31cd3b9a3e0a769210c10113866f069ce0897c Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 29 Sep 2018 14:36:04 +0200 Subject: [PATCH 074/125] fix some compiler warnings regarding generics --- .../learnlib/algorithms/ttt/base/AbstractTTTLearner.java | 2 +- .../learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java | 9 ++++----- .../java/de/learnlib/examples/bbc/example1/Example.java | 1 + .../java/de/learnlib/examples/bbc/example2/Example.java | 1 + .../java/de/learnlib/examples/bbc/example3/Example.java | 1 + .../oracle/emptiness/AbstractBFEmptinessOracleTest.java | 2 +- .../emptiness/AbstractLassoEmptinessOracleImplTest.java | 2 +- .../learnlib/oracle/equivalence/CExFirstOracleTest.java | 2 +- .../oracle/equivalence/DisproveFirstOracleTest.java | 2 +- 9 files changed, 12 insertions(+), 10 deletions(-) diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java index 718a0c2a02..ac804355e1 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java @@ -443,11 +443,11 @@ private GlobalSplitter findSplitterGlobal() { * * @return a splitter for this block, or {@code null} if no such splitter could be found. */ - @SuppressWarnings("unchecked") private Splitter findSplitter(AbstractBaseDTNode blockRoot) { int alphabetSize = alphabet.size(); Object[] properties = new Object[alphabetSize]; + @SuppressWarnings("unchecked") AbstractBaseDTNode[] lcas = new AbstractBaseDTNode[alphabetSize]; boolean first = true; diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java index 722602b0dd..ff83d5dc57 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java @@ -53,10 +53,9 @@ public boolean refineHypothesis(DefaultQuery ceQuery) { } @Override - @SuppressWarnings("unchecked") protected boolean refineHypothesisSingle(DefaultQuery ceQuery) { - if (((TTTHypothesisDFA) hypothesis).computeSuffixOutput(ceQuery.getPrefix(), ceQuery.getSuffix()) - .equals(ceQuery.getOutput())) { + if (getHypothesisModel().computeSuffixOutput(ceQuery.getPrefix(), ceQuery.getSuffix()) + .equals(ceQuery.getOutput())) { return false; } @@ -75,8 +74,8 @@ protected boolean refineHypothesisSingle(DefaultQuery ceQuery) { ExtDTNode succHyp = acex.getHypNode(breakpoint + 1); boolean hypOut = lca.subtreeLabel(succHyp); openTransitions.insertAllIncoming(toSplit.getIncoming()); - ExtDTNode.SplitResult splitResult = toSplit.split(newDiscr, hypOut, !hypOut); - link((ExtDTNode) splitResult.nodeOld, splitState); + ExtDTNode.SplitResult splitResult = toSplit.split(newDiscr, hypOut, !hypOut); + link(splitResult.nodeOld, splitState); ExtDTNode extUnlabeled = (ExtDTNode) splitResult.nodeNew; extUnlabeled.tempPrefix = currReachInconsLength; unlabeledList.addUnlabeled(extUnlabeled); diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java index 1a6b5a8fdd..e9df2d7b4e 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java @@ -93,6 +93,7 @@ public static void main(String[] args) { // create an equivalence oracle, that first searches for a counter example using the ltl properties, and next // with the W-method. + @SuppressWarnings("unchecked") DFAEquivalenceOracle eqOracle = new EQOracleChain.DFAEQOracleChain<>( new CExFirstOracle.DFACExFirstOracle<>(ltl), new DFAWpMethodEQOracle<>(mqOracle, 3)); diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java index 29d96c8d86..31c3ae0281 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java @@ -98,6 +98,7 @@ public static void main(String[] args) { // create an equivalence oracle, that first searches for a counter example using the ltl properties, and next // with the W-method. + @SuppressWarnings("unchecked") MealyEquivalenceOracle eqOracle = new EQOracleChain.MealyEQOracleChain<>( new CExFirstOracle.MealyCExFirstOracle<>(ltl), new MealyWpMethodEQOracle<>(mqOracle, 3)); diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java index 3f9a2c5198..af38b10be0 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java @@ -95,6 +95,7 @@ public static void main(String[] args) { // create an equivalence oracle, that first searches for a counter example using the ltl properties, and next // with the W-method. + @SuppressWarnings("unchecked") MealyEquivalenceOracle eqOracle = new EQOracleChain.MealyEQOracleChain<>( new CExFirstOracle.MealyCExFirstOracle<>(ltl), new MealyWpMethodEQOracle<>(mqOracle, 3)); diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java index 61c9bd3644..12b1fbed0c 100644 --- a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java @@ -59,7 +59,7 @@ protected AbstractBFOracle, Character, D> crea @Test public void testFindCounterExample() { - final DefaultQuery cex = bfeo.findCounterExample(automaton, ALPHABET); + final DefaultQuery cex = bfeo.findCounterExample(automaton, ALPHABET); Assert.assertEquals(cex, query); } diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java index 87ce61f58f..269561ce42 100644 --- a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java @@ -101,7 +101,7 @@ protected AbstractBFOracle, Character, D> crea @Test public void testFindCounterExample() { - final DefaultQuery cex = leo.findCounterExample(automaton, ALPHABET); + final DefaultQuery cex = leo.findCounterExample(automaton, ALPHABET); Assert.assertEquals(cex, query); } diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java index 3fd0833e79..c6411fb4fd 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java @@ -75,7 +75,7 @@ public void testGetPropertyOracles() throws Exception { */ @Test public void testFindCounterExample() throws Exception { - final DefaultQuery ce = oracle.findCounterExample(automaton, inputs); + final DefaultQuery ce = oracle.findCounterExample(automaton, inputs); Assert.assertEquals(ce, query); diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java index 7f1eed1f6e..692b7fbb2b 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java @@ -75,7 +75,7 @@ public void testGetPropertyOracles() throws Exception { */ @Test public void testFindCounterExample() throws Exception { - final DefaultQuery ce = oracle.findCounterExample(automaton, inputs); + final DefaultQuery ce = oracle.findCounterExample(automaton, inputs); Assert.assertEquals(ce, query); From 27a4884fd4c09a8ae69db5ab34cfe006da2bd890 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 5 Oct 2018 16:36:56 +0200 Subject: [PATCH 075/125] Adding documentation Emphasizing the fact that the abbreviation "PC" of the PC* caches actually stands for 'prefix-closedness' (and not for 'partially connectness', etc.). --- .../filter/cache/dfa/DFACacheOracle.java | 56 +++++++++++++++++++ .../learnlib/filter/cache/dfa/DFACaches.java | 56 ++++++++++++++++++- 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java index b205e4e6ea..9f4237d4d5 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java @@ -62,21 +62,77 @@ public class DFACacheOracle implements DFALearningCacheOracle { this.delegate = delegate; } + /** + * Creates a cache oracle for a DFA learning setup, using a tree for internal cache organization. + * + * @param alphabet + * the alphabet containing the symbols of possible queries + * @param delegate + * the oracle to delegate queries to, in case of a cache-miss. + * @param + * input symbol type + * + * @return the cached {@link DFACacheOracle}. + * + * @see IncrementalDFATreeBuilder + */ public static DFACacheOracle createTreeCacheOracle(Alphabet alphabet, MembershipOracle delegate) { return new DFACacheOracle<>(new IncrementalDFATreeBuilder<>(alphabet), delegate); } + /** + * Creates a prefix-closed cache oracle for a DFA learning setup, using a tree for internal cache organization. + * + * @param alphabet + * the alphabet containing the symbols of possible queries + * @param delegate + * the oracle to delegate queries to, in case of a cache-miss. + * @param + * input symbol type + * + * @return the cached {@link DFACacheOracle}. + * + * @see IncrementalPCDFATreeBuilder + */ public static DFACacheOracle createTreePCCacheOracle(Alphabet alphabet, MembershipOracle delegate) { return new DFACacheOracle<>(new IncrementalPCDFATreeBuilder<>(alphabet), delegate); } + /** + * Creates a cache oracle for a DFA learning setup, using a DAG for internal cache organization. + * + * @param alphabet + * the alphabet containing the symbols of possible queries + * @param delegate + * the oracle to delegate queries to, in case of a cache-miss. + * @param + * input symbol type + * + * @return the cached {@link DFACacheOracle}. + * + * @see IncrementalDFADAGBuilder + */ public static DFACacheOracle createDAGCacheOracle(Alphabet alphabet, MembershipOracle delegate) { return new DFACacheOracle<>(new IncrementalDFADAGBuilder<>(alphabet), delegate); } + /** + * Creates a prefix-closed cache oracle for a DFA learning setup, using a DAG for internal cache organization. + * + * @param alphabet + * the alphabet containing the symbols of possible queries + * @param delegate + * the oracle to delegate queries to, in case of a cache-miss. + * @param + * input symbol type + * + * @return the cached {@link DFACacheOracle}. + * + * @see IncrementalPCDFADAGBuilder + */ public static DFACacheOracle createDAGPCCacheOracle(Alphabet alphabet, MembershipOracle delegate) { return new DFACacheOracle<>(new IncrementalPCDFADAGBuilder<>(alphabet), delegate); diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACaches.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACaches.java index 6f12bea5a2..1ce730a185 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACaches.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACaches.java @@ -20,6 +20,10 @@ import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.filter.cache.LearningCacheOracle.DFALearningCacheOracle; import net.automatalib.incremental.dfa.IncrementalDFABuilder; +import net.automatalib.incremental.dfa.dag.IncrementalDFADAGBuilder; +import net.automatalib.incremental.dfa.dag.IncrementalPCDFADAGBuilder; +import net.automatalib.incremental.dfa.tree.IncrementalDFATreeBuilder; +import net.automatalib.incremental.dfa.tree.IncrementalPCDFATreeBuilder; import net.automatalib.words.Alphabet; @ParametersAreNonnullByDefault @@ -29,14 +33,56 @@ private DFACaches() { throw new IllegalStateException("Constructor should never be invoked"); } + /** + * Creates a prefix-closed cache oracle for a DFA learning setup, using a DAG for internal cache organization. + * + * @param alphabet + * the alphabet containing the symbols of possible queries + * @param mqOracle + * the oracle to delegate queries to, in case of a cache-miss. + * @param + * input symbol type + * + * @return the cached {@link DFACacheOracle}. + * + * @see IncrementalPCDFADAGBuilder + */ public static DFACacheOracle createDAGPCCache(Alphabet alphabet, MembershipOracle mqOracle) { return DFACacheOracle.createDAGPCCacheOracle(alphabet, mqOracle); } + /** + * Creates a cache oracle for a DFA learning setup, using a tree for internal cache organization. + * + * @param alphabet + * the alphabet containing the symbols of possible queries + * @param mqOracle + * the oracle to delegate queries to, in case of a cache-miss. + * @param + * input symbol type + * + * @return the cached {@link DFACacheOracle}. + * + * @see IncrementalDFATreeBuilder + */ public static DFACacheOracle createTreeCache(Alphabet alphabet, MembershipOracle mqOracle) { return DFACacheOracle.createTreeCacheOracle(alphabet, mqOracle); } + /** + * Creates a prefix-closed cache oracle for a DFA learning setup, using a tree for internal cache organization. + * + * @param alphabet + * the alphabet containing the symbols of possible queries + * @param mqOracle + * the oracle to delegate queries to, in case of a cache-miss. + * @param + * input symbol type + * + * @return the cached {@link DFACacheOracle}. + * + * @see IncrementalPCDFATreeBuilder + */ public static DFACacheOracle createTreePCCache(Alphabet alphabet, MembershipOracle mqOracle) { return DFACacheOracle.createTreePCCacheOracle(alphabet, mqOracle); } @@ -66,11 +112,15 @@ public static DFACacheOracle createCache(Alphabet alphabet, Membership * Creates a cache oracle for a DFA learning setup, using a DAG for internal cache organization. * * @param alphabet - * the input alphabet + * the alphabet containing the symbols of possible queries * @param mqOracle - * the membership oracle + * the oracle to delegate queries to, in case of a cache-miss. + * @param + * input symbol type * - * @return a Mealy learning cache with a default implementation + * @return the cached {@link DFACacheOracle}. + * + * @see IncrementalDFADAGBuilder */ public static DFACacheOracle createDAGCache(Alphabet alphabet, MembershipOracle mqOracle) { return DFACacheOracle.createDAGCacheOracle(alphabet, mqOracle); From 42c058ab012d9e1deecd8d91be149f7f799e1a39 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 6 Oct 2018 15:29:02 +0200 Subject: [PATCH 076/125] adjust to refactorings of AutomataLib --- .../java/de/learnlib/algorithms/adt/util/ADTUtil.java | 4 ++-- .../de/learnlib/algorithms/rpni/BlueFringeEDSMDFA.java | 8 ++++---- .../de/learnlib/algorithms/rpni/BlueFringeRPNIMealy.java | 2 +- .../java/de/learnlib/datastructure/pta/pta/BasePTA.java | 4 ++-- .../de/learnlib/datastructure/pta/pta/RedBlueMerge.java | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/util/ADTUtil.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/util/ADTUtil.java index f45f0da4ee..5d30b8036f 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/util/ADTUtil.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/util/ADTUtil.java @@ -148,7 +148,7 @@ public static Pair, Word> buildTraceForNode(final ADTNode(inputBuilder.reverse().toWord(), outputBuilder.reverse().toWord()); + return Pair.of(inputBuilder.reverse().toWord(), outputBuilder.reverse().toWord()); } public static O getOutputForSuccessor(final ADTNode node, final ADTNode successor) { @@ -254,7 +254,7 @@ public static Pair, ADTNode> buildADSFromTra tempInput = nextInput; } - return new Pair<>(head, tempADS); + return Pair.of(head, tempADS); } /** diff --git a/algorithms/passive/rpni-edsm/src/main/java/de/learnlib/algorithms/rpni/BlueFringeEDSMDFA.java b/algorithms/passive/rpni-edsm/src/main/java/de/learnlib/algorithms/rpni/BlueFringeEDSMDFA.java index c32552b598..1b1e89fb28 100644 --- a/algorithms/passive/rpni-edsm/src/main/java/de/learnlib/algorithms/rpni/BlueFringeEDSMDFA.java +++ b/algorithms/passive/rpni-edsm/src/main/java/de/learnlib/algorithms/rpni/BlueFringeEDSMDFA.java @@ -88,10 +88,10 @@ public DFA computeModel() { final Optional>, Long>> result = stream.map(qr -> tryMerge(pta, qr, qb)) .filter(Objects::nonNull) - .map(merge -> new Pair<>(merge, - EDSMUtil.score(merge.toMergedAutomaton(), - super.positive, - super.negative))) + .map(merge -> Pair.of(merge, + EDSMUtil.score(merge.toMergedAutomaton(), + super.positive, + super.negative))) .max(Comparator.comparingLong(Pair::getSecond)); if (result.isPresent()) { diff --git a/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/BlueFringeRPNIMealy.java b/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/BlueFringeRPNIMealy.java index 68d414fc0f..42d38c3e9d 100644 --- a/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/BlueFringeRPNIMealy.java +++ b/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/BlueFringeRPNIMealy.java @@ -50,7 +50,7 @@ public BlueFringeRPNIMealy(Alphabet alphabet) { @Override public void addSamples(Collection>> samples) { for (DefaultQuery> qry : samples) { - this.samples.add(new Pair<>(qry.getInput().toIntArray(alphabet), qry.getOutput())); + this.samples.add(Pair.of(qry.getInput().toIntArray(alphabet), qry.getOutput())); } } diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BasePTA.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BasePTA.java index 2cc4cb713f..0480498642 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BasePTA.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BasePTA.java @@ -217,7 +217,7 @@ public void toAutomaton(MutableDeterministic(root, resultInit)); + queue.add(Pair.of(root, resultInit)); Pair curr; while ((curr = queue.poll()) != null) { @@ -232,7 +232,7 @@ public void toAutomaton(MutableDeterministic(ptaSucc, resultSucc)); + queue.offer(Pair.of(ptaSucc, resultSucc)); } I sym = alphabet.getSymbol(i); TP2 transProp = safeTPExtractor.apply(ptaState.getTransProperty(i)); diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java index b0b0d1312e..178bf4b59c 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java @@ -466,7 +466,7 @@ public TP getTransitionProperty(Pair transition) { @Override public Pair getTransition(S state, Integer input) { - return new Pair<>(state, input); + return Pair.of(state, input); } @Override From 51d7036f7389eeac47a0adb62b1da194b8b26215 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 6 Oct 2018 22:48:37 +0200 Subject: [PATCH 077/125] examples: add tests that run the examples --- build-parent/pom.xml | 3 + distribution/pom.xml | 10 ++ examples/pom.xml | 55 +++++++- .../de/learnlib/examples/ExamplesTest.java | 126 ++++++++++++++++++ pom.xml | 20 ++- 5 files changed, 207 insertions(+), 7 deletions(-) create mode 100644 examples/src/test/java/de/learnlib/examples/ExamplesTest.java diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 147e27eea3..3cc17bba1a 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -43,6 +43,9 @@ limitations under the License. jacoco-maven-plugin + + de/learnlib/examples/*.class + **/ADTLearnerBuilder.class **/MealyDHCBuilder.class diff --git a/distribution/pom.xml b/distribution/pom.xml index d2691c0b92..7f44d6dae5 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -240,6 +240,16 @@ limitations under the License. + + + + de.learnlib + learnlib-examples + ${project.version} + test + true + + bundles diff --git a/examples/pom.xml b/examples/pom.xml index cc1448be60..65480a63b0 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -34,6 +34,11 @@ limitations under the License. deployed for this module. + + + + + + + org.testng + testng + + + net.java.openjdk.cacio + cacio-tta + + + org.jmockit + jmockit + - - org.jacoco - jacoco-maven-plugin + + org.apache.maven.plugins + maven-deploy-plugin true - + org.apache.maven.plugins - maven-deploy-plugin + maven-surefire-plugin - true + + net.java.openjdk.cacio.ctc.CTCToolkit + net.java.openjdk.cacio.ctc.CTCGraphicsEnvironment + false + + + @{argLine} -javaagent:${org.jmockit:jmockit:jar} + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + properties + + + + + diff --git a/examples/src/test/java/de/learnlib/examples/ExamplesTest.java b/examples/src/test/java/de/learnlib/examples/ExamplesTest.java new file mode 100644 index 0000000000..c2d5085001 --- /dev/null +++ b/examples/src/test/java/de/learnlib/examples/ExamplesTest.java @@ -0,0 +1,126 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples; + +import java.awt.AWTEvent; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.function.Function; + +import javax.swing.SwingUtilities; + +import de.learnlib.datastructure.observationtable.OTUtils; +import de.learnlib.datastructure.observationtable.ObservationTable; +import mockit.Mock; +import mockit.MockUp; +import net.automatalib.commons.util.system.JVMUtil; +import net.automatalib.modelcheckers.ltsmin.LTSminUtil; +import net.automatalib.words.Word; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class ExamplesTest { + + @BeforeClass + public void setupAutoClose() { + // As soon as we observe an event that indicates a new window, close it to prevent blocking the tests. + Toolkit.getDefaultToolkit().addAWTEventListener(event -> { + final WindowEvent windowEvent = (WindowEvent) event; + final Window w = windowEvent.getWindow(); + w.dispatchEvent(new WindowEvent(w, WindowEvent.WINDOW_CLOSING)); + }, AWTEvent.WINDOW_FOCUS_EVENT_MASK); + } + + @Test + public void testBBCExample1() { + checkLTSminAvailability(); + de.learnlib.examples.bbc.example1.Example.main(new String[0]); + } + + @Test + public void testBBCExample2() { + checkLTSminAvailability(); + de.learnlib.examples.bbc.example2.Example.main(new String[0]); + } + + @Test + public void testBBCExample3() { + checkLTSminAvailability(); + de.learnlib.examples.bbc.example3.Example.main(new String[0]); + } + + @Test + public void testExample1() throws Exception { + checkJVMCompatibility(); + + // Mock OTUtils class, so we don't actually open a browser during the test + new MockUp() { + + @Mock + public void displayHTMLInBrowser(ObservationTable table, + Function, ? extends String> wordToString, + Function outputToString) { + // do nothing + } + }; + + SwingUtilities.invokeAndWait(() -> { + try { + de.learnlib.examples.example1.Example.main(new String[0]); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + @Test + public void testExample2() throws InvocationTargetException, InterruptedException { + checkJVMCompatibility(); + SwingUtilities.invokeAndWait(() -> { + try { + de.learnlib.examples.example2.Example.main(new String[0]); + } catch (IOException | NoSuchMethodException e) { + throw new RuntimeException(e); + } + }); + } + + @Test + public void testExample3() throws InvocationTargetException, InterruptedException { + checkJVMCompatibility(); + SwingUtilities.invokeAndWait(() -> de.learnlib.examples.example3.Example.main(new String[0])); + } + + private static void checkJVMCompatibility() { + if (JVMUtil.getCanonicalSpecVersion() > 8) { + throw new SkipException("The headless AWT environment currently only works with Java 8 and below"); + } + } + + private static void checkLTSminAvailability() { + if (!LTSminUtil.checkUsable()) { + throw new SkipException("LTSmin is not installed"); + } + } + +} diff --git a/pom.xml b/pom.xml index ff25283dc4..e5f9dee909 100644 --- a/pom.xml +++ b/pom.xml @@ -219,14 +219,16 @@ limitations under the License. 0.8.0-SNAPSHOT 0.1 + 1.9 8.1 3.0.2 24.0-jre + 1.43 1.2.3 1.7 + 2.18.3 1.7.25 6.11 - 2.18.3 http://docs.oracle.com/javase/8/docs/api/ @@ -561,6 +563,22 @@ limitations under the License. test + + + org.jmockit + jmockit + ${jmockit.version} + test + + + + + net.java.openjdk.cacio + cacio-tta + ${cacio.version} + test + + com.google.guava From a775759a448fc7394ddf83393d290906d915002c Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 6 Oct 2018 23:54:43 +0200 Subject: [PATCH 078/125] jacoco: do not ignore examples [skip ci] --- build-parent/pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 3cc17bba1a..147e27eea3 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -43,9 +43,6 @@ limitations under the License. jacoco-maven-plugin - - de/learnlib/examples/*.class - **/ADTLearnerBuilder.class **/MealyDHCBuilder.class From e81112605d4aa24e9ab75029933268cedcf579dd Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 10 Oct 2018 16:27:33 +0200 Subject: [PATCH 079/125] cleanup DiscriminationTree iterators - hide several iterators behind a new DiscriminationTreeIterators factory - add DT tests/documentation --- .../hypothesis/vpda/DTNode.java | 4 +- .../ttt/base/AbstractBaseDTNode.java | 7 +- datastructures/discrimination-tree/pom.xml | 38 ++++++++ .../DiscriminationTreeIterators.java | 86 +++++++++++++++++++ .../iterators/InnerNodesIterator.java | 57 ------------ .../iterators/LeavesIterator.java | 57 ------------ .../{NodesIterator.java => NodeIterator.java} | 4 +- .../iterators/TransformingLeavesIterator.java | 67 --------------- .../model/AbstractDiscriminationTree.java | 17 ++++ .../discriminationtree/DummyDT.java | 63 ++++++++++++++ .../discriminationtree/IteratorsTest.java | 70 +++++++++++++++ .../discriminationtree/LCATest.java | 51 +++++++++++ .../discriminationtree/VisualizationTest.java | 55 ++++++++++++ 13 files changed, 387 insertions(+), 189 deletions(-) create mode 100644 datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/DiscriminationTreeIterators.java delete mode 100644 datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/InnerNodesIterator.java delete mode 100644 datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/LeavesIterator.java rename datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/{NodesIterator.java => NodeIterator.java} (92%) delete mode 100644 datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/TransformingLeavesIterator.java create mode 100644 datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/DummyDT.java create mode 100644 datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/IteratorsTest.java create mode 100644 datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/LCATest.java create mode 100644 datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/VisualizationTest.java diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/DTNode.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/DTNode.java index d6a1620756..112362743c 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/DTNode.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/DTNode.java @@ -18,7 +18,7 @@ import java.util.Iterator; import java.util.Map; -import de.learnlib.datastructure.discriminationtree.iterators.TransformingLeavesIterator; +import de.learnlib.datastructure.discriminationtree.iterators.DiscriminationTreeIterators; import de.learnlib.datastructure.discriminationtree.model.AbstractTemporaryIntrusiveDTNode; import de.learnlib.datastructure.discriminationtree.model.BooleanMap; import de.learnlib.datastructure.list.IntrusiveListElem; @@ -60,7 +60,7 @@ public void split(ContextPair discriminator, Map> children } public Iterator> subtreeLocsIterator() { - return new TransformingLeavesIterator<>(this, DTNode::getData); + return DiscriminationTreeIterators.transformingLeafIterator(this, DTNode::getData); } public Iterable> subtreeLocations() { diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java index ff11a19b79..610da63512 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java @@ -17,8 +17,7 @@ import java.util.Iterator; -import de.learnlib.datastructure.discriminationtree.iterators.NodesIterator; -import de.learnlib.datastructure.discriminationtree.iterators.TransformingLeavesIterator; +import de.learnlib.datastructure.discriminationtree.iterators.DiscriminationTreeIterators; import de.learnlib.datastructure.discriminationtree.model.AbstractTemporaryIntrusiveDTNode; import de.learnlib.datastructure.list.IntrusiveListElem; import net.automatalib.words.Word; @@ -56,7 +55,7 @@ public Iterable> subtreeStates() { } public Iterator> subtreeStatesIterator() { - return new TransformingLeavesIterator<>(this, AbstractBaseDTNode::getData); + return DiscriminationTreeIterators.transformingLeafIterator(this, AbstractBaseDTNode::getData); } public IncomingList getIncoming() { @@ -64,7 +63,7 @@ public IncomingList getIncoming() { } public Iterator> subtreeNodesIterator() { - return new NodesIterator<>(this); + return DiscriminationTreeIterators.nodeIterator(this); } /** diff --git a/datastructures/discrimination-tree/pom.xml b/datastructures/discrimination-tree/pom.xml index a85340eb63..40e0a6ddc0 100644 --- a/datastructures/discrimination-tree/pom.xml +++ b/datastructures/discrimination-tree/pom.xml @@ -44,6 +44,14 @@ limitations under the License. net.automatalib automata-api + + net.automatalib + automata-core + + + net.automatalib + automata-commons-util + net.automatalib automata-util @@ -53,5 +61,35 @@ limitations under the License. com.google.guava guava + + + org.testng + testng + + + net.java.openjdk.cacio + cacio-tta + + + net.automatalib + automata-jung-visualizer + test + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + net.java.openjdk.cacio.ctc.CTCToolkit + net.java.openjdk.cacio.ctc.CTCGraphicsEnvironment + false + + + + + diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/DiscriminationTreeIterators.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/DiscriminationTreeIterators.java new file mode 100644 index 0000000000..d8e0db284a --- /dev/null +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/DiscriminationTreeIterators.java @@ -0,0 +1,86 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.discriminationtree.iterators; + +import java.util.Iterator; +import java.util.function.Function; + +import com.google.common.collect.Iterators; +import de.learnlib.datastructure.discriminationtree.model.AbstractDTNode; + +/** + * Factory methods for several kinds of discrimination tree node iterators. + * + * @author frohme + */ +public final class DiscriminationTreeIterators { + + private DiscriminationTreeIterators() { + // prevent instantiation + } + + /** + * Iterator that traverses all nodes of a subtree of a given discrimination tree node. + * + * @param root + * the root node, from which traversal should start + * @param + * node type + */ + public static > Iterator nodeIterator(N root) { + return new NodeIterator<>(root); + } + + /** + * Iterator that traverses all inner nodes (no leaves) of a subtree of a given discrimination tree node. + * + * @param root + * the root node, from which traversal should start + * @param + * node type + */ + public static > Iterator innerNodeIterator(N root) { + return Iterators.filter(nodeIterator(root), n -> !n.isLeaf()); + } + + /** + * Iterator that traverses all leaves (no inner nodes) of a subtree of a given discrimination tree node. + * + * @param root + * the root node, from which traversal should start + * @param + * node type + */ + public static > Iterator leafIterator(N root) { + return Iterators.filter(nodeIterator(root), AbstractDTNode::isLeaf); + } + + /** + * Iterator that traverses all leaves (no inner nodes) of a subtree of a given discrimination tree node. + * Additionally allows to specify a transformer that is applied to the leaf nodes + * + * @param root + * the root node, from which traversal should start + * @param transformer + * the transformer that transforms iterated nodes + * @param + * node type + */ + public static , D> Iterator transformingLeafIterator(N root, + Function transformer) { + return Iterators.transform(leafIterator(root), transformer::apply); + } +} diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/InnerNodesIterator.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/InnerNodesIterator.java deleted file mode 100644 index 6fdb9b3b40..0000000000 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/InnerNodesIterator.java +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.datastructure.discriminationtree.iterators; - -import java.util.ArrayDeque; -import java.util.Deque; - -import com.google.common.collect.AbstractIterator; -import de.learnlib.datastructure.discriminationtree.model.AbstractDTNode; - -/** - * Iterator that traverses all inner nodes (no leaves) of a subtree of a given discrimination tree node. - * - * @param - * node type - * - * @author Malte Isberner - * @author frohme - */ -public class InnerNodesIterator> extends AbstractIterator { - - private final Deque stack = new ArrayDeque<>(); - - public InnerNodesIterator(N root) { - if (!root.isLeaf()) { - stack.push(root); - } - } - - @Override - protected N computeNext() { - while (!stack.isEmpty()) { - N curr = stack.pop(); - - if (!curr.isLeaf()) { - for (N child : curr.getChildren()) { - stack.push(child); - } - return curr; - } - } - return endOfData(); - } -} diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/LeavesIterator.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/LeavesIterator.java deleted file mode 100644 index 6124ca1f9a..0000000000 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/LeavesIterator.java +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.datastructure.discriminationtree.iterators; - -import java.util.ArrayDeque; -import java.util.Deque; - -import com.google.common.collect.AbstractIterator; -import de.learnlib.datastructure.discriminationtree.model.AbstractDTNode; - -/** - * Iterator that traverses all leaves (no inner nodes) of a subtree of a given discrimination tree node. - * - * @param - * node type - * - * @author Malte Isberner - * @author frohme - */ -public class LeavesIterator> extends AbstractIterator { - - private final Deque stack = new ArrayDeque<>(); - - public LeavesIterator(N root) { - stack.push(root); - } - - @Override - protected N computeNext() { - while (!stack.isEmpty()) { - N curr = stack.pop(); - - if (curr.isLeaf()) { - return curr; - } else { - for (N child : curr.getChildren()) { - stack.push(child); - } - } - } - - return endOfData(); - } -} diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/NodesIterator.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/NodeIterator.java similarity index 92% rename from datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/NodesIterator.java rename to datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/NodeIterator.java index 0a926c340e..0eb97d4edd 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/NodesIterator.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/NodeIterator.java @@ -30,11 +30,11 @@ * @author Malte Isberner * @author frohme */ -public class NodesIterator> extends AbstractIterator { +class NodeIterator> extends AbstractIterator { private final Deque stack = new ArrayDeque<>(); - public NodesIterator(N root) { + NodeIterator(N root) { stack.push(root); } diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/TransformingLeavesIterator.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/TransformingLeavesIterator.java deleted file mode 100644 index d66b65d284..0000000000 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/TransformingLeavesIterator.java +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (C) 2013-2018 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.datastructure.discriminationtree.iterators; - -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.function.Function; - -import com.google.common.collect.AbstractIterator; -import de.learnlib.datastructure.discriminationtree.model.AbstractDTNode; - -/** - * Iterator that traverses all leaves (no inner nodes) of a subtree of a given discrimination tree node. Additionally - * allows to specify a transformer that is applied to the leaf nodes. If the transformer yields {@code null} for an - * iterated leaf, the transformed value will be skipped. - * - * @param - * node type - * @param - * type of transformation result - * - * @author MalteIsberner - * @author frohme - */ -public class TransformingLeavesIterator, D> extends AbstractIterator { - - private final Deque stack = new ArrayDeque<>(); - private final Function extractor; - - public TransformingLeavesIterator(N root, Function extractor) { - stack.push(root); - this.extractor = extractor; - } - - @Override - protected D computeNext() { - while (!stack.isEmpty()) { - N curr = stack.pop(); - - if (curr.isLeaf()) { - final D value = this.extractor.apply(curr); - if (value != null) { - return value; - } - } else { - for (N child : curr.getChildren()) { - stack.push(child); - } - } - } - - return endOfData(); - } -} diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDiscriminationTree.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDiscriminationTree.java index a29974880c..a355a3b2be 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDiscriminationTree.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDiscriminationTree.java @@ -91,6 +91,23 @@ public N leastCommonAncestor(N a, N b) { return lower; } + /** + * Fetches for two nodes information about their lowest common ancestor in {@code this} discrimination tree. {@link + * LCAInfo#subtree1Label} will reference the label of the outgoing child transition for the node closer to the LCA, + * {@link LCAInfo#subtree2Label} the label of the outgoing child transition for the node farther away from the LCA. + * If both nodes have equal depth, {@link LCAInfo#subtree1Label} contains {@code node1}'s label and {@link + * LCAInfo#subtree2Label} {@code node2}'s label. + *

+ * Either {@link LCAInfo#subtree1Label} or {@link LCAInfo#subtree2Label} is {@code null}, if {@code node1} ({@code + * node2} respectively) already is the LCA. + * + * @param node1 + * first node + * @param node2 + * second node + * + * @return the corresponding {@link LCAInfo}. + */ public LCAInfo lcaInfo(N node1, N node2) { int d1 = node1.depth; int d2 = node2.depth; diff --git a/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/DummyDT.java b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/DummyDT.java new file mode 100644 index 0000000000..5dfccec872 --- /dev/null +++ b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/DummyDT.java @@ -0,0 +1,63 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.discriminationtree; + +import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +final class DummyDT { + + static final BinaryDTree DT; + static final AbstractWordBasedDTNode INNER_1, INNER_2, LEAF_1, LEAF_2, LEAF_3; + + static { + /* + Construct the following DT: + 1 + (false) / \ (true) + a 2 + (false) / \ (true) + b c + */ + + DT = new BinaryDTree<>(null); + + INNER_1 = DT.getRoot(); + + AbstractWordBasedDTNode.SplitResult sr1 = + INNER_1.split(Word.fromLetter(1), false, true); + + LEAF_1 = sr1.nodeOld; + INNER_2 = sr1.nodeNew; + + LEAF_1.setData('a'); + AbstractWordBasedDTNode.SplitResult sr2 = + INNER_2.split(Word.fromLetter(2), false, true); + + LEAF_2 = sr2.nodeOld; + LEAF_3 = sr2.nodeNew; + + LEAF_2.setData('b'); + LEAF_3.setData('c'); + } + + private DummyDT() { + throw new AssertionError("Should not be instantiated"); + } +} diff --git a/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/IteratorsTest.java b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/IteratorsTest.java new file mode 100644 index 0000000000..41f3086592 --- /dev/null +++ b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/IteratorsTest.java @@ -0,0 +1,70 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.discriminationtree; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.google.common.collect.Sets; +import de.learnlib.datastructure.discriminationtree.iterators.DiscriminationTreeIterators; +import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class IteratorsTest { + + @Test + public void testNodeIterator() { + final Set> nodes = + Sets.newHashSet(DiscriminationTreeIterators.nodeIterator(DummyDT.DT.getRoot())); + + Assert.assertEquals(nodes, + new HashSet<>(Arrays.asList(DummyDT.INNER_1, + DummyDT.INNER_2, + DummyDT.LEAF_1, + DummyDT.LEAF_2, + DummyDT.LEAF_3))); + } + + @Test + public void testLeafIterator() { + final Set> nodes = + Sets.newHashSet(DiscriminationTreeIterators.leafIterator(DummyDT.DT.getRoot())); + + Assert.assertEquals(nodes, new HashSet<>(Arrays.asList(DummyDT.LEAF_1, DummyDT.LEAF_2, DummyDT.LEAF_3))); + } + + @Test + public void testInnerNodeIterator() { + final Set> nodes = + Sets.newHashSet(DiscriminationTreeIterators.innerNodeIterator(DummyDT.DT.getRoot())); + + Assert.assertEquals(nodes, new HashSet<>(Arrays.asList(DummyDT.INNER_1, DummyDT.INNER_2))); + } + + @Test + public void testTransformingLeafIterator() { + final Set nodes = + Sets.newHashSet(DiscriminationTreeIterators.transformingLeafIterator(DummyDT.DT.getRoot(), + n -> String.valueOf(n.getData()))); + + Assert.assertEquals(nodes, Sets.newHashSet("a", "b", "c")); + } +} diff --git a/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/LCATest.java b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/LCATest.java new file mode 100644 index 0000000000..32a543a72d --- /dev/null +++ b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/LCATest.java @@ -0,0 +1,51 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.discriminationtree; + +import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; +import de.learnlib.datastructure.discriminationtree.model.LCAInfo; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class LCATest { + + @Test + public void testLCA() { + final LCAInfo> lcaInfo = + DummyDT.DT.lcaInfo(DummyDT.LEAF_2, DummyDT.LEAF_3); + + Assert.assertEquals(lcaInfo.leastCommonAncestor, DummyDT.INNER_2); + Assert.assertFalse(lcaInfo.subtree1Label); + Assert.assertTrue(lcaInfo.subtree2Label); + + final LCAInfo> lcaInfo2 = + DummyDT.DT.lcaInfo(DummyDT.LEAF_3, DummyDT.LEAF_1); + + Assert.assertEquals(lcaInfo2.leastCommonAncestor, DummyDT.DT.getRoot()); + Assert.assertTrue(lcaInfo2.subtree1Label); + Assert.assertFalse(lcaInfo2.subtree2Label); + + final LCAInfo> lcaInfo3 = + DummyDT.DT.lcaInfo(DummyDT.INNER_2, DummyDT.INNER_2); + + Assert.assertEquals(lcaInfo3.leastCommonAncestor, DummyDT.INNER_2); + Assert.assertNull(lcaInfo3.subtree1Label); + Assert.assertNull(lcaInfo3.subtree2Label); + } +} diff --git a/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/VisualizationTest.java b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/VisualizationTest.java new file mode 100644 index 0000000000..802dd86210 --- /dev/null +++ b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/VisualizationTest.java @@ -0,0 +1,55 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.discriminationtree; + +import java.awt.AWTEvent; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.SwingUtilities; + +import net.automatalib.commons.util.system.JVMUtil; +import net.automatalib.visualization.Visualization; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class VisualizationTest { + + @BeforeClass + public void setupAutoClose() { + // As soon as we observe an event that indicates a new window, close it to prevent blocking the tests. + Toolkit.getDefaultToolkit().addAWTEventListener(event -> { + final WindowEvent windowEvent = (WindowEvent) event; + final Window w = windowEvent.getWindow(); + w.dispatchEvent(new WindowEvent(w, WindowEvent.WINDOW_CLOSING)); + }, AWTEvent.WINDOW_FOCUS_EVENT_MASK); + } + + @Test + public void testVisualization() throws InvocationTargetException, InterruptedException { + if (JVMUtil.getCanonicalSpecVersion() > 8) { + throw new SkipException("The headless AWT environment currently only works with Java 8 and below"); + } + + SwingUtilities.invokeAndWait(() -> Visualization.visualize(DummyDT.DT)); + } +} From bf240747c1b8272e42ffeefc9e639a44e9feb0d9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 11 Oct 2018 12:33:47 +0200 Subject: [PATCH 080/125] Adjust to AutomataLib changes --- .../discriminationtree/hypothesis/HState.java | 15 ++++++--------- .../de/learnlib/algorithms/ttt/base/TTTState.java | 14 ++++++-------- .../datastructure/observationtable/RowImpl.java | 13 ++++++------- 3 files changed, 18 insertions(+), 24 deletions(-) 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..f3bc771779 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 @@ -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.util.array.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> transitions; private final List> nonTreeIncoming = new ArrayList<>(); private AbstractWordBasedDTNode> dtLeaf; private SP property; @@ -41,12 +41,11 @@ public HState(int alphabetSize) { this(alphabetSize, 0, null); } - @SuppressWarnings("unchecked") public HState(int initialAlphabetSize, int id, HTransition treeIncoming) { this.id = id; this.treeIncoming = treeIncoming; this.depth = (treeIncoming == null) ? 0 : treeIncoming.getSource().depth + 1; - this.transitions = new ResizingObjectArray(initialAlphabetSize); + this.transitions = new ResizingArrayStorage<>(HTransition.class, initialAlphabetSize); } public AbstractWordBasedDTNode> getDTLeaf() { @@ -90,18 +89,16 @@ public int getId() { return id; } - @SuppressWarnings("unchecked") public HTransition getTransition(int transIdx) { - return (HTransition) transitions.array[transIdx]; + return transitions.array[transIdx]; } public void setTransition(int transIdx, HTransition transition) { transitions.array[transIdx] = transition; } - @SuppressWarnings("unchecked") public Collection> getOutgoingTransitions() { - return Collections.unmodifiableList(Arrays.asList((HTransition[]) transitions.array)); + return Collections.unmodifiableList(Arrays.asList(transitions.array)); } public int getDepth() { @@ -118,7 +115,7 @@ public void fetchNonTreeIncoming(Collection> t } /** - * See {@link ResizingObjectArray#ensureCapacity(int)}. + * See {@link ResizingArrayStorage#ensureCapacity(int)}. */ public boolean ensureInputCapacity(int capacity) { return this.transitions.ensureCapacity(capacity); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java index 6295f9d4b1..d612586ffd 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java @@ -18,7 +18,7 @@ import java.io.Serializable; import de.learnlib.api.AccessSequenceProvider; -import net.automatalib.commons.util.array.ResizingObjectArray; +import net.automatalib.commons.util.array.ResizingArrayStorage; import net.automatalib.words.Word; /** @@ -33,7 +33,7 @@ public class TTTState implements AccessSequenceProvider, Serializable { final int id; - private final ResizingObjectArray transitions; + private final ResizingArrayStorage> transitions; private final TTTTransition parentTransition; AbstractBaseDTNode dtLeaf; @@ -41,7 +41,7 @@ public class TTTState implements AccessSequenceProvider, Serializable { public TTTState(int initialAlphabetSize, TTTTransition parentTransition, int id) { this.id = id; this.parentTransition = parentTransition; - this.transitions = new ResizingObjectArray(initialAlphabetSize); + this.transitions = new ResizingArrayStorage<>(TTTTransition.class, initialAlphabetSize); } /** @@ -83,18 +83,16 @@ public void setTransition(final int idx, final TTTTransition transition) { transitions.array[idx] = transition; } - @SuppressWarnings("unchecked") public TTTTransition getTransition(final int idx) { - return (TTTTransition) transitions.array[idx]; + return transitions.array[idx]; } - @SuppressWarnings("unchecked") public TTTTransition[] getTransitions() { - return (TTTTransition[]) transitions.array; + return transitions.array; } /** - * See {@link ResizingObjectArray#ensureCapacity(int)}. + * See {@link ResizingArrayStorage#ensureCapacity(int)}. */ public boolean ensureInputCapacity(int capacity) { return this.transitions.ensureCapacity(capacity); diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/RowImpl.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/RowImpl.java index 02636f57e9..b60406af09 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/RowImpl.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/RowImpl.java @@ -17,7 +17,7 @@ import java.io.Serializable; -import net.automatalib.commons.util.array.ResizingObjectArray; +import net.automatalib.commons.util.array.ResizingArrayStorage; import net.automatalib.words.Word; final class RowImpl implements Row, Serializable { @@ -27,7 +27,7 @@ final class RowImpl implements Row, Serializable { private int rowContentId = -1; private int lpIndex; - private ResizingObjectArray successors; + private ResizingArrayStorage> successors; /** * Constructor for short label rows. @@ -70,13 +70,12 @@ void makeShort(int initialAlphabetSize) { return; } lpIndex = -1; - this.successors = new ResizingObjectArray(initialAlphabetSize); + this.successors = new ResizingArrayStorage<>(RowImpl.class, initialAlphabetSize); } @Override - @SuppressWarnings("unchecked") public RowImpl getSuccessor(int inputIdx) { - return (RowImpl) successors.array[inputIdx]; + return successors.array[inputIdx]; } /** @@ -88,7 +87,7 @@ public RowImpl getSuccessor(int inputIdx) { * @param succ * the successor row */ - void setSuccessor(int inputIdx, Row succ) { + void setSuccessor(int inputIdx, RowImpl succ) { successors.array[inputIdx] = succ; } @@ -135,7 +134,7 @@ void setLpIndex(int lpIndex) { } /** - * See {@link ResizingObjectArray#ensureCapacity(int)}. + * See {@link ResizingArrayStorage#ensureCapacity(int)}. */ boolean ensureInputCapacity(int capacity) { return this.successors.ensureCapacity(capacity); From 0ee1f71a6995bfe58a63ec27b337f967ad365aeb Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 11 Oct 2018 13:00:46 +0200 Subject: [PATCH 081/125] more precise SuppressWarnings declaration --- .../src/main/java/de/learnlib/examples/mealy/ExampleGrid.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleGrid.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleGrid.java index 9f0f990ec4..841aaa4dee 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleGrid.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleGrid.java @@ -47,12 +47,12 @@ public static CompactMealy constructMachine(int xsize, int y * * @return a Mealy machine with (xsize * ysize) states */ - @SuppressWarnings("unchecked") public static > A constructMachine(A fm, int xsize, int ysize) { // create 2D grid of states + @SuppressWarnings("unchecked") S[][] stategrid = (S[][]) new Object[xsize][ysize]; for (int x = 0; x < xsize; ++x) { for (int y = 0; y < ysize; ++y) { From 377422a889cecb476518285336201c9726e19118 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 16 Oct 2018 14:59:01 +0200 Subject: [PATCH 082/125] adjust to refactorings in AutomataLib --- .../hypothesis/vpda/HypLoc.java | 19 ++-- .../ttt/dfa/PrefixTTTLearnerDFA.java | 10 +- .../acex/impl/AbstractBaseCounterexample.java | 10 +- .../pta/pta/AbstractBasePTAState.java | 20 ++-- .../datastructure/pta/pta/RedBlueMerge.java | 91 +++++++++---------- .../filter/cache/mealy/MealyCacheOracle.java | 5 +- 6 files changed, 75 insertions(+), 80 deletions(-) diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java index 6b11784e06..d389591cfc 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java @@ -18,10 +18,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.function.Supplier; import de.learnlib.api.AccessSequenceProvider; -import net.automatalib.commons.util.array.RichArray; +import net.automatalib.commons.util.array.ArrayStorage; import net.automatalib.words.VPDAlphabet; import net.automatalib.words.Word; @@ -35,8 +34,8 @@ public class HypLoc implements AccessSequenceProvider { private final AbstractHypTrans treeIncoming; private final Word aseq; - private final RichArray> intSuccessors; - private final RichArray>> returnSuccessors; + private final ArrayStorage> intSuccessors; + private final ArrayStorage>> returnSuccessors; final int index; private boolean accepting; private DTNode leaf; @@ -44,9 +43,8 @@ public class HypLoc implements AccessSequenceProvider { public HypLoc(VPDAlphabet alphabet, int index, boolean accepting, AbstractHypTrans treeIncoming) { this.index = index; this.accepting = accepting; - this.intSuccessors = new RichArray<>(alphabet.getNumInternals()); - this.returnSuccessors = new RichArray<>(alphabet.getNumReturns(), - (Supplier>>) ArrayList::new); + this.intSuccessors = new ArrayStorage<>(alphabet.getNumInternals()); + this.returnSuccessors = new ArrayStorage<>(alphabet.getNumReturns(), ArrayList::new); this.treeIncoming = treeIncoming; this.aseq = (treeIncoming != null) ? treeIncoming.getAccessSequence() : Word.epsilon(); } @@ -54,15 +52,14 @@ public HypLoc(VPDAlphabet alphabet, int index, boolean accepting, AbstractHyp public HypLoc(VPDAlphabet alphabet, int index, boolean accepting, Word aseq) { this.index = index; this.accepting = accepting; - this.intSuccessors = new RichArray<>(alphabet.getNumInternals()); - this.returnSuccessors = new RichArray<>(alphabet.getNumReturns(), - (Supplier>>) ArrayList::new); + this.intSuccessors = new ArrayStorage<>(alphabet.getNumInternals()); + this.returnSuccessors = new ArrayStorage<>(alphabet.getNumReturns(), ArrayList::new); this.treeIncoming = null; this.aseq = aseq; } public void updateStackAlphabetSize(int newStackAlphaSize) { - for (int i = 0; i < returnSuccessors.length; i++) { + for (int i = 0; i < returnSuccessors.size(); i++) { List> transList = returnSuccessors.get(i); if (transList == null) { transList = new ArrayList<>(Collections.nCopies(newStackAlphaSize, null)); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java index ff83d5dc57..09f6b69705 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java @@ -24,7 +24,7 @@ import de.learnlib.algorithms.ttt.base.TTTTransition; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.commons.util.array.RichArray; +import net.automatalib.commons.util.array.ArrayStorage; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -175,13 +175,13 @@ protected ExtDTNode computeNext() { private final class EasyTTTPrefAcex implements AbstractCounterexample { private final Word ceWord; - private final RichArray> hypNodes; - private final RichArray> siftNodes; + private final ArrayStorage> hypNodes; + private final ArrayStorage> siftNodes; EasyTTTPrefAcex(Word ceWord) { this.ceWord = ceWord; - this.hypNodes = new RichArray<>(ceWord.length() + 1); - this.siftNodes = new RichArray<>(ceWord.length() + 1); + this.hypNodes = new ArrayStorage<>(ceWord.length() + 1); + this.siftNodes = new ArrayStorage<>(ceWord.length() + 1); update(ceWord.length()); } diff --git a/commons/acex/src/main/java/de/learnlib/acex/impl/AbstractBaseCounterexample.java b/commons/acex/src/main/java/de/learnlib/acex/impl/AbstractBaseCounterexample.java index 892da91ee2..93ce1cdcd9 100644 --- a/commons/acex/src/main/java/de/learnlib/acex/impl/AbstractBaseCounterexample.java +++ b/commons/acex/src/main/java/de/learnlib/acex/impl/AbstractBaseCounterexample.java @@ -16,11 +16,11 @@ package de.learnlib.acex.impl; import de.learnlib.acex.AbstractCounterexample; -import net.automatalib.commons.util.array.RichArray; +import net.automatalib.commons.util.array.ArrayStorage; public abstract class AbstractBaseCounterexample implements AbstractCounterexample { - private final RichArray values; + private final ArrayStorage values; /** * Constructor. @@ -29,7 +29,7 @@ public abstract class AbstractBaseCounterexample implements AbstractCounterex * length of the counterexample */ public AbstractBaseCounterexample(int m) { - this.values = new RichArray<>(m); + this.values = new ArrayStorage<>(m); } /** @@ -39,7 +39,7 @@ public AbstractBaseCounterexample(int m) { */ @Override public int getLength() { - return values.length; + return values.size(); } @Override @@ -60,7 +60,7 @@ public void setEffect(int index, E effect) { @Override public String toString() { - StringBuilder sb = new StringBuilder(values.length); + StringBuilder sb = new StringBuilder(values.size()); boolean first = true; for (E v : values) { diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBasePTAState.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBasePTAState.java index 03de847978..3407115922 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBasePTAState.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBasePTAState.java @@ -19,13 +19,13 @@ import java.util.function.Consumer; import java.util.stream.Stream; -import net.automatalib.commons.util.array.RichArray; +import net.automatalib.commons.util.array.ArrayStorage; public abstract class AbstractBasePTAState> implements Cloneable { protected SP property; - protected RichArray transProperties; - protected RichArray successors; + protected ArrayStorage transProperties; + protected ArrayStorage successors; protected int id = -1; public SP getStateProperty() { @@ -43,7 +43,7 @@ public S copy() { return copy((transProperties != null) ? transProperties.clone() : null); } - public S copy(RichArray newTPs) { + public S copy(ArrayStorage newTPs) { try { @SuppressWarnings("unchecked") S copy = (S) clone(); @@ -66,19 +66,19 @@ public S getSuccessor(int index) { public void setSuccessor(int index, S succ, int alphabetSize) { if (successors == null) { - successors = new RichArray<>(alphabetSize); + successors = new ArrayStorage<>(alphabetSize); } - successors.update(index, succ); + successors.set(index, succ); } public S getOrCreateSuccessor(int index, int alphabetSize) { if (successors == null) { - successors = new RichArray<>(alphabetSize); + successors = new ArrayStorage<>(alphabetSize); } S succ = successors.get(index); if (succ == null) { succ = createSuccessor(index); - successors.update(index, succ); + successors.set(index, succ); } return succ; } @@ -112,10 +112,10 @@ public boolean tryMergeTransitionProperty(int index, int alphabetSize, TP newTP) return Objects.equals(oldTp, newTP); } } else { - transProperties = new RichArray<>(alphabetSize); + transProperties = new ArrayStorage<>(alphabetSize); } - transProperties.update(index, newTP); + transProperties.set(index, newTP); return true; } diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java index 178bf4b59c..09cde752c9 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java @@ -28,20 +28,19 @@ import com.google.common.collect.Sets; import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.commons.util.Pair; -import net.automatalib.commons.util.array.RichArray; +import net.automatalib.commons.util.array.ArrayStorage; public class RedBlueMerge> { private final AbstractBlueFringePTA pta; - private final RichArray[] succMod; - private final RichArray[] transPropMod; - private final RichArray propMod; + private final ArrayStorage> succMod; + private final ArrayStorage> transPropMod; + private final ArrayStorage propMod; private final int alphabetSize; private final S qr; private final S qb; private boolean merged; - @SuppressWarnings("unchecked") public RedBlueMerge(AbstractBlueFringePTA pta, S qr, S qb) { if (!qr.isRed()) { throw new IllegalArgumentException("Merge target must be a red state"); @@ -53,9 +52,9 @@ public RedBlueMerge(AbstractBlueFringePTA pta, S qr, S qb) { this.pta = pta; int numRedStates = pta.getNumRedStates(); - this.succMod = new RichArray[numRedStates]; - this.transPropMod = new RichArray[numRedStates]; - this.propMod = new RichArray<>(numRedStates); + this.succMod = new ArrayStorage<>(numRedStates); + this.transPropMod = new ArrayStorage<>(numRedStates); + this.propMod = new ArrayStorage<>(numRedStates); this.alphabetSize = pta.alphabetSize; this.qr = qr; @@ -112,13 +111,13 @@ public boolean merge() { } } - RichArray newTPs = null; - RichArray rSuccTPs = rSucc.transProperties; - RichArray qSuccTPs = qSucc.transProperties; + ArrayStorage newTPs = null; + ArrayStorage rSuccTPs = rSucc.transProperties; + ArrayStorage qSuccTPs = qSucc.transProperties; if (rSuccTPs != null) { if (qSuccTPs != null) { - RichArray mergedTPs = mergeTransProperties(qSuccTPs, rSuccTPs); + ArrayStorage mergedTPs = mergeTransProperties(qSuccTPs, rSuccTPs); if (mergedTPs == null) { return false; } else if (mergedTPs != qSuccTPs) { @@ -153,7 +152,7 @@ public boolean merge() { return true; } - private S cloneTopSucc(S succ, int i, Deque> stack, RichArray newTPs) { + private S cloneTopSucc(S succ, int i, Deque> stack, ArrayStorage newTPs) { S succClone = (newTPs != null) ? succ.copy(newTPs) : succ.copy(); if (succClone == succ) { return succ; @@ -188,7 +187,7 @@ private S cloneTop(S topState, Deque> stack) { while (!currSrc.isRed()) { S currSrcClone = currSrc.copy(); - currSrcClone.successors.update(currRec.i, currTgt); + currSrcClone.successors.set(currRec.i, currTgt); if (currSrcClone == currSrc) { return topClone; // we're done } @@ -206,10 +205,10 @@ private S cloneTop(S topState, Deque> stack) { return topClone; } - private RichArray getTransProperties(S q) { + private ArrayStorage getTransProperties(S q) { if (q.isRed()) { int qId = q.id; - RichArray props = transPropMod[qId]; + ArrayStorage props = transPropMod.get(qId); if (props != null) { return props; } @@ -231,7 +230,7 @@ private SP getStateProperty(S q) { private S getSucc(S q, int i) { if (q.isRed()) { int qId = q.id; - RichArray modSuccs = succMod[qId]; + ArrayStorage modSuccs = succMod.get(qId); if (modSuccs != null) { return modSuccs.get(i); } @@ -247,27 +246,27 @@ private void updateRedTransition(S redSrc, int input, S tgt, TP transProp) { assert redSrc.isRed(); int id = redSrc.id; - RichArray newSuccs = succMod[id]; + ArrayStorage newSuccs = succMod.get(id); if (newSuccs == null) { if (redSrc.successors == null) { - newSuccs = new RichArray<>(alphabetSize); + newSuccs = new ArrayStorage<>(alphabetSize); } else { newSuccs = redSrc.successors.clone(); } - succMod[id] = newSuccs; + succMod.set(id, newSuccs); } - newSuccs.update(input, tgt); + newSuccs.set(input, tgt); if (transProp != null) { - RichArray newTransProps = transPropMod[id]; + ArrayStorage newTransProps = transPropMod.get(id); if (newTransProps == null) { if (redSrc.transProperties == null) { - newTransProps = new RichArray<>(alphabetSize); + newTransProps = new ArrayStorage<>(alphabetSize); } else { newTransProps = redSrc.transProperties.clone(); } - transPropMod[id] = newTransProps; + transPropMod.set(id, newTransProps); } - newTransProps.update(input, transProp); + newTransProps.set(input, transProp); } } @@ -278,12 +277,12 @@ private boolean mergeRedProperties(S qr, S qb) { private boolean mergeRedTransProperties(S qr, S qb) { assert qr.isRed(); - RichArray qbProps = qb.transProperties; + ArrayStorage qbProps = qb.transProperties; if (qbProps == null) { return true; } - RichArray qrProps = getTransProperties(qr); - RichArray mergedProps = qbProps; + ArrayStorage qrProps = getTransProperties(qr); + ArrayStorage mergedProps = qbProps; if (qrProps != null) { mergedProps = mergeTransProperties(qrProps, qbProps); if (mergedProps == null) { @@ -291,7 +290,7 @@ private boolean mergeRedTransProperties(S qr, S qb) { } } if (mergedProps != qrProps) { - transPropMod[qr.id] = mergedProps; + transPropMod.set(qr.id, mergedProps); } return true; } @@ -307,21 +306,21 @@ private boolean mergeRedStateProperty(S qr, S qb) { if (qrProp != null) { return Objects.equals(qbProp, qrProp); } - propMod.update(qr.id, qbProp); + propMod.set(qr.id, qbProp); return true; } /** * Merges two non-null transition property arrays. The behavior of this method is as follows:

+ * can be merged, a new {@link ArrayStorage} containing the result of the merge is returned.
  • otherwise + * (i.e., if no merge is possible), {@code null} is returned. */ - private RichArray mergeTransProperties(RichArray tps1, RichArray tps2) { - int len = tps1.length; + private ArrayStorage mergeTransProperties(ArrayStorage tps1, ArrayStorage tps2) { + int len = tps1.size(); int i; - RichArray tps1OrCopy = tps1; + ArrayStorage tps1OrCopy = tps1; for (i = 0; i < len; i++) { TP tp1 = tps1OrCopy.get(i); @@ -333,7 +332,7 @@ private RichArray mergeTransProperties(RichArray tps1, RichArray tps } } else { tps1OrCopy = tps1.clone(); - tps1OrCopy.update(i++, tp2); + tps1OrCopy.set(i++, tp2); break; } } @@ -348,7 +347,7 @@ private RichArray mergeTransProperties(RichArray tps1, RichArray tps return null; } } else { - tps1OrCopy.update(i, tp2); + tps1OrCopy.set(i, tp2); } } } @@ -359,12 +358,12 @@ private RichArray mergeTransProperties(RichArray tps1, RichArray tps public void apply(AbstractBlueFringePTA pta, Consumer> newFrontierConsumer) { int alphabetSize = pta.alphabetSize; - for (int i = 0; i < succMod.length; i++) { + for (int i = 0; i < succMod.size(); i++) { S redState = pta.redStates.get(i); assert redState.isRed(); - RichArray newSuccs = succMod[i]; + ArrayStorage newSuccs = succMod.get(i); if (newSuccs != null) { - int len = newSuccs.length; + int len = newSuccs.size(); for (int j = 0; j < len; j++) { S newSucc = newSuccs.get(j); if (newSucc != null) { @@ -386,7 +385,7 @@ public void apply(AbstractBlueFringePTA pta, Consumer newTransProps = transPropMod[i]; + ArrayStorage newTransProps = transPropMod.get(i); if (newTransProps != null) { redState.transProperties = newTransProps; } @@ -404,7 +403,7 @@ private void incorporate(S state) { S curr; while ((curr = queue.poll()) != null) { - RichArray succs = curr.successors; + ArrayStorage succs = curr.successors; if (succs == null) { continue; } @@ -436,8 +435,8 @@ public S getSuccessor(Pair transition) { final S source = transition.getFirst(); final Integer input = transition.getSecond(); - if (source.isRed() && succMod[source.id] != null) { - return succMod[source.id].get(input); + if (source.isRed() && succMod.get(source.id) != null) { + return succMod.get(source.id).get(input); } return pta.getSuccessor(source, input); @@ -457,8 +456,8 @@ public TP getTransitionProperty(Pair transition) { final S source = transition.getFirst(); final Integer input = transition.getSecond(); - if (source.isRed() && transPropMod[source.id] != null) { - return transPropMod[source.id].get(input); + if (source.isRed() && transPropMod.get(source.id) != null) { + return transPropMod.get(source.id).get(input); } return source.transProperties.get(input); diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java index 3f7fb8d4ab..4f32d2b526 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java @@ -27,7 +27,6 @@ import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; -import net.automatalib.commons.util.array.RichArray; import net.automatalib.commons.util.comparison.CmpUtil; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.incremental.mealy.IncrementalMealyBuilder; @@ -121,8 +120,8 @@ public void processQueries(Collection>> queries) { return; } - RichArray>> qrys = new RichArray<>(queries); - qrys.parallelSort(queryCmp); + List>> qrys = new ArrayList<>(queries); + qrys.sort(queryCmp); List> masterQueries = new ArrayList<>(); From a3449685d967b82dcc05bbc027616e28cc733e66 Mon Sep 17 00:00:00 2001 From: Jeroen Meijer Date: Wed, 17 Oct 2018 00:08:19 -0700 Subject: [PATCH 083/125] Add black-box checking with monitors. (#61) * Accommodate automatalib changes. * Add a chain for property oracles. * Add an example for black-box checking with monitors. * fix parameter name * Make a property oracle also an inclusion oracle. Also widen types for implementations of black box oracles. * Add a refinement counter learner. * Fix bug in verifying lassos. * Optmization for ShallowCopySULOmegaOracle. We can assume one SUL is already in the correct state. * Optimize LassoOracles. LassoOracles will now perform only one OmegaQuery per Lasso. Previously LassoOracles would perform an OmegaQuery for each unrolling of the Lasso's loop. This was unnecessary and more costly. * Fix Javadoc. * adjust to changes in AutomataLib * travis: update LTSmin installation - Require version v3.1.0 - Download binary from a configurable repository --- .travis.yml | 2 +- .../api/logging/LoggingPropertyOracle.java | 7 +- .../learnlib/api/oracle/AutomatonOracle.java | 2 +- .../learnlib/api/oracle/BlackBoxOracle.java | 4 +- .../learnlib/api/oracle/EmptinessOracle.java | 2 +- .../learnlib/api/oracle/InclusionOracle.java | 2 +- .../api/oracle/LassoEmptinessOracle.java | 23 +-- .../de/learnlib/api/oracle/LassoOracle.java | 84 +++++----- .../learnlib/api/oracle/PropertyOracle.java | 33 +++- .../api/statistic/StatisticLearner.java | 45 ++++++ .../api/statistic/StatisticOracle.java | 6 +- build-tools/install-ltsmin.sh | 2 +- .../examples/bbc/example1/Example.java | 2 +- .../examples/bbc/example2/Example.java | 2 +- .../examples/bbc/example3/Example.java | 2 +- .../examples/bbc/example4/Example.java | 139 +++++++++++++++++ .../DFALassoEmptinessOracleImpl.java | 11 +- .../emptiness/LassoEmptinessOracleImpl.java | 16 +- .../MealyLassoEmptinessOracleImpl.java | 11 +- .../AbstractLassoEmptinessOracleImplTest.java | 33 ++-- .../DFALassoEmptinessOracleImplTest.java | 2 +- .../MealyLassoEmptinessOracleImplTest.java | 2 +- .../oracle/equivalence/CExFirstOracle.java | 25 ++- .../equivalence/DisproveFirstOracle.java | 40 ++--- .../equivalence/CExFirstOracleTest.java | 10 +- .../equivalence/DisproveFirstOracleTest.java | 12 +- .../learner/RefinementCounterLearner.java | 95 +++++++++++ .../membership/AbstractSULOmegaOracle.java | 45 +++--- .../property/AbstractPropertyOracle.java | 8 +- .../property/DFAFinitePropertyOracle.java | 2 +- .../property/DFALassoPropertyOracle.java | 2 +- .../property/MealyFinitePropertyOracle.java | 2 +- .../property/MealyLassoPropertyOracle.java | 2 +- .../oracle/property/PropertyOracleChain.java | 147 ++++++++++++++++++ 34 files changed, 627 insertions(+), 195 deletions(-) create mode 100644 api/src/main/java/de/learnlib/api/statistic/StatisticLearner.java create mode 100644 examples/src/main/java/de/learnlib/examples/bbc/example4/Example.java create mode 100644 oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/learner/RefinementCounterLearner.java create mode 100644 oracles/property-oracles/src/main/java/de/learnlib/oracle/property/PropertyOracleChain.java diff --git a/.travis.yml b/.travis.yml index b53d31b683..b10b1af876 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ branches: env: global: - - LTSMIN_VERSION=v3.0.2 + - LTSMIN_VERSION=v3.1.0 install: # install LTSmin diff --git a/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java b/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java index 0c341b10ba..f9551326e5 100644 --- a/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java +++ b/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java @@ -21,6 +21,7 @@ import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.exception.ModelCheckingException; @@ -39,7 +40,7 @@ * @param

    + * Note that a property oracle is also an {@link InclusionOracle} and thus an {@link EquivalenceOracle}, hence it can + * be use used to find counterexamples to hypotheses. + *

    * An implementation should keep track of whether the property is already disproved. * * @param the input type @@ -38,7 +42,7 @@ * @author Jeroen Meijer */ @ParametersAreNonnullByDefault -public interface PropertyOracle { +public interface PropertyOracle, P, D> extends InclusionOracle { /** * Returns whether the property is disproved. @@ -66,7 +70,7 @@ default boolean isDisproved() { /** * Returns the counterexample for the property if {@link #isDisproved()}, {@code null} otherwise. * - * If this method does not return {@code null}, a previous call to {@link #disprove(Object, Collection)} must + * If this method does not return {@code null}, a previous call to {@link #disprove(Output, Collection)} must * have returned a {@link DefaultQuery}. * * @return the counterexample for the property if {@link #isDisproved()}, {@code null} otherwise. @@ -87,19 +91,32 @@ default boolean isDisproved() { DefaultQuery disprove(A hypothesis, Collection inputs); /** - * Try to find a counterexample to the given {@code hypothesis}. + * Try to find a counterexample to the given {@code hypothesis} if the property can not be disproved. * * @param hypothesis the hypothesis to find a counterexample to. * @param inputs the input alphabet. * * @return the {@link DefaultQuery} that is a counterexample to the given {@code hypothesis}, or {@code - * null}, a counterexample could not be found. + * null}, a counterexample could not be found or the property could be disproved. + */ + @Override + @Nullable + default DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + return isDisproved() || disprove(hypothesis, inputs) != null ? null : doFindCounterExample(hypothesis, inputs); + } + + /** + * Unconditionally find a counterexample, i.e. regardless of whether the property can be disproved. In fact, + * {@link #disprove(Output, Collection)} is not even be called. + * + * @see #findCounterExample(Output, Collection) */ @Nullable - DefaultQuery findCounterExample(A hypothesis, Collection inputs); + DefaultQuery doFindCounterExample(A hypothesis, Collection inputs); - interface DFAPropertyOracle extends PropertyOracle, P, Boolean> {} + interface DFAPropertyOracle extends PropertyOracle, P, Boolean>, DFAInclusionOracle {} - interface MealyPropertyOracle extends PropertyOracle, P, Word> {} + interface MealyPropertyOracle + extends PropertyOracle, P, Word>, MealyInclusionOracle {} } diff --git a/api/src/main/java/de/learnlib/api/statistic/StatisticLearner.java b/api/src/main/java/de/learnlib/api/statistic/StatisticLearner.java new file mode 100644 index 0000000000..7c4cd6fb37 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/statistic/StatisticLearner.java @@ -0,0 +1,45 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api.statistic; + +import javax.annotation.Nonnull; + +import de.learnlib.api.algorithm.LearningAlgorithm; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +/** + * Common interface for learners keeping statistics. + * + * @param + * the automaton type + * @param + * input symbol class + * @param + * output symbol class + * + * @author Jeroen Meijer + */ +public interface StatisticLearner extends LearningAlgorithm { + + @Nonnull + StatisticData getStatisticalData(); + + interface DFAStatisticLearner extends StatisticLearner, I, Boolean> {} + + interface MealyStatisticLearner extends StatisticLearner, I, Word> {} +} diff --git a/api/src/main/java/de/learnlib/api/statistic/StatisticOracle.java b/api/src/main/java/de/learnlib/api/statistic/StatisticOracle.java index 8dd52822a0..d3dce825e0 100644 --- a/api/src/main/java/de/learnlib/api/statistic/StatisticOracle.java +++ b/api/src/main/java/de/learnlib/api/statistic/StatisticOracle.java @@ -25,12 +25,12 @@ * * @param * input symbol class - * @param - * output symbol class + * @param + * output domain class * * @author falkhowar */ -public interface StatisticOracle extends Filter { +public interface StatisticOracle extends Filter { /** * @return the statistical data gathered by this oracle diff --git a/build-tools/install-ltsmin.sh b/build-tools/install-ltsmin.sh index 3b2112b618..cca3c7d055 100755 --- a/build-tools/install-ltsmin.sh +++ b/build-tools/install-ltsmin.sh @@ -1,7 +1,7 @@ #!/bin/bash LTSMIN_NAME="ltsmin-${LTSMIN_VERSION}-$TRAVIS_OS_NAME.tgz" -LTSMIN_URL="https://github.com/utwente-fmt/ltsmin/releases/download/$LTSMIN_VERSION/$LTSMIN_NAME" +LTSMIN_URL="https://github.com/$%7BLTSMIN_REPO:-utwente-fmt%7D/ltsmin/releases/download/$LTSMIN_VERSION/$LTSMIN_NAME" # test if we have a cached version test -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/ltsmin-convert" -a -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/etf2lts-mc" && exit 0 diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java index e9df2d7b4e..f6f3358742 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java @@ -38,7 +38,7 @@ import de.learnlib.oracle.property.DFALassoPropertyOracle; import de.learnlib.util.Experiment; import net.automatalib.automata.fsa.DFA; -import net.automatalib.modelcheckers.ltsmin.LTSminLTLDFABuilder; +import net.automatalib.modelcheckers.ltsmin.ltl.LTSminLTLDFABuilder; import net.automatalib.modelchecking.ModelCheckerLasso.DFAModelCheckerLasso; import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; import net.automatalib.words.Alphabet; diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java index 31c3ae0281..69601fac1a 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java @@ -38,7 +38,7 @@ import de.learnlib.oracle.property.MealyLassoPropertyOracle; import de.learnlib.util.Experiment; import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.modelcheckers.ltsmin.LTSminLTLIOBuilder; +import net.automatalib.modelcheckers.ltsmin.ltl.LTSminLTLIOBuilder; import net.automatalib.modelchecking.ModelCheckerLasso.MealyModelCheckerLasso; import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; import net.automatalib.words.Alphabet; diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java index af38b10be0..31786cdd77 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java @@ -38,7 +38,7 @@ import de.learnlib.oracle.property.MealyLassoPropertyOracle; import de.learnlib.util.Experiment; import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.modelcheckers.ltsmin.LTSminLTLAlternatingBuilder; +import net.automatalib.modelcheckers.ltsmin.ltl.LTSminLTLAlternatingBuilder; import net.automatalib.modelchecking.ModelCheckerLasso.MealyModelCheckerLasso; import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; import net.automatalib.words.Alphabet; diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example4/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/example4/Example.java new file mode 100644 index 0000000000..203ab8bc00 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/bbc/example4/Example.java @@ -0,0 +1,139 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.bbc.example4; + +import java.util.function.Function; + +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.algorithms.ttt.dfa.TTTLearnerDFA; +import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; +import de.learnlib.api.logging.LoggingPropertyOracle; +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; +import de.learnlib.api.oracle.InclusionOracle.DFAInclusionOracle; +import de.learnlib.api.oracle.LassoEmptinessOracle; +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; +import de.learnlib.api.oracle.PropertyOracle; +import de.learnlib.examples.LearningExample.DFALearningExample; +import de.learnlib.examples.dfa.ExampleTinyDFA; +import de.learnlib.oracle.emptiness.DFABFEmptinessOracle; +import de.learnlib.oracle.emptiness.DFALassoEmptinessOracleImpl; +import de.learnlib.oracle.equivalence.CExFirstOracle; +import de.learnlib.oracle.equivalence.DFABFInclusionOracle; +import de.learnlib.oracle.equivalence.EQOracleChain; +import de.learnlib.oracle.equivalence.WpMethodEQOracle.DFAWpMethodEQOracle; +import de.learnlib.oracle.membership.SimulatorOmegaOracle.DFASimulatorOmegaOracle; +import de.learnlib.oracle.property.DFAFinitePropertyOracle; +import de.learnlib.oracle.property.DFALassoPropertyOracle; +import de.learnlib.oracle.property.PropertyOracleChain; +import de.learnlib.util.Experiment; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.modelcheckers.ltsmin.LTSminUtil; +import net.automatalib.modelcheckers.ltsmin.LTSminVersion; +import net.automatalib.modelcheckers.ltsmin.ltl.LTSminLTLDFABuilder; +import net.automatalib.modelcheckers.ltsmin.monitor.LTSminMonitorDFABuilder; +import net.automatalib.modelchecking.ModelChecker; +import net.automatalib.modelchecking.ModelCheckerLasso.DFAModelCheckerLasso; +import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest; +import net.automatalib.words.Alphabet; + +/** + * Runs a black-box checking experiment for a DFA. + *

    + * This example is similar to {@link de.learnlib.examples.bbc.example1.Example}, except that is also uses a monitor + * to disprove properties for the learned DFA. + * + * @author Jeroen Meijer + */ +public final class Example { + + /** + * A function that transforms edges in an FSM source to actual input for a DFA. + */ + public static final Function EDGE_PARSER = s -> s.charAt(0); + + private Example() {} + + public static void main(String[] args) { + + DFALearningExample le = ExampleTinyDFA.createExample(); + + // define the alphabet + Alphabet sigma = le.getAlphabet(); + + // create the DFA to be verified/learned + DFA dfa = le.getReferenceAutomaton(); + + // create an omega membership oracle + DFAOmegaMembershipOracle omqOracle = new DFASimulatorOmegaOracle<>(dfa); + + // create a regular membership oracle + DFAMembershipOracle mqOracle = omqOracle.getMembershipOracle(); + + // create a learner + DFALearner learner = new TTTLearnerDFA<>(sigma, mqOracle, AcexAnalyzers.LINEAR_FWD); + + // create a model checker that uses a Buchi automaton + DFAModelCheckerLasso modelCheckerBuchi = + new LTSminLTLDFABuilder().withString2Input(EDGE_PARSER).create(); + + // create a lasso emptiness oracle, that is used to disprove properties + LassoEmptinessOracle.DFALassoEmptinessOracle + lassoEmptinessOracle = new DFALassoEmptinessOracleImpl<>(omqOracle); + + // The following code requires v3.1.0 + if (!LTSminUtil.supports(LTSminVersion.of(3, 1, 0))) { + return; + } + + // create a model checker that uses monitors + ModelChecker.DFAModelChecker> modelCheckerMonitor = + new LTSminMonitorDFABuilder().withString2Input(EDGE_PARSER).create(); + + // create an emptiness oracle, that is used to disprove properties. + EmptinessOracle.DFAEmptinessOracle + emptinessOracle = new DFABFEmptinessOracle<>(mqOracle, 1.0); + + // create an inclusion oracle, that is used to find counterexamples to hypotheses + DFAInclusionOracle inclusionOracle = new DFABFInclusionOracle<>(mqOracle, 1.0); + + // create an LTL property oracle, that also logs stuff + // also it chains the property oracle that uses monitors and Buchi automata + PropertyOracle.DFAPropertyOracle ltl = new LoggingPropertyOracle.DFALoggingPropertyOracle<>( + new PropertyOracleChain.DFAPropertyOracleChain<>( + new DFAFinitePropertyOracle<>("letter==\"b\"", inclusionOracle, emptinessOracle, modelCheckerMonitor), + new DFALassoPropertyOracle<>("letter==\"b\"", inclusionOracle, lassoEmptinessOracle, modelCheckerBuchi))); + + // create an equivalence oracle, that first searches for a counter example using the ltl properties, and next + // with the W-method. + DFAEquivalenceOracle eqOracle = new EQOracleChain.DFAEQOracleChain<>( + new CExFirstOracle.DFACExFirstOracle<>(ltl), + new DFAWpMethodEQOracle<>(mqOracle, 3)); + + // create an experiment + Experiment.DFAExperiment experiment = new Experiment.DFAExperiment<>(learner, eqOracle, sigma); + + // run the experiment + experiment.run(); + + // get the result + final DFA result = experiment.getFinalHypothesis(); + + // assert we have the correct result + assert DeterministicEquivalenceTest.findSeparatingWord(dfa, result, sigma) == null; + } +} diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java index 19de071f6d..498d8af3d4 100644 --- a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java @@ -15,14 +15,13 @@ */ package de.learnlib.oracle.emptiness; -import de.learnlib.api.oracle.LassoEmptinessOracle; -import de.learnlib.api.oracle.LassoOracle; +import de.learnlib.api.oracle.LassoEmptinessOracle.DFALassoEmptinessOracle; +import de.learnlib.api.oracle.LassoOracle.DFALassoOracle; import de.learnlib.api.oracle.OmegaMembershipOracle; -import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.Lasso.DFALasso; -public class DFALassoEmptinessOracleImpl - extends LassoEmptinessOracleImpl, S, I, Boolean> - implements LassoEmptinessOracle.DFALassoEmptinessOracle, LassoOracle.DFALassoOracle { +public class DFALassoEmptinessOracleImpl extends LassoEmptinessOracleImpl, S, I, Boolean> + implements DFALassoEmptinessOracle, DFALassoOracle { public DFALassoEmptinessOracleImpl(OmegaMembershipOracle omegaMembershipOracle) { super(omegaMembershipOracle); diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java index 4de67911f2..ddc83b09f6 100644 --- a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java @@ -24,12 +24,11 @@ import de.learnlib.api.oracle.OmegaMembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; -import de.learnlib.util.AbstractBFOracle; +import net.automatalib.automata.concepts.Output; import net.automatalib.modelchecking.Lasso; import net.automatalib.words.Word; public class LassoEmptinessOracleImpl, S, I, D> - extends AbstractBFOracle implements LassoEmptinessOracle, LassoOracle { /** @@ -38,7 +37,6 @@ public class LassoEmptinessOracleImpl, S, I, D> private final OmegaMembershipOracle omegaMembershipOracle; public LassoEmptinessOracleImpl(OmegaMembershipOracle omegaMembershipOracle) { - super(omegaMembershipOracle.getMembershipOracle(), -1.0); this.omegaMembershipOracle = omegaMembershipOracle; } @@ -47,14 +45,16 @@ public OmegaMembershipOracle getOmegaMembershipOracle() { } @Override - public OmegaQuery processOmegaQuery(OmegaQuery query) { + public OmegaQuery processInput(Word prefix, Word loop, int repeat) { + final OmegaQuery query = new OmegaQuery<>(prefix, loop, repeat); omegaMembershipOracle.processQuery(query); + return query; } @Override - public boolean isCounterExample(L hypothesis, Iterable inputs, @Nullable D output) { - return LassoEmptinessOracle.super.isCounterExample(hypothesis, inputs, output); + public boolean isCounterExample(Output hypothesis, Iterable input, @Nullable D output) { + return LassoEmptinessOracle.super.isCounterExample(hypothesis, input, output); } @Nullable @@ -64,7 +64,7 @@ public DefaultQuery findCounterExample(L hypothesis, Collection processInput(L hypothesis, Word input) { - return LassoOracle.super.processInput(hypothesis, input); + public boolean isOmegaCounterExample(boolean isUltimatelyPeriodic) { + return LassoEmptinessOracle.super.isOmegaCounterExample(isUltimatelyPeriodic); } } diff --git a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java index aa4d8953d1..2064f19650 100644 --- a/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java @@ -15,15 +15,14 @@ */ package de.learnlib.oracle.emptiness; -import de.learnlib.api.oracle.LassoEmptinessOracle; -import de.learnlib.api.oracle.LassoOracle; +import de.learnlib.api.oracle.LassoEmptinessOracle.MealyLassoEmptinessOracle; +import de.learnlib.api.oracle.LassoOracle.MealyLassoOracle; import de.learnlib.api.oracle.OmegaMembershipOracle; -import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.Lasso.MealyLasso; import net.automatalib.words.Word; -public class MealyLassoEmptinessOracleImpl - extends LassoEmptinessOracleImpl, S, I, Word> - implements LassoEmptinessOracle.MealyLassoEmptinessOracle, LassoOracle.MealyLassoOracle { +public class MealyLassoEmptinessOracleImpl extends LassoEmptinessOracleImpl, S, I, Word> + implements MealyLassoEmptinessOracle, MealyLassoOracle { public MealyLassoEmptinessOracleImpl(OmegaMembershipOracle> omegaMembershipOracle) { super(omegaMembershipOracle); diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java index 269561ce42..5a1e4f7a4f 100644 --- a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java @@ -17,13 +17,13 @@ import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; -import de.learnlib.oracle.AbstractBFOracleTest; -import de.learnlib.util.AbstractBFOracle; import net.automatalib.modelchecking.Lasso; -import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.Alphabet; import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -36,8 +36,9 @@ * @param the lasso type * @param the output type */ -public abstract class AbstractLassoEmptinessOracleImplTest, D> - extends AbstractBFOracleTest { +public abstract class AbstractLassoEmptinessOracleImplTest, D> { + + public static final Alphabet ALPHABET = Alphabets.singleton('a'); private LassoEmptinessOracleImpl leo; @@ -61,23 +62,15 @@ public abstract class AbstractLassoEmptinessOracleImplTest test = new OmegaQuery<>(prefix, loop, 1); - + public void testProcessInput() throws Exception { Mockito.doAnswer(invocation -> { final OmegaQuery q = invocation.getArgument(0); if (q.getLoop().equals(Word.fromSymbols('a'))) { @@ -88,17 +81,15 @@ public void testProcessOmegaQuery() throws Exception { return null; }).when(leo.getOmegaMembershipOracle()).processQuery(ArgumentMatchers.any()); - leo.processOmegaQuery(test); + final OmegaQuery test = leo.processInput(prefix, loop, 1); + Assert.assertEquals(test.getPrefix(), Word.epsilon()); + Assert.assertEquals(test.getLoop(), Word.fromSymbols('a')); + Assert.assertEquals(test.getRepeat(), 1); Assert.assertEquals(test.getOutput(), output); Assert.assertEquals(test.getPeriodicity(), 1); } - @Override - protected AbstractBFOracle, Character, D> createBreadthFirstOracle(double multiplier) { - return createLassoEmptinessOracleImpl(); - } - @Test public void testFindCounterExample() { final DefaultQuery cex = leo.findCounterExample(automaton, ALPHABET); diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java index 7a9b0b3640..97cd610d56 100644 --- a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java @@ -47,7 +47,7 @@ public void setUp() { if (q.getLoop().equals(Word.fromSymbols('a'))) { q.answer(true, 1); } else { - q.answer(false, 1); + q.answer(false, -1); } return null; }).when(omo).processQuery(ArgumentMatchers.any()); diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java index e0e12bdecc..30094df7b0 100644 --- a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java @@ -47,7 +47,7 @@ public void setUp() { if (q.getLoop().equals(Word.fromSymbols('a'))) { q.answer(Word.fromSymbols('1'), 1); } else { - q.answer(Word.epsilon(), 1); + q.answer(Word.epsilon(), -1); } return null; }).when(omo).processQuery(ArgumentMatchers.any()); diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java index 9661e7bcd6..8454e047a0 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java @@ -15,8 +15,10 @@ */ package de.learnlib.oracle.equivalence; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import javax.annotation.Nullable; @@ -45,7 +47,7 @@ */ public class CExFirstOracle, I, D> implements BlackBoxOracle { - private final Collection> propertyOracles; + private final List> propertyOracles; public CExFirstOracle() { this(Collections.emptySet()); @@ -55,28 +57,23 @@ public CExFirstOracle(PropertyOracle propertyOracle) { this(Collections.singleton(propertyOracle)); } - public CExFirstOracle(Collection> propertyOracles) { - this.propertyOracles = Collections.unmodifiableCollection(propertyOracles); + public CExFirstOracle(Collection> propertyOracles) { + this.propertyOracles = new ArrayList<>(propertyOracles); } @Override - public Collection> getPropertyOracles() { + public List> getPropertyOracles() { return propertyOracles; } @Nullable @Override public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { - for (PropertyOracle propertyOracle : propertyOracles) { - if (!propertyOracle.isDisproved()) { - final DefaultQuery ce = propertyOracle.disprove(hypothesis, inputs); - if (ce == null) { - final DefaultQuery result = propertyOracle.findCounterExample(hypothesis, inputs); - if (result != null) { - assert isCounterExample(hypothesis, result.getInput(), result.getOutput()); - return result; - } - } + for (PropertyOracle propertyOracle : propertyOracles) { + final DefaultQuery result = propertyOracle.findCounterExample(hypothesis, inputs); + if (result != null) { + assert isCounterExample(hypothesis, result.getInput(), result.getOutput()); + return result; } } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java index 985ceb92d9..2f250dcda5 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java @@ -15,11 +15,14 @@ */ package de.learnlib.oracle.equivalence; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import javax.annotation.Nullable; +import com.google.common.collect.Lists; import de.learnlib.api.oracle.BlackBoxOracle; import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.api.query.DefaultQuery; @@ -44,47 +47,45 @@ */ public class DisproveFirstOracle, I, D> implements BlackBoxOracle { - private final Collection> propertyOracles; + private final List> propertyOracles; public DisproveFirstOracle() { - this(Collections.emptySet()); + this(Collections.emptyList()); } - public DisproveFirstOracle(PropertyOracle propertyOracle) { - this(Collections.singleton(propertyOracle)); + public DisproveFirstOracle(PropertyOracle propertyOracle) { + this(Lists.newArrayList(propertyOracle)); } - public DisproveFirstOracle(Collection> propertyOracles) { - this.propertyOracles = Collections.unmodifiableCollection(propertyOracles); + public DisproveFirstOracle(Collection> propertyOracles) { + this.propertyOracles = new ArrayList<>(propertyOracles); } @Override - public Collection> getPropertyOracles() { + public List> getPropertyOracles() { return propertyOracles; } @Nullable @Override public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { - for (PropertyOracle po : propertyOracles) { + for (PropertyOracle po : propertyOracles) { if (!po.isDisproved()) { po.disprove(hypothesis, inputs); } } - DefaultQuery ce = null; - for (PropertyOracle po : propertyOracles) { + for (PropertyOracle po : propertyOracles) { if (!po.isDisproved()) { - ce = po.findCounterExample(hypothesis, inputs); + final DefaultQuery ce = po.doFindCounterExample(hypothesis, inputs); if (ce != null) { - break; + assert isCounterExample(hypothesis, ce.getInput(), ce.getOutput()); + return ce; } } } - assert ce == null || isCounterExample(hypothesis, ce.getInput(), ce.getOutput()); - - return ce; + return null; } public static class DFADisproveFirstOracle extends DisproveFirstOracle, I, Boolean> @@ -94,11 +95,11 @@ public DFADisproveFirstOracle() { super(); } - public DFADisproveFirstOracle(PropertyOracle, ?, Boolean> propertyOracle) { + public DFADisproveFirstOracle(PropertyOracle, ?, Boolean> propertyOracle) { super(propertyOracle); } - public DFADisproveFirstOracle(Collection, ?, Boolean>> propertyOracles) { + public DFADisproveFirstOracle(Collection, ?, Boolean>> propertyOracles) { super(propertyOracles); } } @@ -110,11 +111,12 @@ public MealyDisproveFirstOracle() { super(); } - public MealyDisproveFirstOracle(PropertyOracle, ?, Word> propertyOracle) { + public MealyDisproveFirstOracle(PropertyOracle, ?, Word> propertyOracle) { super(propertyOracle); } - public MealyDisproveFirstOracle(Collection, ?, Word>> propertyOracles) { + public MealyDisproveFirstOracle( + Collection, ?, Word>> propertyOracles) { super(propertyOracles); } } diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java index c6411fb4fd..1f328da89e 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java @@ -32,7 +32,7 @@ public class CExFirstOracleTest { - @Mock + @Mock() private PropertyOracle, Boolean, Boolean> po1; @Mock @@ -59,8 +59,10 @@ public void setUp() { Mockito.when(automaton.computeOutput(Mockito.any())).thenReturn(Boolean.FALSE); oracle = new CExFirstOracle<>(Lists.newArrayList(po1, po2)); - Mockito.when(po1.findCounterExample(automaton, inputs)).thenReturn(query); - Mockito.when(po2.findCounterExample(automaton, inputs)).thenReturn(query); + Mockito.when(po1.findCounterExample(automaton, inputs)).thenCallRealMethod(); + Mockito.when(po1.doFindCounterExample(automaton, inputs)).thenReturn(query); + Mockito.when(po2.findCounterExample(automaton, inputs)).thenCallRealMethod(); + Mockito.when(po2.doFindCounterExample(automaton, inputs)).thenReturn(query); } @Test @@ -71,7 +73,7 @@ public void testGetPropertyOracles() throws Exception { /** * Tests: * 1. whether the correct counterexample is given by the {@link CExFirstOracle}, and - * 2. whether {@link PropertyOracle#disprove(Object, Collection)} is called only on {@link #po2}. + * 2. whether {@link PropertyOracle#disprove(Output, Collection)} is called only on {@link #po2}. */ @Test public void testFindCounterExample() throws Exception { diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java index 692b7fbb2b..a5555e81b2 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java @@ -59,8 +59,10 @@ public void setUp() { Mockito.when(automaton.computeOutput(Mockito.any())).thenReturn(Boolean.FALSE); oracle = new DisproveFirstOracle<>(Lists.newArrayList(po1, po2)); - Mockito.when(po1.findCounterExample(automaton, inputs)).thenReturn(query); - Mockito.when(po2.findCounterExample(automaton, inputs)).thenReturn(query); + Mockito.when(po1.findCounterExample(automaton, inputs)).thenCallRealMethod(); + Mockito.when(po1.doFindCounterExample(automaton, inputs)).thenReturn(query); + Mockito.when(po2.findCounterExample(automaton, inputs)).thenCallRealMethod(); + Mockito.when(po2.doFindCounterExample(automaton, inputs)).thenReturn(query); } @Test @@ -71,7 +73,7 @@ public void testGetPropertyOracles() throws Exception { /** * Tests: * 1. whether the correct counterexample is given by the {@link DisproveFirstOracle}, and - * 2. whether {@link PropertyOracle#disprove(Object, Collection)} is called only on {@link #po2}. + * 2. whether {@link PropertyOracle#disprove(Output, Collection)} is called only on {@link #po2}. */ @Test public void testFindCounterExample() throws Exception { @@ -79,8 +81,8 @@ public void testFindCounterExample() throws Exception { Assert.assertEquals(ce, query); - Mockito.verify(po1).disprove(automaton, inputs); + Mockito.verify(po1, Mockito.times(1)).disprove(automaton, inputs); Mockito.verify(po2).disprove(automaton, inputs); - Mockito.verify(po2, Mockito.never()).findCounterExample(automaton, inputs); + Mockito.verify(po2, Mockito.never()).doFindCounterExample(automaton, inputs); } } \ No newline at end of file diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/learner/RefinementCounterLearner.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/learner/RefinementCounterLearner.java new file mode 100644 index 0000000000..d9b091d967 --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/learner/RefinementCounterLearner.java @@ -0,0 +1,95 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.statistic.learner; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.statistic.StatisticLearner; +import de.learnlib.filter.statistic.Counter; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +/** + * Counts the number of hypothesis refinements. + * + * The value of the {@link Counter} returned by {@link #getStatisticalData()} returns the same value as + * Experiment.getRounds(). + * + * @param the automaton type. + * @param the input type. + * @param the output type. + */ +@ParametersAreNonnullByDefault +public class RefinementCounterLearner implements StatisticLearner { + + private final LearningAlgorithm learningAlgorithm; + + private final Counter counter; + + public RefinementCounterLearner(String name, LearningAlgorithm learningAlgorithm) { + counter = new Counter(name, "refinements"); + this.learningAlgorithm = learningAlgorithm; + } + + @Override + public void startLearning() { + learningAlgorithm.startLearning(); + } + + @Override + public boolean refineHypothesis(@Nonnull DefaultQuery ceQuery) { + final boolean refined = learningAlgorithm.refineHypothesis(ceQuery); + if (refined) { + counter.increment(); + } + return refined; + } + + @Nonnull + @Override + public M getHypothesisModel() { + return learningAlgorithm.getHypothesisModel(); + } + + @Nonnull + @Override + public Counter getStatisticalData() { + return counter; + } + + public static class DFARefinementCounterLearner extends RefinementCounterLearner, I, Boolean> + implements DFAStatisticLearner { + + public DFARefinementCounterLearner(String name, LearningAlgorithm, I, Boolean> learningAlgorithm) { + super(name, learningAlgorithm); + } + } + + public static class MealyRefinementCounterLearner + extends RefinementCounterLearner, I, Word> + implements MealyStatisticLearner { + + public MealyRefinementCounterLearner( + String name, + LearningAlgorithm, I, Word> learningAlgorithm) { + super(name, learningAlgorithm); + } + } +} diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java index 16ba109bdf..7e486f2904 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java @@ -69,7 +69,11 @@ protected AbstractSULOmegaOracle(ObservableSUL sul) { * @return the {@link ObservableSUL}. */ public ObservableSUL getSul() { - return sul; + if (sul.canFork()) { + return localSul.get(); + } else { + return sul; + } } @Override @@ -117,11 +121,12 @@ private Pair, Integer> answerQuery(ObservableSUL sul, Word p int prefixLength = prefix.length(); for (Q q: states) { - if (isSameState(inputBuilder.toWord(0, prefixLength), q, inputBuilder.toWord(), nextState)) { + if (isSameState(inputBuilder.toWord(), nextState, inputBuilder.toWord(0, prefixLength), q)) { return Pair.of(outputBuilder.toWord(), i + 1); } prefixLength += loop.length(); } + states.add(nextState); } return Pair.of(null, -1); @@ -244,30 +249,24 @@ public boolean isSameState(Word input1, Integer s1, Word input2, Integer s // in this case the hash codes are equal, now we must check if we accidentally had a hash-collision. final ObservableSUL sul1 = getSul(); final ObservableSUL sul2 = forkedSUL; - sul1.pre(); + + // assert sul1 is already in the correct state + assert s1.equals(sul1.getState().hashCode()); + + sul2.pre(); try { - // step through the first SUL - for (I sym : input1) { - sul1.step(sym); - } - sul2.pre(); - try { - // step through the second SUL - for (I sym : input2) { - sul2.step(sym); - } - - assert sul1.getState().hashCode() == sul2.getState().hashCode(); - assert s1.equals(sul1.getState().hashCode()); - assert s2.equals(sul2.getState().hashCode()); - - // check for state equivalence - return sul1.getState().equals(sul2.getState()); - } finally { - sul2.post(); + // step through the second SUL + for (I sym : input2) { + sul2.step(sym); } + + assert sul1.getState().hashCode() == sul2.getState().hashCode(); + assert s2.equals(sul2.getState().hashCode()); + + // check for state equivalence + return sul1.getState().equals(sul2.getState()); } finally { - sul1.post(); + sul2.post(); } } } diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java index f8b58db8ed..12d6aea442 100644 --- a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java @@ -78,19 +78,19 @@ public DefaultQuery getCounterExample() { return counterExample; } - protected abstract R doFindCounterExample(A hypothesis, Collection inputs); + protected abstract R modelCheck(A hypothesis, Collection inputs); @Nullable @Override - public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { - final A result = doFindCounterExample(hypothesis, inputs); + public DefaultQuery doFindCounterExample(A hypothesis, Collection inputs) { + final A result = modelCheck(hypothesis, inputs); return result != null ? inclusionOracle.findCounterExample(result, inputs) : null; } @Nullable @Override public DefaultQuery disprove(A hypothesis, Collection inputs) { - final R ce = doFindCounterExample(hypothesis, inputs); + final R ce = modelCheck(hypothesis, inputs); return ce != null ? setCounterExample(emptinessOracle.findCounterExample(ce, inputs)) : null; } diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java index 01132a2786..f28a0b0804 100644 --- a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java @@ -45,7 +45,7 @@ public DFAFinitePropertyOracle(P property, } @Override - protected DFA doFindCounterExample(DFA hypothesis, Collection inputs) { + protected DFA modelCheck(DFA hypothesis, Collection inputs) { return modelChecker.findCounterExample(hypothesis, inputs, getProperty()); } } diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java index fa115f0139..f6e86f6fd7 100644 --- a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java @@ -46,7 +46,7 @@ public DFALassoPropertyOracle(P property, } @Override - protected Lasso.DFALasso doFindCounterExample(DFA hypothesis, Collection inputs) { + protected Lasso.DFALasso modelCheck(DFA hypothesis, Collection inputs) { return modelChecker.findCounterExample(hypothesis, inputs, getProperty()); } } diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java index f4d324bb0c..22e6451a8c 100644 --- a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java @@ -48,7 +48,7 @@ public MealyFinitePropertyOracle(P property, } @Override - protected MealyMachine doFindCounterExample(MealyMachine hypothesis, + protected MealyMachine modelCheck(MealyMachine hypothesis, Collection inputs) { return modelChecker.findCounterExample(hypothesis, inputs, getProperty()); diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java index 6980eb8266..1cf2f2c9cc 100644 --- a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java @@ -49,7 +49,7 @@ public MealyLassoPropertyOracle(P property, } @Override - protected Lasso.MealyLasso doFindCounterExample(MealyMachine hypothesis, + protected Lasso.MealyLasso modelCheck(MealyMachine hypothesis, Collection inputs) { return modelChecker.findCounterExample(hypothesis, inputs, getProperty()); } diff --git a/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/PropertyOracleChain.java b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/PropertyOracleChain.java new file mode 100644 index 0000000000..28f262a4da --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/PropertyOracleChain.java @@ -0,0 +1,147 @@ +/* Copyright (C) 2013-2018 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.property; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.oracle.PropertyOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.words.Word; + +/** + * A chain of property oracles. Useful when combining multiple model checking strategies to disprove a property, or when + * finding counter examples to hypotheses. + *

    + * For example you may want to construct a chain that first uses a model checker for monitors, and next, one that uses + * a model checker for full LTL. This strategy tends to give shorter counter examples for properties, and these counter + * examples can be found more quickly (as in smaller hypothesis size and less learning queries). + * + * @param the input type. + * @param the automaton type. + * @param

    the property type. + * @param the output type. + * + * @author Jeroen Meijer + */ +@ParametersAreNonnullByDefault +public class PropertyOracleChain, P, D> implements PropertyOracle { + + private P property; + + private DefaultQuery counterExample; + + private final List> oracles; + + @SafeVarargs + public PropertyOracleChain(PropertyOracle... oracles) { + this(Arrays.asList(oracles)); + } + + public PropertyOracleChain(Collection> oracles) { + this.oracles = new ArrayList<>(oracles); + if (!this.oracles.isEmpty()) { + property = this.oracles.iterator().next().getProperty(); + } else { + property = null; + } + } + + public void addOracle(PropertyOracle oracle) { + assert oracle.getProperty() == null || oracle.getProperty().equals(property); + oracle.setProperty(property); + oracles.add(oracle); + } + + @Override + public DefaultQuery doFindCounterExample(A hypothesis, Collection inputs) { + for (PropertyOracle oracle : oracles) { + DefaultQuery ceQry = oracle.findCounterExample(hypothesis, inputs); + if (ceQry != null) { + return ceQry; + } + } + + return null; + } + + @Nullable + @Override + public DefaultQuery disprove(A hypothesis, Collection inputs) { + for (PropertyOracle oracle : oracles) { + DefaultQuery ceQry = oracle.disprove(hypothesis, inputs); + if (ceQry != null) { + counterExample = ceQry; + return ceQry; + } + } + + return null; + } + + @Override + public void setProperty(P property) { + oracles.forEach(o -> o.setProperty(property)); + this.property = property; + } + + @Override + public P getProperty() { + return property; + } + + @Nullable + @Override + public DefaultQuery getCounterExample() { + return counterExample; + } + + public static class DFAPropertyOracleChain extends PropertyOracleChain, P, Boolean> + implements DFAPropertyOracle { + + @SafeVarargs + public DFAPropertyOracleChain(PropertyOracle, P, Boolean>... oracles) { + super(oracles); + } + + public DFAPropertyOracleChain(Collection, P, Boolean>> oracles) { + super(oracles); + } + } + + public static class MealyPropertyOracleChain + extends PropertyOracleChain, P, Word> + implements MealyPropertyOracle { + + @SafeVarargs + public MealyPropertyOracleChain(PropertyOracle, P, Word>... oracles) { + super(oracles); + } + + public MealyPropertyOracleChain( + Collection, P, Word>> oracles) { + super(oracles); + } + } +} From 510395ae88edd1c50d2412ccd0702ce5c97d67fc Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 17 Oct 2018 09:19:00 +0200 Subject: [PATCH 084/125] Fix/Cleanup example tests - fix compilation error introduced by PR merge - refactor tests to be distinguished by name, rather than package --- .../learnlib-pmd-exclusions.properties | 6 ++-- .../{example1/Example.java => Example1.java} | 6 ++-- .../{example2/Example.java => Example2.java} | 6 ++-- .../{example3/Example.java => Example3.java} | 12 +++---- .../{example1/Example.java => Example1.java} | 6 ++-- .../{example2/Example.java => Example2.java} | 10 +++--- .../{example3/Example.java => Example3.java} | 11 ++++--- .../{example4/Example.java => Example4.java} | 11 ++++--- .../de/learnlib/examples/ExamplesTest.java | 31 ++++++++++++------- 9 files changed, 55 insertions(+), 44 deletions(-) rename examples/src/main/java/de/learnlib/examples/{example1/Example.java => Example1.java} (98%) rename examples/src/main/java/de/learnlib/examples/{example2/Example.java => Example2.java} (98%) rename examples/src/main/java/de/learnlib/examples/{example3/Example.java => Example3.java} (97%) rename examples/src/main/java/de/learnlib/examples/bbc/{example1/Example.java => Example1.java} (98%) rename examples/src/main/java/de/learnlib/examples/bbc/{example2/Example.java => Example2.java} (95%) rename examples/src/main/java/de/learnlib/examples/bbc/{example3/Example.java => Example3.java} (95%) rename examples/src/main/java/de/learnlib/examples/bbc/{example4/Example.java => Example4.java} (95%) diff --git a/build-tools/src/main/resources/learnlib-pmd-exclusions.properties b/build-tools/src/main/resources/learnlib-pmd-exclusions.properties index 19f11a1071..abdc1c608e 100644 --- a/build-tools/src/main/resources/learnlib-pmd-exclusions.properties +++ b/build-tools/src/main/resources/learnlib-pmd-exclusions.properties @@ -41,9 +41,9 @@ de.learnlib.drivers.reflect.ConcreteMethodInput=AvoidThrowingRawExceptionTypes,P de.learnlib.drivers.reflect.SimplePOJODataMapper=AvoidThrowingRawExceptionTypes,PreserveStackTrace # fine for exampels -de.learnlib.examples.example1.Example=SystemPrintln -de.learnlib.examples.example2.Example=SystemPrintln -de.learnlib.examples.example3.Example=SystemPrintln +de.learnlib.examples.Example1=SystemPrintln +de.learnlib.examples.Example2=SystemPrintln +de.learnlib.examples.Example3=SystemPrintln # we want to allow mapping generic RuntimeExceptions de.learnlib.mapper.MappedSUL=AvoidCatchingGenericException diff --git a/examples/src/main/java/de/learnlib/examples/example1/Example.java b/examples/src/main/java/de/learnlib/examples/Example1.java similarity index 98% rename from examples/src/main/java/de/learnlib/examples/example1/Example.java rename to examples/src/main/java/de/learnlib/examples/Example1.java index 7d3333794e..013b699b8f 100644 --- a/examples/src/main/java/de/learnlib/examples/example1/Example.java +++ b/examples/src/main/java/de/learnlib/examples/Example1.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.examples.example1; +package de.learnlib.examples; import java.io.IOException; @@ -41,11 +41,11 @@ * * @author falkhowar */ -public final class Example { +public final class Example1 { private static final int EXPLORATION_DEPTH = 4; - private Example() { + private Example1() { // prevent instantiation } diff --git a/examples/src/main/java/de/learnlib/examples/example2/Example.java b/examples/src/main/java/de/learnlib/examples/Example2.java similarity index 98% rename from examples/src/main/java/de/learnlib/examples/example2/Example.java rename to examples/src/main/java/de/learnlib/examples/Example2.java index 28bf6ef190..b338e3a594 100644 --- a/examples/src/main/java/de/learnlib/examples/example2/Example.java +++ b/examples/src/main/java/de/learnlib/examples/Example2.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.examples.example2; +package de.learnlib.examples; import java.io.IOException; import java.lang.reflect.Method; @@ -48,13 +48,13 @@ * * @author falkhowar */ -public final class Example { +public final class Example2 { private static final double RESET_PROBABILITY = 0.05; private static final int MAX_STEPS = 10000; private static final int RANDOM_SEED = 46346293; - private Example() { + private Example2() { // prevent instantiation } diff --git a/examples/src/main/java/de/learnlib/examples/example3/Example.java b/examples/src/main/java/de/learnlib/examples/Example3.java similarity index 97% rename from examples/src/main/java/de/learnlib/examples/example3/Example.java rename to examples/src/main/java/de/learnlib/examples/Example3.java index 5390d19c81..28eb07fc62 100644 --- a/examples/src/main/java/de/learnlib/examples/example3/Example.java +++ b/examples/src/main/java/de/learnlib/examples/Example3.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.examples.example3; +package de.learnlib.examples; import java.util.ArrayList; import java.util.Collection; @@ -23,7 +23,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.api.query.Query; -import de.learnlib.examples.example2.Example.BoundedStringQueue; +import de.learnlib.examples.Example2.BoundedStringQueue; import de.learnlib.filter.reuse.ReuseCapableOracle; import de.learnlib.filter.reuse.ReuseOracle; import de.learnlib.filter.reuse.ReuseOracle.ReuseOracleBuilder; @@ -37,14 +37,14 @@ /** * This example shows how to use the reuse filter on the {@link BoundedStringQueue} of {@link - * de.learnlib.examples.example2.Example}. + * Example2}. *

    * Please note that there is no equivalence oracle used in this example so the resulting mealy machines are only first * "guesses". * * @author Oliver Bauer */ -public class Example { +public class Example3 { private static final String OFFER_1 = "offer_1"; private static final String OFFER_2 = "offer_2"; @@ -52,7 +52,7 @@ public class Example { private final Alphabet sigma; private final List> initialSuffixes; - public Example() { + public Example3() { sigma = new SimpleAlphabet<>(); sigma.add(OFFER_1); sigma.add(OFFER_2); @@ -65,7 +65,7 @@ public Example() { } public static void main(String[] args) { - Example example = new Example(); + Example3 example = new Example3(); System.out.println("--"); System.out.println("Run experiment 1 (ReuseOracle):"); MealyMachine result1 = example.runExperiment1(); diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/Example1.java similarity index 98% rename from examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java rename to examples/src/main/java/de/learnlib/examples/bbc/Example1.java index f6f3358742..df5c529834 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example1/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example1.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.examples.bbc.example1; +package de.learnlib.examples.bbc; import java.util.function.Function; @@ -48,14 +48,14 @@ * * @author Jeroen Meijer */ -public final class Example { +public final class Example1 { /** * A function that transforms edges in an FSM source to actual input for a DFA. */ public static final Function EDGE_PARSER = s -> s.charAt(0); - private Example() {} + private Example1() {} public static void main(String[] args) { diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/Example2.java similarity index 95% rename from examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java rename to examples/src/main/java/de/learnlib/examples/bbc/Example2.java index 69601fac1a..bd251f7957 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example2/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example2.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.examples.bbc.example2; +package de.learnlib.examples.bbc; import java.util.function.Function; @@ -46,20 +46,20 @@ /** * Run a black-box checking experiment with Mealy machines and straightforward edge semantics. * - * The main difference with {@link de.learnlib.examples.bbc.example3.Example} is how the LTL formula is written. + * The main difference with {@link Example3} is how the LTL formula is written. * - * @see de.learnlib.examples.bbc.example3.Example + * @see Example3 * * @author Jeroen Meijer */ -public final class Example { +public final class Example2 { /** * A function that transforms edges in an FSM source to actual input, and output in the Mealy machine. */ public static final Function EDGE_PARSER = s -> s.charAt(0); - private Example() { } + private Example2() { } public static void main(String[] args) { diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/Example3.java similarity index 95% rename from examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java rename to examples/src/main/java/de/learnlib/examples/bbc/Example3.java index 31786cdd77..2270251a5d 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example3/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example3.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.examples.bbc.example3; +package de.learnlib.examples.bbc; import java.util.function.Function; @@ -28,6 +28,7 @@ import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.examples.LearningExample.MealyLearningExample; +import de.learnlib.examples.bbc.Example2; import de.learnlib.examples.mealy.ExampleTinyMealy; import de.learnlib.oracle.emptiness.MealyLassoEmptinessOracleImpl; import de.learnlib.oracle.equivalence.CExFirstOracle; @@ -46,17 +47,17 @@ /** * Run a black-box checking experiment with a Mealy machine and alternating edge semantics. * - * The main difference with {@link de.learnlib.examples.bbc.example2.Example} is how the LTL formula is written. + * The main difference with {@link Example2} is how the LTL formula is written. * - * @see de.learnlib.examples.bbc.example2.Example + * @see Example2 * * @author Jeroen Meijer */ -public final class Example { +public final class Example3 { public static final Function EDGE_PARSER = s -> s.charAt(0); - private Example() { } + private Example3() { } public static void main(String[] args) { diff --git a/examples/src/main/java/de/learnlib/examples/bbc/example4/Example.java b/examples/src/main/java/de/learnlib/examples/bbc/Example4.java similarity index 95% rename from examples/src/main/java/de/learnlib/examples/bbc/example4/Example.java rename to examples/src/main/java/de/learnlib/examples/bbc/Example4.java index 203ab8bc00..1c4c013e5d 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/example4/Example.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example4.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.examples.bbc.example4; +package de.learnlib.examples.bbc; import java.util.function.Function; @@ -29,6 +29,7 @@ import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.examples.LearningExample.DFALearningExample; +import de.learnlib.examples.bbc.Example1; import de.learnlib.examples.dfa.ExampleTinyDFA; import de.learnlib.oracle.emptiness.DFABFEmptinessOracle; import de.learnlib.oracle.emptiness.DFALassoEmptinessOracleImpl; @@ -54,19 +55,19 @@ /** * Runs a black-box checking experiment for a DFA. *

    - * This example is similar to {@link de.learnlib.examples.bbc.example1.Example}, except that is also uses a monitor + * This example is similar to {@link Example1}, except that is also uses a monitor * to disprove properties for the learned DFA. * * @author Jeroen Meijer */ -public final class Example { +public final class Example4 { /** * A function that transforms edges in an FSM source to actual input for a DFA. */ public static final Function EDGE_PARSER = s -> s.charAt(0); - private Example() {} + private Example4() {} public static void main(String[] args) { @@ -113,6 +114,7 @@ public static void main(String[] args) { // create an LTL property oracle, that also logs stuff // also it chains the property oracle that uses monitors and Buchi automata + @SuppressWarnings("unchecked") PropertyOracle.DFAPropertyOracle ltl = new LoggingPropertyOracle.DFALoggingPropertyOracle<>( new PropertyOracleChain.DFAPropertyOracleChain<>( new DFAFinitePropertyOracle<>("letter==\"b\"", inclusionOracle, emptinessOracle, modelCheckerMonitor), @@ -120,6 +122,7 @@ public static void main(String[] args) { // create an equivalence oracle, that first searches for a counter example using the ltl properties, and next // with the W-method. + @SuppressWarnings("unchecked") DFAEquivalenceOracle eqOracle = new EQOracleChain.DFAEQOracleChain<>( new CExFirstOracle.DFACExFirstOracle<>(ltl), new DFAWpMethodEQOracle<>(mqOracle, 3)); diff --git a/examples/src/test/java/de/learnlib/examples/ExamplesTest.java b/examples/src/test/java/de/learnlib/examples/ExamplesTest.java index c2d5085001..82fb581705 100644 --- a/examples/src/test/java/de/learnlib/examples/ExamplesTest.java +++ b/examples/src/test/java/de/learnlib/examples/ExamplesTest.java @@ -31,6 +31,7 @@ import mockit.MockUp; import net.automatalib.commons.util.system.JVMUtil; import net.automatalib.modelcheckers.ltsmin.LTSminUtil; +import net.automatalib.modelcheckers.ltsmin.LTSminVersion; import net.automatalib.words.Word; import org.testng.SkipException; import org.testng.annotations.BeforeClass; @@ -53,20 +54,26 @@ public void setupAutoClose() { @Test public void testBBCExample1() { - checkLTSminAvailability(); - de.learnlib.examples.bbc.example1.Example.main(new String[0]); + checkLTSminAvailability(3, 0, 0); + de.learnlib.examples.bbc.Example1.main(new String[0]); } @Test public void testBBCExample2() { - checkLTSminAvailability(); - de.learnlib.examples.bbc.example2.Example.main(new String[0]); + checkLTSminAvailability(3, 0, 0); + de.learnlib.examples.bbc.Example2.main(new String[0]); } @Test public void testBBCExample3() { - checkLTSminAvailability(); - de.learnlib.examples.bbc.example3.Example.main(new String[0]); + checkLTSminAvailability(3, 0, 0); + de.learnlib.examples.bbc.Example3.main(new String[0]); + } + + @Test + public void testBBCExample4() { + checkLTSminAvailability(3, 1, 0); + de.learnlib.examples.bbc.Example4.main(new String[0]); } @Test @@ -86,7 +93,7 @@ public void displayHTMLInBrowser(ObservationTable table, SwingUtilities.invokeAndWait(() -> { try { - de.learnlib.examples.example1.Example.main(new String[0]); + Example1.main(new String[0]); } catch (IOException e) { throw new RuntimeException(e); } @@ -98,7 +105,7 @@ public void testExample2() throws InvocationTargetException, InterruptedExceptio checkJVMCompatibility(); SwingUtilities.invokeAndWait(() -> { try { - de.learnlib.examples.example2.Example.main(new String[0]); + Example2.main(new String[0]); } catch (IOException | NoSuchMethodException e) { throw new RuntimeException(e); } @@ -108,7 +115,7 @@ public void testExample2() throws InvocationTargetException, InterruptedExceptio @Test public void testExample3() throws InvocationTargetException, InterruptedException { checkJVMCompatibility(); - SwingUtilities.invokeAndWait(() -> de.learnlib.examples.example3.Example.main(new String[0])); + SwingUtilities.invokeAndWait(() -> Example3.main(new String[0])); } private static void checkJVMCompatibility() { @@ -117,9 +124,9 @@ private static void checkJVMCompatibility() { } } - private static void checkLTSminAvailability() { - if (!LTSminUtil.checkUsable()) { - throw new SkipException("LTSmin is not installed"); + private static void checkLTSminAvailability(int major, int minor, int patch) { + if (!LTSminUtil.supports(LTSminVersion.of(major, minor, patch))) { + throw new SkipException("LTSmin is not installed in the proper version"); } } From 219039b8956f801040bb64e396360415071fb6b7 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 17 Oct 2018 09:43:28 +0200 Subject: [PATCH 085/125] examples: fix PMD violation --- examples/src/main/java/de/learnlib/examples/bbc/Example3.java | 1 - examples/src/main/java/de/learnlib/examples/bbc/Example4.java | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/src/main/java/de/learnlib/examples/bbc/Example3.java b/examples/src/main/java/de/learnlib/examples/bbc/Example3.java index 2270251a5d..b508f52142 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/Example3.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example3.java @@ -28,7 +28,6 @@ import de.learnlib.api.oracle.OmegaMembershipOracle.MealyOmegaMembershipOracle; import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.examples.LearningExample.MealyLearningExample; -import de.learnlib.examples.bbc.Example2; import de.learnlib.examples.mealy.ExampleTinyMealy; import de.learnlib.oracle.emptiness.MealyLassoEmptinessOracleImpl; import de.learnlib.oracle.equivalence.CExFirstOracle; diff --git a/examples/src/main/java/de/learnlib/examples/bbc/Example4.java b/examples/src/main/java/de/learnlib/examples/bbc/Example4.java index 1c4c013e5d..e34f5ffc9f 100644 --- a/examples/src/main/java/de/learnlib/examples/bbc/Example4.java +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example4.java @@ -29,7 +29,6 @@ import de.learnlib.api.oracle.OmegaMembershipOracle.DFAOmegaMembershipOracle; import de.learnlib.api.oracle.PropertyOracle; import de.learnlib.examples.LearningExample.DFALearningExample; -import de.learnlib.examples.bbc.Example1; import de.learnlib.examples.dfa.ExampleTinyDFA; import de.learnlib.oracle.emptiness.DFABFEmptinessOracle; import de.learnlib.oracle.emptiness.DFALassoEmptinessOracleImpl; From 68e93821485f656fcf1369a70196fde8fa0229b2 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 20 Oct 2018 19:28:05 +0200 Subject: [PATCH 086/125] improvements/cleanups to parallel oracles - fixed a bug, where the cached DynamicParallelOracle would not spawn additional threads - changed default timeout of cached threads to 60 seconds (down from 100 seconds) - removed several "withDefault*" methods on oracle builders - removed ParallelOracleBuilder methods which take only a single oracle - added convenience method to create a DynamicParallelOracle given a collection of oracles - added documentation - added test cases --- oracles/parallelism/pom.xml | 4 + .../DynamicParallelOracleBuilder.java | 92 +++++++----- .../oracle/parallelism/ParallelOracle.java | 2 +- .../parallelism/ParallelOracleBuilders.java | 119 ++++++++++++--- .../StaticParallelOracleBuilder.java | 20 +-- .../DynamicParallelOracleTest.java | 135 ++++++++++++++++-- .../parallelism/StaticParallelOracleTest.java | 28 +++- 7 files changed, 308 insertions(+), 92 deletions(-) diff --git a/oracles/parallelism/pom.xml b/oracles/parallelism/pom.xml index 37665a6557..593064df95 100644 --- a/oracles/parallelism/pom.xml +++ b/oracles/parallelism/pom.xml @@ -44,6 +44,10 @@ limitations under the License. net.automatalib automata-api + + net.automatalib + automata-commons-util + com.google.guava diff --git a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracleBuilder.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracleBuilder.java index 3f45f72db8..2df9dfdf6b 100644 --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracleBuilder.java +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracleBuilder.java @@ -15,10 +15,9 @@ */ package de.learnlib.oracle.parallelism; +import java.util.Collection; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -26,8 +25,11 @@ import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; +import com.google.common.base.Preconditions; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.oracle.parallelism.ParallelOracle.PoolPolicy; +import net.automatalib.commons.util.array.ArrayStorage; +import net.automatalib.commons.util.concurrent.ScalingThreadPoolExecutor; /** * Builder class for a {@link DynamicParallelOracle}. @@ -42,9 +44,10 @@ @ParametersAreNonnullByDefault public class DynamicParallelOracleBuilder { - private static final int DEFAULT_KEEP_ALIVE_TIME = 100; - @Nonnull + private static final int DEFAULT_KEEP_ALIVE_TIME = 60; + private final Supplier> oracleSupplier; + private final Collection> oracles; private ExecutorService customExecutor; @Nonnegative private int batchSize = DynamicParallelOracle.BATCH_SIZE; @@ -55,17 +58,18 @@ public class DynamicParallelOracleBuilder { public DynamicParallelOracleBuilder(Supplier> oracleSupplier) { this.oracleSupplier = oracleSupplier; + this.oracles = null; } - @Nonnull - public DynamicParallelOracleBuilder withCustomExecutor(ExecutorService executor) { - this.customExecutor = executor; - return this; + public DynamicParallelOracleBuilder(Collection> oracles) { + Preconditions.checkArgument(!oracles.isEmpty(), "No oracles specified"); + this.oracles = oracles; + this.oracleSupplier = null; } @Nonnull - public DynamicParallelOracleBuilder withDefaultExecutor() { - this.customExecutor = null; + public DynamicParallelOracleBuilder withCustomExecutor(ExecutorService executor) { + this.customExecutor = executor; return this; } @@ -75,30 +79,12 @@ public DynamicParallelOracleBuilder withBatchSize(int batchSize) { return this; } - @Nonnull - public DynamicParallelOracleBuilder withDefaultBatchSize() { - this.batchSize = DynamicParallelOracle.BATCH_SIZE; - return this; - } - @Nonnull public DynamicParallelOracleBuilder withPoolSize(@Nonnegative int poolSize) { this.poolSize = poolSize; return this; } - @Nonnull - public DynamicParallelOracleBuilder withDefaultPoolSize() { - this.poolSize = DynamicParallelOracle.POOL_SIZE; - return this; - } - - @Nonnull - public DynamicParallelOracleBuilder withDefaultPoolPolicy() { - this.poolPolicy = DynamicParallelOracle.POOL_POLICY; - return this; - } - @Nonnull public DynamicParallelOracleBuilder withPoolPolicy(PoolPolicy policy) { this.poolPolicy = policy; @@ -107,25 +93,59 @@ public DynamicParallelOracleBuilder withPoolPolicy(PoolPolicy policy) { @Nonnull public DynamicParallelOracle create() { - ExecutorService executor = customExecutor; - if (executor == null) { + + final Supplier> supplier; + final ExecutorService executor; + + if (oracles != null) { + executor = Executors.newFixedThreadPool(oracles.size()); + supplier = new StaticOracleProvider<>(new ArrayStorage<>(oracles)); + } else if (customExecutor != null) { + executor = customExecutor; + supplier = oracleSupplier; + } else { switch (poolPolicy) { case FIXED: executor = Executors.newFixedThreadPool(poolSize); break; case CACHED: - executor = new ThreadPoolExecutor(0, - poolSize, - DEFAULT_KEEP_ALIVE_TIME, - TimeUnit.SECONDS, - new LinkedBlockingQueue<>()); + executor = new ScalingThreadPoolExecutor(0, poolSize, DEFAULT_KEEP_ALIVE_TIME, TimeUnit.SECONDS); break; default: throw new IllegalStateException("Unknown pool policy: " + poolPolicy); } + supplier = oracleSupplier; } - return new DynamicParallelOracle<>(oracleSupplier, batchSize, executor); + return new DynamicParallelOracle<>(supplier, batchSize, executor); + } + + static class StaticOracleProvider implements Supplier> { + + private final ArrayStorage> oracles; + private int idx; + + StaticOracleProvider(ArrayStorage> oracles) { + this.oracles = oracles; + } + + StaticOracleProvider(Collection> oracles) { + this.oracles = new ArrayStorage<>(oracles.size()); + int idx = 0; + for (final MembershipOracle oracle : oracles) { + this.oracles.set(idx++, oracle); + } + } + + @Override + public synchronized MembershipOracle get() { + if (idx < oracles.size()) { + return oracles.get(idx++); + } + + throw new IllegalStateException( + "The supplier should not have been called more than " + oracles.size() + " times"); + } } } diff --git a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracle.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracle.java index 74ff76282d..e1ba2b929d 100644 --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracle.java +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracle.java @@ -65,7 +65,7 @@ enum PoolPolicy { FIXED, /** * Maintain a "cached" thread pool. Threads will be created on-demand, but will be kept alive for re-use when - * all jobs are processed. However, they will be terminated when they have been idle for 100 seconds. + * all jobs are processed. However, they will be terminated when they have been idle for 60 seconds. *

    * Note that as opposed to {@link Executors#newCachedThreadPool()}, the specified pool size will never be * exceeded. diff --git a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracleBuilders.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracleBuilders.java index 18e8835591..c2a0a09481 100644 --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracleBuilders.java +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracleBuilders.java @@ -15,17 +15,15 @@ */ package de.learnlib.oracle.parallelism; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.List; import java.util.function.Supplier; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; -import com.google.common.base.Suppliers; +import com.google.common.collect.Lists; import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.oracle.parallelism.ParallelOracle.PoolPolicy; /** * Builders for (static and dynamic) parallel oracles. @@ -34,19 +32,17 @@ *

    * Usage examples *

    - * Creating a static parallel oracle with a minimum batch size of 20 and a fixed thread pool, using a membership oracle - * shared by 4 threads: + * Creating a static parallel oracle with a minimum batch size of 20 and a fixed thread pool, using two membership + * oracles (running in two separate threads): *

    - * ParallelOracleBuilders.newStaticParallelOracle(membershipOracle)
    + * ParallelOracleBuilders.newStaticParallelOracle(oracle1, oracle2)
      *      .withMinBatchSize(20)
    - *      .withNumInstances(4)
    - *      .withPoolPolicy(PoolPolicy.FIXED)
      *      .create();
      * 
    *

    * Creating a dynamic parallel oracle with a custom executor, and a batch size of 5, using a shared membership oracle: *

    - * ParallelOracleBuilders.newDynamicParallelOracle(membershipOracle)
    + * ParallelOracleBuilders.newDynamicParallelOracle(() -> membershipOracle)
      *      .withBatchSize(5)
      *      .withCustomExecutor(myExecutor)
      *      .create();
    @@ -71,36 +67,119 @@ private ParallelOracleBuilders() {
             throw new AssertionError("Constructor should not be invoked");
         }
     
    +    /**
    +     * Creates a {@link DynamicParallelOracleBuilder} using the provided supplier. Uses the further specified
    +     * {@link DynamicParallelOracleBuilder#withPoolPolicy(PoolPolicy)} and
    +     * {@link DynamicParallelOracleBuilder#withPoolSize(int)} (or its defaults) to determine the thread pool.
    +     *
    +     * @param oracleSupplier
    +     *         the supplier for spawning new thread-specific membership oracle instances
    +     * @param 
    +     *         input symbol type
    +     * @param 
    +     *         output domain type
    +     *
    +     * @return a preconfigured oracle builder
    +     */
         @Nonnull
    -    public static  DynamicParallelOracleBuilder newDynamicParallelOracle(MembershipOracle sharedOracle) {
    -        return newDynamicParallelOracle(() -> sharedOracle);
    +    public static  DynamicParallelOracleBuilder newDynamicParallelOracle(Supplier> oracleSupplier) {
    +        return new DynamicParallelOracleBuilder<>(oracleSupplier);
         }
     
    +    /**
    +     * Convenience method for {@link #newDynamicParallelOracle(Collection)}.
    +     *
    +     * @param firstOracle
    +     *         the first (mandatory) oracle
    +     * @param otherOracles
    +     *         further (optional) oracles to be used by other threads
    +     * @param 
    +     *         input symbol type
    +     * @param 
    +     *         output domain type
    +     *
    +     * @return a preconfigured oracle builder
    +     */
         @Nonnull
    -    public static  DynamicParallelOracleBuilder newDynamicParallelOracle(Supplier> oracleSupplier) {
    -        return new DynamicParallelOracleBuilder<>(oracleSupplier);
    +    @SafeVarargs
    +    public static  DynamicParallelOracleBuilder newDynamicParallelOracle(MembershipOracle firstOracle,
    +                                                                                     MembershipOracle... otherOracles) {
    +        return newDynamicParallelOracle(Lists.asList(firstOracle, otherOracles));
         }
     
    +    /**
    +     * Creates a {@link DynamicParallelOracleBuilder} using the provided collection of membership oracles. The resulting
    +     * parallel oracle will always use a {@link PoolPolicy#FIXED} pool policy and spawn a separate thread for each of
    +     * the provided oracles (so that the oracles do not need to care about synchronization if they don't share state).
    +     *
    +     * @param oracles
    +     *         the oracle instances to distribute the queries to
    +     * @param 
    +     *         input symbol type
    +     * @param 
    +     *         output domain type
    +     *
    +     * @return the preconfigured oracle builder
    +     */
         @Nonnull
    -    public static  StaticParallelOracleBuilder newStaticParallelOracle(MembershipOracle sharedOracle) {
    -        return newStaticParallelOracle(Suppliers.ofInstance(sharedOracle));
    +    public static  DynamicParallelOracleBuilder newDynamicParallelOracle(Collection> oracles) {
    +        return new DynamicParallelOracleBuilder<>(oracles);
         }
     
    +    /**
    +     * Creates a {@link StaticParallelOracleBuilder} using the provided supplier. Uses the further specified
    +     * {@link StaticParallelOracleBuilder#withPoolPolicy(PoolPolicy)} and
    +     * {@link StaticParallelOracleBuilder#withNumInstances(int)}} (or its defaults) to determine the thread pool.
    +     *
    +     * @param oracleSupplier
    +     *         the supplier for spawning new thread-specific membership oracle instances
    +     * @param 
    +     *         input symbol type
    +     * @param 
    +     *         output domain type
    +     *
    +     * @return a preconfigured oracle builder
    +     */
         @Nonnull
         public static  StaticParallelOracleBuilder newStaticParallelOracle(Supplier> oracleSupplier) {
             return new StaticParallelOracleBuilder<>(oracleSupplier);
         }
     
    +    /**
    +     * Convenience method for {@link #newStaticParallelOracle(Collection)}.
    +     *
    +     * @param firstOracle
    +     *         the first (mandatory) oracle
    +     * @param otherOracles
    +     *         further (optional) oracles to be used by other threads
    +     * @param 
    +     *         input symbol type
    +     * @param 
    +     *         output domain type
    +     *
    +     * @return a preconfigured oracle builder
    +     */
         @Nonnull
         @SafeVarargs
         public static  StaticParallelOracleBuilder newStaticParallelOracle(MembershipOracle firstOracle,
                                                                                        MembershipOracle... otherOracles) {
    -        List> oracles = new ArrayList<>(otherOracles.length + 1);
    -        oracles.add(firstOracle);
    -        Collections.addAll(oracles, otherOracles);
    -        return newStaticParallelOracle(oracles);
    +        return newStaticParallelOracle(Lists.asList(firstOracle, otherOracles));
         }
     
    +    /**
    +     * Creates a {@link StaticParallelOracleBuilder} using the provided collection of membership oracles. The resulting
    +     * parallel oracle will always use a {@link PoolPolicy#FIXED} pool policy and spawn a separate thread for each of
    +     * the provided oracles (so that the oracles do not need to care about synchronization if they don't share state).
    +     *
    +     * @param oracles
    +     *         the oracle instances to distribute the queries to
    +     * @param 
    +     *         input symbol type
    +     * @param 
    +     *         output domain type
    +     *
    +     * @return the preconfigured oracle builder
    +     */
         @Nonnull
         public static  StaticParallelOracleBuilder newStaticParallelOracle(Collection> oracles) {
             return new StaticParallelOracleBuilder<>(oracles);
    diff --git a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracleBuilder.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracleBuilder.java
    index 4bd157ad21..a4ad8e8fca 100644
    --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracleBuilder.java
    +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticParallelOracleBuilder.java
    @@ -24,6 +24,7 @@
     import javax.annotation.Nonnull;
     import javax.annotation.ParametersAreNonnullByDefault;
     
    +import com.google.common.base.Preconditions;
     import de.learnlib.api.oracle.MembershipOracle;
     import de.learnlib.oracle.parallelism.ParallelOracle.PoolPolicy;
     
    @@ -50,6 +51,7 @@ public class StaticParallelOracleBuilder {
         private PoolPolicy poolPolicy = StaticParallelOracle.POOL_POLICY;
     
         public StaticParallelOracleBuilder(Collection> oracles) {
    +        Preconditions.checkArgument(!oracles.isEmpty(), "No oracles specified");
             this.oracles = oracles;
             this.oracleSupplier = null;
         }
    @@ -59,36 +61,18 @@ public StaticParallelOracleBuilder(Supplier> or
             this.oracleSupplier = oracleSupplier;
         }
     
    -    @Nonnull
    -    public StaticParallelOracleBuilder withDefaultMinBatchSize() {
    -        this.minBatchSize = StaticParallelOracle.MIN_BATCH_SIZE;
    -        return this;
    -    }
    -
         @Nonnull
         public StaticParallelOracleBuilder withMinBatchSize(@Nonnegative int minBatchSize) {
             this.minBatchSize = minBatchSize;
             return this;
         }
     
    -    @Nonnull
    -    public StaticParallelOracleBuilder withDefaultPoolPolicy() {
    -        this.poolPolicy = StaticParallelOracle.POOL_POLICY;
    -        return this;
    -    }
    -
         @Nonnull
         public StaticParallelOracleBuilder withPoolPolicy(PoolPolicy policy) {
             this.poolPolicy = policy;
             return this;
         }
     
    -    @Nonnull
    -    public StaticParallelOracleBuilder withDefaultNumInstances() {
    -        this.numInstances = StaticParallelOracle.NUM_INSTANCES;
    -        return this;
    -    }
    -
         @Nonnull
         public StaticParallelOracleBuilder withNumInstances(@Nonnegative int numInstances) {
             this.numInstances = numInstances;
    diff --git a/oracles/parallelism/src/test/java/de/learnlib/oracle/parallelism/DynamicParallelOracleTest.java b/oracles/parallelism/src/test/java/de/learnlib/oracle/parallelism/DynamicParallelOracleTest.java
    index 9e0ac2f384..ac55a42b24 100644
    --- a/oracles/parallelism/src/test/java/de/learnlib/oracle/parallelism/DynamicParallelOracleTest.java
    +++ b/oracles/parallelism/src/test/java/de/learnlib/oracle/parallelism/DynamicParallelOracleTest.java
    @@ -16,12 +16,16 @@
     package de.learnlib.oracle.parallelism;
     
     import java.util.ArrayList;
    +import java.util.Arrays;
     import java.util.Collection;
     import java.util.List;
    +import java.util.concurrent.CountDownLatch;
     import java.util.concurrent.atomic.AtomicBoolean;
    +import java.util.function.Function;
     
     import de.learnlib.api.oracle.MembershipOracle;
     import de.learnlib.api.query.Query;
    +import de.learnlib.oracle.parallelism.DynamicParallelOracleBuilder.StaticOracleProvider;
     import de.learnlib.oracle.parallelism.ParallelOracle.PoolPolicy;
     import net.automatalib.words.Word;
     import org.testng.Assert;
    @@ -51,16 +55,6 @@ public void testDistinctQueries() {
             }
         }
     
    -    private static List createQueries(int numQueries) {
    -        List queries = new ArrayList<>(numQueries);
    -
    -        for (int i = 0; i < numQueries; i++) {
    -            queries.add(new AnswerOnceQuery());
    -        }
    -
    -        return queries;
    -    }
    -
         @Test(expectedExceptions = IllegalStateException.class)
         public void testDuplicateQueries() {
             ParallelOracle oracle = ParallelOracleBuilders.newDynamicParallelOracle(new NullOracle())
    @@ -78,7 +72,126 @@ public void testDuplicateQueries() {
             }
         }
     
    -    private static final class NullOracle implements MembershipOracle {
    +    @Test(timeOut = 2000)
    +    public void testCachedThreadCreation() {
    +        // Explicitly use the supplier version, to test the cached pool creation
    +        testThreadCreation(oracles -> ParallelOracleBuilders.newDynamicParallelOracle(new StaticOracleProvider<>(oracles))
    +                                                            .withBatchSize(1)
    +                                                            .withPoolSize(oracles.size())
    +                                                            .withPoolPolicy(PoolPolicy.CACHED)
    +                                                            .create());
    +    }
    +
    +    @Test(timeOut = 2000)
    +    public void testFixedThreadCreation() {
    +        // Test the fixed pool creation
    +        testThreadCreation(oracles -> ParallelOracleBuilders.newDynamicParallelOracle(oracles)
    +                                                            .withBatchSize(1)
    +                                                            .create());
    +    }
    +
    +    @Test(timeOut = 2000)
    +    public void testCachedThreadScheduling() {
    +        // Explicitly use the supplier version, to test the cached pool creation
    +        testThreadScheduling(oracles -> ParallelOracleBuilders.newDynamicParallelOracle(new StaticOracleProvider<>(oracles))
    +                                                              .withBatchSize(1)
    +                                                              .withPoolSize(2)
    +                                                              .withPoolPolicy(PoolPolicy.CACHED)
    +                                                              .create());
    +
    +    }
    +
    +    @Test(timeOut = 2000)
    +    public void testFixedThreadScheduling() {
    +        // Test the fixed pool creation
    +        testThreadScheduling(oracles -> ParallelOracleBuilders.newDynamicParallelOracle(oracles)
    +                                                              .withBatchSize(1)
    +                                                              .create());
    +    }
    +
    +    private void testThreadCreation(Function, ParallelOracle> parallelOracleFunction) {
    +
    +        final List queries = createQueries(10);
    +        final int expectedThreads = queries.size();
    +
    +        final CountDownLatch latch = new CountDownLatch(expectedThreads);
    +        final NullOracle[] oracles = new NullOracle[expectedThreads];
    +
    +        for (int i = 0; i < expectedThreads; i++) {
    +            oracles[i] = new NullOracle() {
    +
    +                @Override
    +                public void processQueries(Collection> queries) {
    +                    try {
    +                        latch.countDown();
    +                        latch.await();
    +                    } catch (InterruptedException e) {
    +                        throw new IllegalStateException(e);
    +                    }
    +                    super.processQueries(queries);
    +                }
    +            };
    +        }
    +
    +        final ParallelOracle oracle = parallelOracleFunction.apply(Arrays.asList(oracles));
    +
    +        try {
    +            // this method only returns, if 'expectedThreads' threads are spawned, which all decrease the shared latch
    +            oracle.processQueries(queries);
    +        } finally {
    +            oracle.shutdown();
    +        }
    +    }
    +
    +    private void testThreadScheduling(Function, ParallelOracle> parallelOracleFunction) {
    +
    +        final List queries = createQueries(10);
    +        final CountDownLatch latch = new CountDownLatch(queries.size() - 1);
    +
    +        final NullOracle awaitingOracle = new NullOracle() {
    +
    +            @Override
    +            public void processQueries(Collection> queries) {
    +                try {
    +                    latch.await();
    +                } catch (InterruptedException e) {
    +                    throw new IllegalStateException(e);
    +                }
    +                super.processQueries(queries);
    +            }
    +        };
    +
    +        final NullOracle countDownOracle = new NullOracle() {
    +
    +            @Override
    +            public void processQueries(Collection> queries) {
    +                latch.countDown();
    +                super.processQueries(queries);
    +            }
    +        };
    +
    +        final ParallelOracle oracle =
    +                parallelOracleFunction.apply(Arrays.asList(awaitingOracle, countDownOracle));
    +
    +        try {
    +            // this method only returns, if the countDownOracle was scheduled 9 times to unblock the awaitingOracle
    +            oracle.processQueries(queries);
    +        } finally {
    +            oracle.shutdown();
    +        }
    +    }
    +
    +    private static List createQueries(int numQueries) {
    +        List queries = new ArrayList<>(numQueries);
    +
    +        for (int i = 0; i < numQueries; i++) {
    +            queries.add(new AnswerOnceQuery());
    +        }
    +
    +        return queries;
    +    }
    +
    +    private static class NullOracle implements MembershipOracle {
     
             @Override
             public void processQueries(Collection> queries) {
    diff --git a/oracles/parallelism/src/test/java/de/learnlib/oracle/parallelism/StaticParallelOracleTest.java b/oracles/parallelism/src/test/java/de/learnlib/oracle/parallelism/StaticParallelOracleTest.java
    index 513b516dde..80eafe1484 100644
    --- a/oracles/parallelism/src/test/java/de/learnlib/oracle/parallelism/StaticParallelOracleTest.java
    +++ b/oracles/parallelism/src/test/java/de/learnlib/oracle/parallelism/StaticParallelOracleTest.java
    @@ -25,13 +25,15 @@
     import de.learnlib.api.oracle.MembershipOracle;
     import de.learnlib.api.query.DefaultQuery;
     import de.learnlib.api.query.Query;
    +import de.learnlib.oracle.parallelism.DynamicParallelOracleBuilder.StaticOracleProvider;
    +import de.learnlib.oracle.parallelism.ParallelOracle.PoolPolicy;
     import net.automatalib.words.Word;
     import org.testng.Assert;
     import org.testng.annotations.AfterClass;
    -import org.testng.annotations.BeforeClass;
    +import org.testng.annotations.DataProvider;
    +import org.testng.annotations.Factory;
     import org.testng.annotations.Test;
     
    -@Test
     public class StaticParallelOracleTest {
     
         public static final int NUM_ORACLES = 10;
    @@ -39,17 +41,31 @@ public class StaticParallelOracleTest {
         public static final int MAX_WORD_LEN = 30;
     
         private static final Random RANDOM = new Random();
    -    private StaticParallelOracle parallelOracle;
    +    private final StaticParallelOracle parallelOracle;
     
    -    @BeforeClass
    -    public void setUp() {
    +    @Factory(dataProvider = "staticOracles")
    +    public StaticParallelOracleTest(StaticParallelOracle parallelOracle) {
    +        this.parallelOracle = parallelOracle;
    +    }
    +
    +    @DataProvider(name = "staticOracles")
    +    public static Object[][] createStaticParallelOracles() {
             List oracles = new ArrayList<>(NUM_ORACLES);
             for (int i = 0; i < NUM_ORACLES; i++) {
                 oracles.add(new TestMembershipOracle(i));
             }
     
    -        parallelOracle =
    +        final Object[][] result = new Object[2][1];
    +
    +        result[0][0] =
                     ParallelOracleBuilders.newStaticParallelOracle(oracles).withMinBatchSize(MIN_BATCH_SIZE).create();
    +        result[1][0] = ParallelOracleBuilders.newStaticParallelOracle(new StaticOracleProvider<>(oracles))
    +                                             .withMinBatchSize(MIN_BATCH_SIZE)
    +                                             .withNumInstances(NUM_ORACLES)
    +                                             .withPoolPolicy(PoolPolicy.CACHED)
    +                                             .create();
    +
    +        return result;
         }
     
         @AfterClass
    
    From 244ad5012cda5f13632de6bb32feb76cb28f0126 Mon Sep 17 00:00:00 2001
    From: Markus Frohme 
    Date: Sun, 21 Oct 2018 21:36:00 +0200
    Subject: [PATCH 087/125] Aggregate membership queries in DT-based learners
    
    Refactors several DT-based learning algorithms (KV, DT [+VPDA variant], TTT [+VPDA variant]) to collect and prepare as many queries as possible before posing them to a membership oracle. The goal of this change is to allow for a better parallelization in case a parallel oracle is used (which can only split a given batch onto different oracle instances).
    
    This also includes some refactorings among the discrimination tree implementations to share as much code as possible.
    
    fixes #55
    ---
     .../hypothesis/vpda/DTree.java                |  38 ++++---
     .../hypothesis/vpda/TransList.java            |  11 --
     .../vpda/AbstractVPDALearner.java             |  98 +++++++++++-----
     .../discriminationtree/AbstractDTLearner.java |  48 +++++---
     algorithms/active/kearns-vazirani/pom.xml     |   4 +
     .../algorithms/kv/dfa/KearnsVaziraniDFA.java  |  89 ++++++++++-----
     .../kv/mealy/KearnsVaziraniMealy.java         |  98 +++++++++++-----
     .../algorithms/ttt/vpda/TTTLearnerVPDA.java   |   2 +-
     .../ttt/base/AbstractTTTLearner.java          | 107 +++++++++++++-----
     .../ttt/base/BaseTTTDiscriminationTree.java   |  58 +++++-----
     .../model/AbstractDiscriminationTree.java     |  85 +++++++++++++-
     .../AbstractWordBasedDiscriminationTree.java  |  12 +-
     .../datastructure/list/IntrusiveList.java     |  11 ++
     13 files changed, 463 insertions(+), 198 deletions(-)
    
    diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/DTree.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/DTree.java
    index edbb354790..b40c0e6ea3 100644
    --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/DTree.java
    +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/DTree.java
    @@ -15,8 +15,11 @@
      */
     package de.learnlib.algorithms.discriminationtree.hypothesis.vpda;
     
    -import de.learnlib.api.AccessSequenceProvider;
    +import java.util.List;
    +import java.util.function.Predicate;
    +
     import de.learnlib.api.oracle.MembershipOracle;
    +import de.learnlib.api.query.DefaultQuery;
     import de.learnlib.datastructure.discriminationtree.model.AbstractDiscriminationTree;
     import net.automatalib.words.Word;
     
    @@ -32,34 +35,33 @@ public DTree(MembershipOracle oracle) {
             super(new DTNode<>(null, false), oracle);
         }
     
    -    public DTree(DTNode root, MembershipOracle oracle) {
    -        super(root, oracle);
    -    }
    -
         @Override
         public DTNode sift(DTNode start, Word prefix) {
             return sift(start, prefix, true);
         }
     
    -    public DTNode sift(DTNode start, Word as, boolean hard) {
    -        DTNode curr = start;
    -        while (curr.isInner() && (hard || !curr.isTemp())) {
    -            ContextPair discr = curr.getDiscriminator();
    -            Word prefix = discr.getPrefix().concat(as);
    -            Boolean outcome = oracle.answerQuery(prefix, discr.getSuffix());
    +    @Override
    +    public List> sift(List> starts, List> prefixes) {
    +        return sift(starts, prefixes, true);
    +    }
     
    -            curr = curr.getChild(outcome);
    -        }
    +    public DTNode sift(DTNode start, Word as, boolean hard) {
    +        return super.sift(start, as, getSiftPredicate(hard));
    +    }
     
    -        return curr;
    +    public List> sift(List> starts, List> prefixes, boolean hard) {
    +        return super.sift(starts, prefixes, getSiftPredicate(hard));
         }
     
    -    public DTNode sift(AccessSequenceProvider asp) {
    -        return sift(getRoot(), asp, false);
    +    @Override
    +    protected DefaultQuery buildQuery(DTNode node, Word prefix) {
    +        final ContextPair discr = node.getDiscriminator();
    +        final Word completePrefix = discr.getPrefix().concat(prefix);
    +        return new DefaultQuery<>(completePrefix, node.getDiscriminator().getSuffix());
         }
     
    -    public DTNode sift(DTNode start, AccessSequenceProvider asp, boolean hard) {
    -        return sift(start, asp.getAccessSequence(), hard);
    +    private static  Predicate> getSiftPredicate(boolean hard) {
    +        return n -> n.isInner() && (hard || !n.isTemp());
         }
     
     }
    diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/TransList.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/TransList.java
    index 93a98acc1d..5f9e3b3598 100644
    --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/TransList.java
    +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/TransList.java
    @@ -87,15 +87,4 @@ public AbstractHypTrans poll() {
             return result;
         }
     
    -    public int size() {
    -        AbstractHypTrans curr = next;
    -        int i = 0;
    -        while (curr != null) {
    -            i++;
    -            curr = curr.getNextElement();
    -        }
    -
    -        return i;
    -    }
    -
     }
    diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/AbstractVPDALearner.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/AbstractVPDALearner.java
    index 05dd15c22e..16923b9d0e 100644
    --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/AbstractVPDALearner.java
    +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/AbstractVPDALearner.java
    @@ -15,6 +15,11 @@
      */
     package de.learnlib.algorithms.discriminationtree.vpda;
     
    +import java.util.ArrayList;
    +import java.util.Collections;
    +import java.util.Iterator;
    +import java.util.List;
    +
     import de.learnlib.algorithms.discriminationtree.hypothesis.vpda.AbstractHypTrans;
     import de.learnlib.algorithms.discriminationtree.hypothesis.vpda.ContextPair;
     import de.learnlib.algorithms.discriminationtree.hypothesis.vpda.DTNode;
    @@ -63,7 +68,7 @@ public AbstractVPDALearner(VPDAlphabet alphabet, MembershipOracle
         @Override
         public void startLearning() {
             HypLoc initLoc = hypothesis.initialize();
    -        DTNode leaf = dtree.sift(initLoc);
    +        DTNode leaf = dtree.sift(initLoc.getAccessSequence());
             link(leaf, initLoc);
             initializeLocation(initLoc);
     
    @@ -128,16 +133,10 @@ protected void initializeLocation(HypLoc loc) {
         }
     
         protected void closeTransitions() {
    -        AbstractHypTrans next;
             UnorderedCollection> 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/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java index e8329a3ae0..b84123b441 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 @@ -149,9 +149,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 +173,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); + } } } diff --git a/algorithms/active/kearns-vazirani/pom.xml b/algorithms/active/kearns-vazirani/pom.xml index 1550c01c39..1a7d977394 100644 --- a/algorithms/active/kearns-vazirani/pom.xml +++ b/algorithms/active/kearns-vazirani/pom.xml @@ -43,6 +43,10 @@ limitations under the License. net.automatalib automata-core + + net.automatalib + automata-commons-util + de.learnlib diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java index f3ecebc128..50bbc53bb5 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java @@ -17,7 +17,9 @@ import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Collections; import java.util.Deque; +import java.util.Iterator; import java.util.List; import com.github.misberner.buildergen.annotations.GenerateBuilder; @@ -35,6 +37,7 @@ import de.learnlib.datastructure.discriminationtree.model.LCAInfo; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.commons.util.array.ArrayStorage; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -172,6 +175,9 @@ private void splitState(StateInfo stateInfo, private void updateTransitions(List transList, AbstractWordBasedDTNode> oldDtTarget) { // TODO: replace with primitive specialization int numTrans = transList.size(); + + final List> transAs = new ArrayList<>(numTrans); + for (int i = 0; i < numTrans; i++) { long encodedTrans = transList.get(i); @@ -181,8 +187,18 @@ private void updateTransitions(List transList, StateInfo sourceInfo = stateInfos.get(sourceState); I symbol = alphabet.getSymbol(transIdx); - StateInfo succ = sift(oldDtTarget, sourceInfo.accessSequence.append(symbol)); - setTransition(sourceState, transIdx, succ); + transAs.add(sourceInfo.accessSequence.append(symbol)); + } + + final List> succs = sift(Collections.nCopies(numTrans, oldDtTarget), transAs); + + for (int i = 0; i < numTrans; i++) { + long encodedTrans = transList.get(i); + + int sourceState = (int) (encodedTrans >> StateInfo.INTEGER_WORD_WIDTH); + int transIdx = (int) (encodedTrans); + + setTransition(sourceState, transIdx, succs.get(i)); } } @@ -225,13 +241,17 @@ private void initState(StateInfo stateInfo) { int state = stateInfo.id; Word accessSequence = stateInfo.accessSequence; + final ArrayStorage> transAs = new ArrayStorage<>(alphabetSize); + for (int i = 0; i < alphabetSize; i++) { I sym = alphabet.getSymbol(i); + transAs.set(i, accessSequence.append(sym)); + } - Word transAs = accessSequence.append(sym); + final List> succs = sift(transAs); - StateInfo succ = sift(transAs); - setTransition(state, i, succ); + for (int i = 0; i < alphabetSize; i++) { + setTransition(state, i, succs.get(i)); } } @@ -240,27 +260,36 @@ private void setTransition(int state, int symIdx, StateInfo succInfo hypothesis.setTransition(state, symIdx, succInfo.id); } - private StateInfo sift(Word prefix) { - return sift(discriminationTree.getRoot(), prefix); + private List> sift(List> prefixes) { + return sift(Collections.nCopies(prefixes.size(), discriminationTree.getRoot()), prefixes); } - private StateInfo sift(AbstractWordBasedDTNode> start, - Word prefix) { - AbstractWordBasedDTNode> leaf = discriminationTree.sift(start, prefix); + private List> sift(List>> starts, + List> prefixes) { - StateInfo succStateInfo = leaf.getData(); - if (succStateInfo == null) { - // Special case: this is the *first* state of a different - // acceptance than the initial state - boolean initAccepting = hypothesis.isAccepting(hypothesis.getIntInitialState()); - succStateInfo = createState(prefix, !initAccepting); - leaf.setData(succStateInfo); - succStateInfo.dtNode = leaf; + final List>> leaves = + discriminationTree.sift(starts, prefixes); + final ArrayStorage> result = new ArrayStorage<>(leaves.size()); - initState(succStateInfo); + for (int i = 0; i < leaves.size(); i++) { + final AbstractWordBasedDTNode> leaf = leaves.get(i); + + StateInfo succStateInfo = leaf.getData(); + if (succStateInfo == null) { + // Special case: this is the *first* state of a different + // acceptance than the initial state + boolean initAccepting = hypothesis.isAccepting(hypothesis.getIntInitialState()); + succStateInfo = createState(prefixes.get(i), !initAccepting); + leaf.setData(succStateInfo); + succStateInfo.dtNode = leaf; + + initState(succStateInfo); + } + + result.set(i, succStateInfo); } - return succStateInfo; + return result; } @Override @@ -280,14 +309,22 @@ public void addAlphabetSymbol(I symbol) { } // use new list to prevent concurrent modification exception - for (final StateInfo si : new ArrayList<>(this.stateInfos)) { - final int state = si.id; - final Word accessSequence = si.accessSequence; - final Word transAs = accessSequence.append(symbol); + final List> transAs = new ArrayList<>(this.stateInfos.size()); + for (final StateInfo si : this.stateInfos) { + transAs.add(si.accessSequence.append(symbol)); + } + + final List> succs = sift(transAs); - final StateInfo succ = sift(transAs); - setTransition(state, inputIdx, succ); + final Iterator> stateIter = this.stateInfos.iterator(); + final Iterator> leafsIter = succs.iterator(); + + while (stateIter.hasNext() && leafsIter.hasNext()) { + setTransition(stateIter.next().id, inputIdx, leafsIter.next()); } + + assert !stateIter.hasNext(); + assert !leafsIter.hasNext(); } @Override diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java index 1585505e01..ebf61db9cb 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java @@ -17,7 +17,9 @@ import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Collections; import java.util.Deque; +import java.util.Iterator; import java.util.List; import java.util.Objects; @@ -185,6 +187,9 @@ private Word newOutcome(O transOutput, Word succOutcome) { private void updateTransitions(List transList, AbstractWordBasedDTNode, StateInfo>> oldDtTarget) { // TODO: replace with primitive specialization int numTrans = transList.size(); + + final List> transAs = new ArrayList<>(numTrans); + for (int i = 0; i < numTrans; i++) { long encodedTrans = transList.get(i); @@ -194,10 +199,21 @@ private void updateTransitions(List transList, StateInfo> sourceInfo = stateInfos.get(sourceState); I symbol = alphabet.getSymbol(transIdx); - StateInfo> succInfo = sift(oldDtTarget, sourceInfo.accessSequence.append(symbol)); + transAs.add(sourceInfo.accessSequence.append(symbol)); + } + + final List>> succs = sift(Collections.nCopies(numTrans, oldDtTarget), transAs); + + for (int i = 0; i < numTrans; i++) { + long encodedTrans = transList.get(i); + + int sourceState = (int) (encodedTrans >> StateInfo.INTEGER_WORD_WIDTH); + int transIdx = (int) (encodedTrans); - O output = hypothesis.getTransition(sourceState, transIdx).getOutput(); - setTransition(sourceState, transIdx, succInfo, output); + setTransition(sourceState, + transIdx, + succs.get(i), + hypothesis.getTransition(sourceState, transIdx).getOutput()); } } @@ -238,15 +254,20 @@ private void initState(StateInfo> stateInfo) { int state = stateInfo.id; Word accessSequence = stateInfo.accessSequence; + final List> transAs = new ArrayList<>(alphabetSize); + final List>> outputQueries = new ArrayList<>(alphabetSize); + for (int i = 0; i < alphabetSize; i++) { I sym = alphabet.getSymbol(i); + transAs.add(accessSequence.append(sym)); + outputQueries.add(new DefaultQuery<>(accessSequence, Word.fromLetter(sym))); + } - O output = oracle.answerQuery(accessSequence, Word.fromLetter(sym)).firstSymbol(); - - Word transAs = accessSequence.append(sym); + final List>> succs = sift(transAs); + this.oracle.processQueries(outputQueries); - StateInfo> succInfo = sift(transAs); - setTransition(state, i, succInfo, output); + for (int i = 0; i < alphabetSize; i++) { + setTransition(state, i, succs.get(i), outputQueries.get(i).getOutput().firstSymbol()); } } @@ -255,27 +276,35 @@ private void setTransition(int state, int symIdx, StateInfo> succInfo hypothesis.setTransition(state, symIdx, succInfo.id, output); } - private StateInfo> sift(Word prefix) { - return sift(discriminationTree.getRoot(), prefix); + private List>> sift(List> prefixes) { + return sift(Collections.nCopies(prefixes.size(), discriminationTree.getRoot()), prefixes); } - private StateInfo> sift(AbstractWordBasedDTNode, StateInfo>> start, - Word prefix) { - AbstractWordBasedDTNode, StateInfo>> leaf = discriminationTree.sift(start, prefix); + private List>> sift(List, StateInfo>>> starts, + List> prefixes) { + + final List, StateInfo>>> leaves = + discriminationTree.sift(starts, prefixes); + final List>> result = new ArrayList<>(leaves.size()); - StateInfo> succStateInfo = leaf.getData(); - if (succStateInfo == null) { - // Special case: this is the *first* state with a different output - // for some discriminator - succStateInfo = createState(prefix); + for (int i = 0; i < leaves.size(); i++) { + final AbstractWordBasedDTNode, StateInfo>> leaf = leaves.get(i); - leaf.setData(succStateInfo); - succStateInfo.dtNode = leaf; + StateInfo> succStateInfo = leaf.getData(); + if (succStateInfo == null) { + // Special case: this is the *first* state of a different + // acceptance than the initial state + succStateInfo = createState(prefixes.get(i)); + leaf.setData(succStateInfo); + succStateInfo.dtNode = leaf; - initState(succStateInfo); + initState(succStateInfo); + } + + result.add(succStateInfo); } - return succStateInfo; + return result; } @Override @@ -295,15 +324,26 @@ public void addAlphabetSymbol(I symbol) { } // use new list to prevent concurrent modification exception - for (final StateInfo> si : new ArrayList<>(this.stateInfos)) { - final int state = si.id; - final Word accessSequence = si.accessSequence; - final Word transAs = accessSequence.append(symbol); + final List> transAs = new ArrayList<>(this.stateInfos.size()); + final List>> outputQueries = new ArrayList<>(this.stateInfos.size()); + + for (final StateInfo> si : this.stateInfos) { + transAs.add(si.accessSequence.append(symbol)); + outputQueries.add(new DefaultQuery<>(si.accessSequence, Word.fromLetter(symbol))); + } + + final List>> succs = sift(transAs); + this.oracle.processQueries(outputQueries); - final O output = oracle.answerQuery(accessSequence, Word.fromLetter(symbol)).firstSymbol(); + final Iterator>> stateIter = this.stateInfos.iterator(); + final Iterator>> leafsIter = succs.iterator(); + final Iterator>> outputsIter = outputQueries.iterator(); - final StateInfo> succ = sift(transAs); - setTransition(state, inputIdx, succ, output); + while (stateIter.hasNext() && leafsIter.hasNext()) { + setTransition(stateIter.next().id, + inputIdx, + leafsIter.next(), + outputsIter.next().getOutput().firstSymbol()); } } diff --git a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java index dbc80e1f72..6041d949df 100644 --- a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java +++ b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java @@ -624,7 +624,7 @@ protected void determinize(State> state, Word suffix) { if (!alphabet.isCallSymbol(sym)) { AbstractHypTrans trans = hypothesis.getInternalTransition(curr, sym); if (!trans.isTree() && !trans.getNonTreeTarget().isLeaf()) { - updateDTTarget(trans, true); + updateDTTargets(Collections.singletonList(trans), true); } } curr = hypothesis.getSuccessor(curr, sym); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java index ac804355e1..ca48052717 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java @@ -149,7 +149,7 @@ public void startLearning() { } TTTState init = hypothesis.initialize(); - AbstractBaseDTNode initNode = dtree.sift(init, false); + AbstractBaseDTNode initNode = dtree.sift(init.getAccessSequence(), false); link(initNode, init); initializeState(init); @@ -765,22 +765,58 @@ private void createNewState(AbstractBaseDTNode newNode) { } protected void closeTransitions() { - TTTTransition next; UnorderedCollection> newStateNodes = new UnorderedCollection<>(); do { - while ((next = openTransitions.poll()) != null) { - AbstractBaseDTNode newStateNode = closeTransition(next, false); - if (newStateNode != null) { - newStateNodes.add(newStateNode); - } - } + newStateNodes.addAll(closeTransitions(openTransitions, false)); if (!newStateNodes.isEmpty()) { addNewStates(newStateNodes); } } while (!openTransitions.isEmpty()); } + /** + * 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 transList + * the list of transitions + * + * @return a collection containing the reached leaves of transitions that needed sifting + */ + private List> closeTransitions(IncomingList transList, boolean hard) { + + final List> transToSift = new ArrayList<>(transList.size()); + + TTTTransition t; + while ((t = transList.poll()) != null) { + if (!t.isTree()) { + transToSift.add(t); + } + } + + if (transToSift.isEmpty()) { + return Collections.emptyList(); + } + + final Iterator> leavesIter = updateDTTargets(transToSift, hard).iterator(); + final List> result = new ArrayList<>(transToSift.size()); + + for (final TTTTransition transition : transToSift) { + final AbstractBaseDTNode node = leavesIter.next(); + if (node.isLeaf() && node.getData() == null && transition.getNextElement() == null) { + result.add(node); + } + } + + assert !leavesIter.hasNext(); + return result; + } + private void addNewStates(UnorderedCollection> newStateNodes) { AbstractBaseDTNode minTransNode = null; TTTTransition minTrans = null; @@ -818,25 +854,6 @@ protected TTTState makeTree(TTTTransition trans) { return state; } - /** - * Ensures that the specified transition points to a leaf-node. If the transition is a tree transition, this method - * has no effect. - * - * @param trans - * the transition - */ - private AbstractBaseDTNode closeTransition(TTTTransition trans, boolean hard) { - if (trans.isTree()) { - return null; - } - - AbstractBaseDTNode node = updateDTTarget(trans, hard); - if (node.isLeaf() && node.getData() == null && trans.getNextElement() == null) { - return node; - } - return null; - } - /** * Updates the transition to point to either a leaf in the discrimination tree, or---if the {@code hard} parameter * is set to {@code false}---to a block root. @@ -854,12 +871,46 @@ private AbstractBaseDTNode updateDTTarget(TTTTransition transition, } AbstractBaseDTNode dt = transition.getNonTreeTarget(); - dt = dtree.sift(dt, transition, hard); + dt = dtree.sift(dt, transition.getAccessSequence(), hard); transition.setNonTreeTarget(dt); return dt; } + /** + * Bulk version of {@link #updateDTTarget(TTTTransition, boolean)}. + */ + private List> updateDTTargets(List> transitions, boolean hard) { + + final List> nodes = new ArrayList<>(transitions.size()); + final List> prefixes = new ArrayList<>(transitions.size()); + + for (final TTTTransition t : transitions) { + if (!t.isTree()) { + AbstractBaseDTNode dt = t.getNonTreeTarget(); + + nodes.add(dt); + prefixes.add(t.getAccessSequence()); + } + } + + final Iterator> leavesIter = dtree.sift(nodes, prefixes, hard).iterator(); + final List> result = new ArrayList<>(transitions.size()); + + for (final TTTTransition t : transitions) { + if (t.isTree()) { + result.add(t.getTreeTarget().dtLeaf); + } else { + AbstractBaseDTNode leaf = leavesIter.next(); + t.setNonTreeTarget(leaf); + result.add(leaf); + } + } + + assert !leavesIter.hasNext(); + return result; + } + /** * Performs a membership query. * diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BaseTTTDiscriminationTree.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BaseTTTDiscriminationTree.java index b84ab9d0f1..42c10095fe 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BaseTTTDiscriminationTree.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BaseTTTDiscriminationTree.java @@ -15,12 +15,14 @@ */ package de.learnlib.algorithms.ttt.base; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.function.Predicate; import java.util.function.Supplier; -import de.learnlib.api.AccessSequenceProvider; import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.discriminationtree.model.AbstractDiscriminationTree; import net.automatalib.visualization.VisualizationHelper; import net.automatalib.words.Word; @@ -45,48 +47,30 @@ public BaseTTTDiscriminationTree(MembershipOracle oracle, AbstractBaseDTNo super(root, oracle); } - /** - * Sifts an access sequence provided by an object into the tree, starting at the root. This operation performs a - * "hard" sift, i.e., it will not stop at temporary nodes. - * - * @param asp - * the object providing the access sequence - * - * @return the leaf resulting from the sift operation - */ - public AbstractBaseDTNode sift(AccessSequenceProvider asp) { - return sift(asp, true); - } - /** * Sifts an access sequence provided by an object into the tree, starting at the root. This can either be a "soft" * sift, which stops either at the leaf or at the first temporary node, or a "hard" sift, stopping only at a * leaf. * - * @param asp + * @param word * the object providing the access sequence + * @param hard + * flag, whether this should be a soft or a hard sift + * + * @return the leaf resulting from the sift operation */ - public AbstractBaseDTNode sift(AccessSequenceProvider asp, boolean hard) { - return sift(asp.getAccessSequence(), hard); - } - public AbstractBaseDTNode sift(Word word, boolean hard) { return sift(root, word, hard); } - public AbstractBaseDTNode sift(AbstractBaseDTNode start, Word word, boolean hard) { - AbstractBaseDTNode curr = start; - - while (!curr.isLeaf() && (hard || !curr.isTemp())) { - D outcome = super.oracle.answerQuery(word, curr.getDiscriminator()); - curr = curr.child(outcome); - } - - return curr; + public AbstractBaseDTNode sift(AbstractBaseDTNode start, Word prefix, boolean hard) { + return super.sift(start, prefix, getSiftPredicate(hard)); } - public AbstractBaseDTNode sift(AbstractBaseDTNode start, AccessSequenceProvider asp, boolean hard) { - return sift(start, asp.getAccessSequence(), hard); + public List> sift(List> starts, + List> prefixes, + boolean hard) { + return super.sift(starts, prefixes, getSiftPredicate(hard)); } @Override @@ -94,6 +78,20 @@ public AbstractBaseDTNode sift(AbstractBaseDTNode start, Word pre return sift(start, prefix, true); } + @Override + public List> sift(List> starts, List> prefixes) { + return sift(starts, prefixes, true); + } + + @Override + protected DefaultQuery buildQuery(AbstractBaseDTNode node, Word prefix) { + return new DefaultQuery<>(prefix, node.getDiscriminator()); + } + + private static Predicate> getSiftPredicate(boolean hard) { + return n -> !n.isLeaf() && (hard || !n.isTemp()); + } + @Override public VisualizationHelper, Entry>> getVisualizationHelper() { return new VisualizationHelper, Entry>>() { diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDiscriminationTree.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDiscriminationTree.java index a355a3b2be..4752ed42b5 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDiscriminationTree.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDiscriminationTree.java @@ -17,14 +17,21 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.BitSet; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.RandomAccess; +import java.util.function.Predicate; import com.google.common.collect.Iterables; import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.commons.util.BitSetIterator; +import net.automatalib.commons.util.array.ArrayStorage; import net.automatalib.graphs.Graph; import net.automatalib.util.graphs.traversal.GraphTraversal; import net.automatalib.visualization.DefaultVisualizationHelper; @@ -62,7 +69,81 @@ public N sift(Word prefix) { return sift(root, prefix); } - public abstract N sift(N start, Word prefix); + public N sift(N start, Word prefix) { + return sift(start, prefix, n -> !n.isLeaf()); + } + + protected N sift(N start, Word prefix, Predicate continueExploring) { + N curr = start; + + while (continueExploring.test(curr)) { + final DefaultQuery query = buildQuery(curr, prefix); + oracle.processQuery(query); + curr = curr.child(query.getOutput()); + } + + return curr; + } + + public List sift(List starts, List> prefixes) { + assert starts.size() == prefixes.size(); + return sift(starts, prefixes, n -> !n.isLeaf()); + } + + protected List sift(List starts, List> prefixes, Predicate continueExploring) { + assert starts.size() == prefixes.size(); + + if (starts.isEmpty()) { + return Collections.emptyList(); + } else if (starts.size() == 1) { + return Collections.singletonList(sift(starts.get(0), prefixes.get(0), continueExploring)); + } + + final int size = starts.size(); + final ArrayStorage result = new ArrayStorage<>(starts); + final BitSet activeVector = new BitSet(size); + + for (int i = 0; i < size; i++) { + activeVector.set(i, continueExploring.test(result.get(i))); + } + + final List> prefixStorage; + if (prefixes instanceof RandomAccess) { + prefixStorage = prefixes; + } else { + prefixStorage = new ArrayStorage<>(prefixes); + } + + while (!activeVector.isEmpty()) { + + final List> queries = new ArrayList<>(activeVector.cardinality()); + final BitSetIterator preIter = new BitSetIterator(activeVector); + + while (preIter.hasNext()) { + final int idx = preIter.nextInt(); + queries.add(buildQuery(result.get(idx), prefixStorage.get(idx))); + } + + oracle.processQueries(queries); + + final BitSetIterator postIter = new BitSetIterator(activeVector); + final Iterator> responseIter = queries.iterator(); + + while (postIter.hasNext()) { + final int idx = postIter.nextInt(); + final N current = result.get(idx); + final O out = responseIter.next().getOutput(); + final N child = current.child(out); + result.set(idx, child); + + if (!continueExploring.test(child)) { + activeVector.clear(idx); + } + } + } + + return result; + } public N getRoot() { return root; @@ -148,6 +229,8 @@ public LCAInfo lcaInfo(N node1, N node2) { return new LCAInfo<>(curr1, out1, out2, swap); } + protected abstract DefaultQuery buildQuery(N node, Word prefix); + /* * AutomataLib Graph API */ diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDiscriminationTree.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDiscriminationTree.java index b083b618b3..a3e0ba2f0a 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDiscriminationTree.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDiscriminationTree.java @@ -16,6 +16,7 @@ package de.learnlib.datastructure.discriminationtree.model; import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; import net.automatalib.words.Word; /** @@ -38,14 +39,7 @@ public AbstractWordBasedDiscriminationTree(AbstractWordBasedDTNode root } @Override - public AbstractWordBasedDTNode sift(AbstractWordBasedDTNode start, Word prefix) { - AbstractWordBasedDTNode curr = start; - - while (!curr.isLeaf()) { - O out = super.oracle.answerQuery(prefix, curr.getDiscriminator()); - curr = curr.child(out); - } - - return curr; + protected DefaultQuery buildQuery(AbstractWordBasedDTNode node, Word prefix) { + return new DefaultQuery<>(prefix, node.getDiscriminator()); } } diff --git a/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveList.java b/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveList.java index ba1dac26f3..d46e34371d 100644 --- a/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveList.java +++ b/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveList.java @@ -42,6 +42,17 @@ public T choose() { return next; } + public int size() { + T curr = next; + int i = 0; + while (curr != null) { + i++; + curr = curr.getNextElement(); + } + + return i; + } + @Override public Iterator iterator() { return new ListIterator(next); From 066c70a369de67adf42c7cab27e31d4730537022 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 24 Oct 2018 11:56:31 +0200 Subject: [PATCH 088/125] bump dependency versions --- pom.xml | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pom.xml b/pom.xml index e5f9dee909..40bcb47317 100644 --- a/pom.xml +++ b/pom.xml @@ -192,43 +192,44 @@ limitations under the License. 1.8 3.0.1 - 3.0.0 + 3.1.0 3.0.0 - 2.17 - 3.7.0 + 3.0.0 + 3.8.0 4.3.0 3.1.1 - 1.4.1 + 3.0.0-M1 + 3.0.0-M2 1.6.0 - 2.21.0 + 2.22.1 1.6 - 2.9 - 0.8.0 + 3.0.0 + 0.8.2 3.0.1 1.0.0 3.10.0 2.5.3 3.0.2 - 1.1 - 3.6 + 3.0.0 + 3.7.1 3.0.1 - 3.1.3.1 - 2.20 + 3.1.7 + 2.22.1 1.1.0 0.8.0-SNAPSHOT 0.1 1.9 - 8.1 + 8.14 3.0.2 - 24.0-jre + 27.0-jre 1.43 1.2.3 1.7 - 2.18.3 + 2.23.0 1.7.25 - 6.11 + 6.14.3 http://docs.oracle.com/javase/8/docs/api/ From 6c0a2ef2c04a6d901d5ccea1553d5bd12bb67c31 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 24 Oct 2018 11:57:10 +0200 Subject: [PATCH 089/125] explicitly state deploy-plugin version --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 40bcb47317..f3d636107d 100644 --- a/pom.xml +++ b/pom.xml @@ -642,6 +642,11 @@ limitations under the License. maven-dependency-plugin ${dependency-plugin.version} + + org.apache.maven.plugins + maven-deploy-plugin + ${deploy-plugin.version} + org.apache.maven.plugins maven-checkstyle-plugin From 064bb27d603c4a1b70ba67533d7ff1322ec4533c Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 24 Oct 2018 11:57:31 +0200 Subject: [PATCH 090/125] workaround false-positive reports from SpotBugs on Java 11 --- .../src/main/resources/learnlib-spotbugs-exclusions.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml b/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml index aed280d934..c2882415ce 100644 --- a/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml +++ b/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml @@ -34,4 +34,12 @@ limitations under the License. --> + + + + + + + + \ No newline at end of file From 0f08b96e22a5477904b25ec63fcb6ddbfabc29ea Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 24 Oct 2018 11:58:25 +0200 Subject: [PATCH 091/125] fix JavaDoc generation on Java 11 is not a valid HTML5 tag --- .../api/algorithm/LearningAlgorithm.java | 2 +- .../api/oracle/EquivalenceOracle.java | 8 ++++---- .../counterexamples/GlobalSuffixFinder.java | 4 ++-- .../counterexamples/GlobalSuffixFinders.java | 12 +++++------ .../counterexamples/LocalSuffixFinder.java | 20 +++++++++---------- .../counterexamples/LocalSuffixFinders.java | 6 +++--- .../MutableObservationTable.java | 4 ++-- .../learnlib/filter/reuse/tree/ReuseEdge.java | 8 ++++---- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java b/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java index 8c2dbffa9c..6d0a171168 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java +++ b/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java @@ -55,7 +55,7 @@ public interface LearningAlgorithm { * @param ceQuery * the query which exposes diverging behavior, as posed to the real SUL (i.e. with the SULs output). * - * @return true if the counterexample triggered a refinement of the hypothesis, false otherwise + * @return {@code true} if the counterexample triggered a refinement of the hypothesis, {@code false} otherwise * (i.e., it was no counterexample). */ boolean refineHypothesis(@Nonnull DefaultQuery ceQuery); diff --git a/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java b/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java index cdae480635..a21e36ee5c 100644 --- a/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java @@ -33,7 +33,7 @@ *

    * CAVEAT: Equivalence oracles serve as an abstraction to tackle the (generally undecidable) problem of black-box * equivalence testing. The contract imposed by this interface is that results returned by the {@link - * #findCounterExample(Object, Collection)} method are in fact counterexamples, BUT a null result + * #findCounterExample(Object, Collection)} method are in fact counterexamples, BUT a {@code null} result * signalling no counterexample was found does not mean that there can be none. * * @param @@ -52,15 +52,15 @@ public interface EquivalenceOracle { /** * Searches for a counterexample disproving the subjected hypothesis. A counterexample is query which, when * performed on the SUL, yields a different output than what was predicted by the hypothesis. If no counterexample - * could be found (this does not necessarily mean that none exists), null is returned. + * could be found (this does not necessarily mean that none exists), {@code null} is returned. * * @param hypothesis * the conjecture * @param inputs * the set of inputs to consider, this should be a subset of the input alphabet of the provided hypothesis * - * @return a query exposing different behavior, or null if no counterexample could be found. In case a - * non-null value is returned, the output field in the {@link DefaultQuery} contains the SUL output for the + * @return a query exposing different behavior, or {@code null} if no counterexample could be found. In case a + * non-{@code null} value is returned, the output field in the {@link DefaultQuery} contains the SUL output for the * respective query. */ @Nullable diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinder.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinder.java index d9bca93036..8ef5683206 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinder.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinder.java @@ -31,8 +31,8 @@ *

    * Please note that the type parameters of these class only constitute upper bounds for the respective input * symbol and output classes, denoting the requirements of the process in general. A suffix finder which does not - * exploit any properties of the used classes will implement this interface with <Object,Object> generic - * arguments only. The genericity is still maintained due to the RI and RO generic parameters in the + * exploit any properties of the used classes will implement this interface with {@code } generic + * arguments only. The genericity is still maintained due to the {@code RI} and {@code RO} generic parameters in the * {@link #findSuffixes(Query, AccessSequenceTransformer, SuffixOutput, MembershipOracle)} method. * * @param diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinders.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinders.java index bd9c31c7fb..9feb93bbca 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinders.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinders.java @@ -129,7 +129,7 @@ private GlobalSuffixFinders() { /** * Transforms a {@link LocalSuffixFinder} into a global one. This is a convenience method, behaving like - * fromLocalFinder(localFinder, false). + * {@link #fromLocalFinder(LocalSuffixFinder, boolean)}. * * @see #fromLocalFinder(LocalSuffixFinder, boolean) */ @@ -142,7 +142,7 @@ public static GlobalSuffixFinder fromLocalFinder(LocalSuffixFinder< * suffix-closedness of the set of distinguishing suffixes might not be preserved. Note that for correctly * implemented local suffix finders, this does not impair correctness of the learning algorithm. However, without * suffix closedness, intermediate hypothesis models might be non-canonical, if no additional precautions are taken. - * For that reasons, the allSuffixes parameter can be specified to control whether or not the list returned + * For that reasons, the {@code allSuffixes} parameter can be specified to control whether or not the list returned * by {@link GlobalSuffixFinder#findSuffixes(Query, AccessSequenceTransformer, SuffixOutput, MembershipOracle)} of * the returned global suffix finder should not only contain the single suffix, but also all of its suffixes, * ensuring suffix-closedness. @@ -189,7 +189,7 @@ public static List> suffixesForLocalOutput(Query ceQuery, i * suffix-closedness of the set of distinguishing suffixes might not be preserved. Note that for correctly * implemented local suffix finders, this does not impair correctness of the learning algorithm. However, without * suffix closedness, intermediate hypothesis models might be non-canonical, if no additional precautions are taken. - * For that reasons, the allSuffixes parameter can be specified to control whether or not the list returned + * For that reasons, the {@code allSuffixes} parameter can be specified to control whether or not the list returned * by {@link GlobalSuffixFinder#findSuffixes(Query, AccessSequenceTransformer, SuffixOutput, MembershipOracle)} of * the returned global suffix finder should not only contain the single suffix, but also all of its suffixes, * ensuring suffix-closedness. @@ -255,7 +255,7 @@ public static List> findShahbaz(Query ceQuery, AccessSequen } /** - * Returns the suffix (plus all of its suffixes, if allSuffixes is true) found by the access sequence + * Returns the suffix (plus all of its suffixes, if {@code allSuffixes} is true) found by the access sequence * transformation in ascending linear order. * * @param ceQuery @@ -283,7 +283,7 @@ public static List> findLinear(Query ceQuery, } /** - * Returns the suffix (plus all of its suffixes, if allSuffixes is true) found by the access sequence + * Returns the suffix (plus all of its suffixes, if {@code allSuffixes} is true) found by the access sequence * transformation in descending linear order. * * @param ceQuery @@ -311,7 +311,7 @@ public static List> findLinearReverse(Query ceQuery, } /** - * Returns the suffix (plus all of its suffixes, if allSuffixes is true) found by the binary search access + * Returns the suffix (plus all of its suffixes, if {@code allSuffixes} is true) found by the binary search access * sequence transformation. * * @param ceQuery diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinder.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinder.java index 52f42d2895..0eed353c89 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinder.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinder.java @@ -24,21 +24,21 @@ /** * Suffix-based local counterexample analyzer. *

    - * Given a query (u, v) which is a counterexample (i.e., the suffix-output for (u,v) is distinct from - * the target system's output for (u,v)), it calculates the index i of the suffix such that - * w[i:] (w = uv) still allows to expose a behavioral difference for an adequate prefix. This adequate - * prefix can be determined as {w[:i]}, where {.} denotes the access sequence of the corresponding + * Given a query {@code (u, v)} which is a counterexample (i.e., the suffix-output for {@code (u,v)} is distinct from + * the target system's output for {@code (u,v)}), it calculates the index {@code i} of the suffix such that + * {@code w[i:]} ({@code w = uv}) still allows to expose a behavioral difference for an adequate prefix. This adequate + * prefix can be determined as {@code {w[:i]}}, where {@code {.}} denotes the access sequence of the corresponding * word. *

    - * The effect of adding such a suffix can be described as follows: {w[:i]} and {w[:i-1]}w[i-1] both + * The effect of adding such a suffix can be described as follows: {@code {w[:i]}} and {@code {w[:i-1]}w[i-1]} both * lead to the same state in the hypothesis, but a local suffix finder chooses the index i such that the output for - * ({w[:i]}, w[i:]) and ({w[:i-1]}w[i-1], w[i:]) will differ. Hence, the transition to the state - * reached by {w[:i]} from {w[:i-1]} is disproved. + * {@code ({w[:i]}, w[i:])} and {@code ({w[:i-1]}w[i-1], w[i:])} will differ. Hence, the transition to the state + * reached by {@code {w[:i]}} from {@code {w[:i-1]}} is disproved. *

    * Please note that the type parameters of these class only constitute upper bounds for the respective input * symbol and output classes, denoting the requirements of the process in general. A suffix finder which does not - * exploit any properties of the used classes will implement this interface with <Object,Object> generic - * arguments only. The genericity is still maintained due to the RI and RO generic parameters in the + * exploit any properties of the used classes will implement this interface with {@code } generic + * arguments only. The genericity is still maintained due to the {@code RI} and {@code RO} generic parameters in the * {@link #findSuffixIndex(Query, AccessSequenceTransformer, SuffixOutput, MembershipOracle)} method. * * @param @@ -70,7 +70,7 @@ public interface LocalSuffixFinder { * @param oracle * interface to the System Under Learning (SUL). * - * @return an adequate split index, or -1 if the counterexample could not be analyzed. + * @return an adequate split index, or {@code -1} if the counterexample could not be analyzed. */ int findSuffixIndex(Query ceQuery, AccessSequenceTransformer asTransformer, diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinders.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinders.java index 35b7f4c879..6dc98c7e32 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinders.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinders.java @@ -73,7 +73,7 @@ private LocalSuffixFinders() { * @param oracle * interface to the SUL * - * @return the index of the respective suffix, or -1 if no counterexample could be found + * @return the index of the respective suffix, or {@code -1} if no counterexample could be found * * @see LocalSuffixFinder */ @@ -103,7 +103,7 @@ public static int findLinear(Query ceQuery, * @param oracle * interface to the SUL * - * @return the index of the respective suffix, or -1 if no counterexample could be found + * @return the index of the respective suffix, or {@code -1} if no counterexample could be found * * @see LocalSuffixFinder */ @@ -133,7 +133,7 @@ public static int findLinearReverse(Query ceQuery, * @param oracle * interface to the SUL * - * @return the index of the respective suffix, or -1 if no counterexample could be found + * @return the index of the respective suffix, or {@code -1} if no counterexample could be found * * @see LocalSuffixFinder */ diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/MutableObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/MutableObservationTable.java index 669a07befd..eb5fdd8b37 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/MutableObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/MutableObservationTable.java @@ -41,7 +41,7 @@ List>> initialize(List> initialShortPrefixes, /** * Checks whether this observation table has been initialized yet (i.e., contains any rows). * - * @return true iff the table has been initialized + * @return {@code true} iff the table has been initialized */ boolean isInitialized(); @@ -49,7 +49,7 @@ List>> initialize(List> initialShortPrefixes, /** * Adds a suffix to the list of distinguishing suffixes. This is a convenience method that can be used as shorthand - * for addSufixes(Collections.singletonList(suffix), oracle) + * for {@code addSufixes(Collections.singletonList(suffix), oracle)}. * * @param suffix * the suffix to add diff --git a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseEdge.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseEdge.java index 518f4ac8a5..8a4f071b09 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseEdge.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseEdge.java @@ -39,13 +39,13 @@ public class ReuseEdge { /** * Default constructor. * - * @param source, + * @param source * not allowed to be {@code null}. - * @param target, + * @param target * not allowed to be {@code null}. - * @param input, + * @param input * not allowed to be {@code null}. - * @param output, + * @param output * in case of quiescence maybe {@code null}. */ public ReuseEdge(final ReuseNode source, final ReuseNode target, final I input, final O output) { From f7b0feb0dd42cae9d834ddf766ea8cf0391f7aaa Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 24 Oct 2018 15:57:48 +0200 Subject: [PATCH 092/125] build-tools: make LTSmin install script windows/macOS compatible --- build-tools/install-ltsmin.sh | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/build-tools/install-ltsmin.sh b/build-tools/install-ltsmin.sh index cca3c7d055..4b46141409 100755 --- a/build-tools/install-ltsmin.sh +++ b/build-tools/install-ltsmin.sh @@ -3,18 +3,23 @@ LTSMIN_NAME="ltsmin-${LTSMIN_VERSION}-$TRAVIS_OS_NAME.tgz" LTSMIN_URL="https://github.com/$%7BLTSMIN_REPO:-utwente-fmt%7D/ltsmin/releases/download/$LTSMIN_VERSION/$LTSMIN_NAME" +if [ $TRAVIS_OS_NAME = "windows" ]; then + FILE_SUFFIX=".exe" +fi + # test if we have a cached version -test -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/ltsmin-convert" -a -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/etf2lts-mc" && exit 0 +test -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/ltsmin-convert${FILE_SUFFIX}" -a -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/etf2lts-mc${FILE_SUFFIX}" && exit 0 -# create the directoy where the binaries end up. +# create the directoy where the binaries and downloads end up. mkdir -p "$HOME/ltsmin" +mkdir -p "$HOME/ltsmin-download" # download the LTSmin binaries -wget "$LTSMIN_URL" -P /tmp +wget "$LTSMIN_URL" -P "$HOME/ltsmin-download" # the files to extract -echo ltsmin-convert > /tmp/files -echo etf2lts-mc >> /tmp/files +echo ${LTSMIN_VERSION}/bin/ltsmin-convert${FILE_SUFFIX} > $HOME/ltsmin-download/files +echo ${LTSMIN_VERSION}/bin/etf2lts-mc${FILE_SUFFIX} >> $HOME/ltsmin-download/files # extract the files -tar -xf "/tmp/$LTSMIN_NAME" -C "$HOME/ltsmin" --no-anchored --files-from=/tmp/files +tar -xf "$HOME/ltsmin-download/$LTSMIN_NAME" -C "$HOME/ltsmin" --files-from=$HOME/ltsmin-download/files From 93680a40cd159ada3432c7673c48685f33be8ebb Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Wed, 24 Oct 2018 16:00:18 +0200 Subject: [PATCH 093/125] travis: update test configurations - Add Java 11 builds - Add osx and (deactivated) windows builds. The windows builds should work in theory, but are currently disabled because of the (known) issue that VMs hang if the repository uses secret env variables. - Move expensive analysis and documentation generation to a subset of configurations to be less taxing on CI server --- .travis.yml | 53 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index b10b1af876..b1c2e546f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,38 +25,67 @@ env: install: # install LTSmin - - build-tools/install-ltsmin.sh + - ${TRAVIS_BUILD_DIR}/build-tools/install-ltsmin.sh - PATH="$PATH:$HOME/ltsmin/$LTSMIN_VERSION/bin" # override any "sane" defaults of Travis VMs - cp ${TRAVIS_BUILD_DIR}/build-tools/travis-settings.xml ${HOME}/.m2/settings.xml # set Travis environment variables "AUTOMATALIB_FORK" and "AUTOMATALIB_BRANCH" to build custom AutomataLib versions. # Defaults are "LearnLib" and the current/targeted LearnLib branch ($TRAVIS_BRANCH, relies on the same naming # conventions between AutomataLib and LearnLib branches). - - git clone -b ${AUTOMATALIB_BRANCH:-$TRAVIS_BRANCH} --single-branch https://github.com/${AUTOMATALIB_FORK:-LearnLib}/automatalib.git /tmp/automatalib-develop - - pushd /tmp/automatalib-develop + - git clone -b ${AUTOMATALIB_BRANCH:-$TRAVIS_BRANCH} --single-branch https://github.com/${AUTOMATALIB_FORK:-LearnLib}/automatalib.git ${HOME}/automatalib-develop + - cd ${HOME}/automatalib-develop - mvn install -DskipTests - - popd + - cd ${TRAVIS_BUILD_DIR} script: - - mvn install -B -Pintegration-tests,code-analysis,bundles + - mvn install -B jobs: fast_finish: true include: + # Run code analysis and documentation generation only in our core environments (since it's an expensive task) - jdk: openjdk8 - - jdk: openjdk10 - - jdk: openjdk10 - env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=10 -Dmaven.compiler.target=10" + script: mvn install -B -Pintegration-tests,code-analysis,bundles + - jdk: openjdk11 + script: mvn install -B -Pintegration-tests,code-analysis,bundles + # Run "normal" tests in other environments + - stage: Integration Tests + jdk: openjdk11 + env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=11 -Dmaven.compiler.target=11" + - os: osx + jdk: openjdk8 + # Force old xcode version so JDK8 isn't overridden from newer xcode version + osx_image: xcode9.3 + - os: osx + jdk: openjdk11 +# - os: windows +# jdk: oraclejdk8 +# language: shell +# before_install: +# - cinst jdk8 -params 'installdir=C:\\jdk8' +# - export JAVA_HOME="C:\jdk8" +# - export PATH=${JAVA_HOME}/bin:${PATH} +# - cinst maven -params 'installdir=C:\\maven' +# - os: windows +# jdk: oraclejdk11 +# language: shell +# before_install: +# - cinst jdk11 -params 'installdir=C:\\jdk11' +# - export JAVA_HOME="C:\jdk11" +# - export PATH=${JAVA_HOME}/bin:${PATH} +# - cinst maven -params 'installdir=C:\\maven' + # Run coverage in default environment - stage: coverage - jdk: openjdk8 # use openjdk8 build + jdk: openjdk8 script: - mvn install -B -Pintegration-tests,code-coverage - mvn coveralls:report + # Run deployment in default environment - stage: deploy - jdk: openjdk8 # use openjdk build - script: skip # skip the normal build + jdk: openjdk8 + # skip regular build and define deployment in deploy phase, which is skipped for pull-requests + script: skip deploy: - # define deployment in deploy phase, which is skipped for pull-requests provider: script script: mvn -DskipTests=true deploy on: From 71f2bf3b7e75e18fea67f607ba37132a3824bf2a Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 30 Oct 2018 11:26:25 +0100 Subject: [PATCH 094/125] refactor learnlib-oracle-support - Renamed module to learnlib-test-support - Moved non-integration tests from learnlib-learner-it-support to (now new) learlib-test-support module --- algorithms/active/adt/pom.xml | 8 +++++--- algorithms/active/dhc/pom.xml | 4 ++++ algorithms/active/discrimination-tree-vpda/pom.xml | 6 ++++-- algorithms/active/discrimination-tree/pom.xml | 6 ++++-- algorithms/active/kearns-vazirani/pom.xml | 6 ++++-- algorithms/active/lstar/pom.xml | 4 ++++ algorithms/active/nlstar/pom.xml | 6 ++++-- algorithms/active/ttt-vpda/pom.xml | 4 ++++ algorithms/active/ttt/pom.xml | 4 ++++ oracles/emptiness-oracles/pom.xml | 2 +- .../emptiness/AbstractBFEmptinessOracleTest.java | 2 +- oracles/equivalence-oracles/pom.xml | 2 +- .../equivalence/AbstractBFInclusionOracleTest.java | 2 +- pom.xml | 2 +- test-support/pom.xml | 2 +- .../{oracle-support => test-support}/pom.xml | 14 +++++++++++--- .../testsupport}/AbstractBFOracleTest.java | 2 +- .../AbstractGrowingAlphabetDFATest.java | 4 ++-- .../AbstractGrowingAlphabetMealyTest.java | 4 ++-- .../testsupport/AbstractGrowingAlphabetTest.java | 0 .../AbstractResumableLearnerDFATest.java | 4 ++-- .../AbstractResumableLearnerMealyTest.java | 4 ++-- .../testsupport/AbstractResumableLearnerTest.java | 0 23 files changed, 63 insertions(+), 29 deletions(-) rename test-support/{oracle-support => test-support}/pom.xml (74%) rename test-support/{oracle-support/src/main/java/de/learnlib/oracle => test-support/src/main/java/de/learnlib/testsupport}/AbstractBFOracleTest.java (98%) rename test-support/{learner-it-support => test-support}/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java (93%) rename test-support/{learner-it-support => test-support}/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java (94%) rename test-support/{learner-it-support => test-support}/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java (100%) rename test-support/{learner-it-support => test-support}/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java (93%) rename test-support/{learner-it-support => test-support}/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java (93%) rename test-support/{learner-it-support => test-support}/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java (100%) diff --git a/algorithms/active/adt/pom.xml b/algorithms/active/adt/pom.xml index bfa40acc2d..e7a836c2d2 100644 --- a/algorithms/active/adt/pom.xml +++ b/algorithms/active/adt/pom.xml @@ -83,19 +83,21 @@ limitations under the License. org.testng testng - test de.learnlib.testsupport learnlib-learning-examples - test de.learnlib.testsupport learnlib-learner-it-support - test + + + + de.learnlib.testsupport + learnlib-test-support diff --git a/algorithms/active/dhc/pom.xml b/algorithms/active/dhc/pom.xml index 17fa04c7cb..21a9a1d4f0 100644 --- a/algorithms/active/dhc/pom.xml +++ b/algorithms/active/dhc/pom.xml @@ -103,6 +103,10 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support + + de.learnlib.testsupport + learnlib-test-support + diff --git a/algorithms/active/discrimination-tree-vpda/pom.xml b/algorithms/active/discrimination-tree-vpda/pom.xml index bf9149aabe..0c4d8a0630 100644 --- a/algorithms/active/discrimination-tree-vpda/pom.xml +++ b/algorithms/active/discrimination-tree-vpda/pom.xml @@ -85,12 +85,14 @@ limitations under the License. org.testng testng - test de.learnlib.testsupport learnlib-learner-it-support - test + + + de.learnlib.testsupport + learnlib-test-support diff --git a/algorithms/active/discrimination-tree/pom.xml b/algorithms/active/discrimination-tree/pom.xml index 9245ffcca4..a4ef6d6c3a 100644 --- a/algorithms/active/discrimination-tree/pom.xml +++ b/algorithms/active/discrimination-tree/pom.xml @@ -71,12 +71,14 @@ limitations under the License. org.testng testng - test de.learnlib.testsupport learnlib-learner-it-support - test + + + de.learnlib.testsupport + learnlib-test-support de.learnlib diff --git a/algorithms/active/kearns-vazirani/pom.xml b/algorithms/active/kearns-vazirani/pom.xml index 1a7d977394..ff561e85c4 100644 --- a/algorithms/active/kearns-vazirani/pom.xml +++ b/algorithms/active/kearns-vazirani/pom.xml @@ -64,12 +64,14 @@ limitations under the License. org.testng testng - test de.learnlib.testsupport learnlib-learner-it-support - test + + + de.learnlib.testsupport + learnlib-test-support com.github.misberner.buildergen diff --git a/algorithms/active/lstar/pom.xml b/algorithms/active/lstar/pom.xml index 23154428a2..b15f74b005 100644 --- a/algorithms/active/lstar/pom.xml +++ b/algorithms/active/lstar/pom.xml @@ -99,6 +99,10 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support + + de.learnlib.testsupport + learnlib-test-support + de.learnlib learnlib-equivalence-oracles diff --git a/algorithms/active/nlstar/pom.xml b/algorithms/active/nlstar/pom.xml index 769f65c82a..9fdbe04aec 100644 --- a/algorithms/active/nlstar/pom.xml +++ b/algorithms/active/nlstar/pom.xml @@ -58,12 +58,14 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - test + + + de.learnlib.testsupport + learnlib-test-support org.testng testng - test de.learnlib diff --git a/algorithms/active/ttt-vpda/pom.xml b/algorithms/active/ttt-vpda/pom.xml index e16dcafc1f..5429270f82 100644 --- a/algorithms/active/ttt-vpda/pom.xml +++ b/algorithms/active/ttt-vpda/pom.xml @@ -92,5 +92,9 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support + + de.learnlib.testsupport + learnlib-test-support + diff --git a/algorithms/active/ttt/pom.xml b/algorithms/active/ttt/pom.xml index 39a82feacb..905d11c024 100644 --- a/algorithms/active/ttt/pom.xml +++ b/algorithms/active/ttt/pom.xml @@ -105,6 +105,10 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support + + de.learnlib.testsupport + learnlib-test-support + diff --git a/oracles/emptiness-oracles/pom.xml b/oracles/emptiness-oracles/pom.xml index d842b3783a..2536234062 100644 --- a/oracles/emptiness-oracles/pom.xml +++ b/oracles/emptiness-oracles/pom.xml @@ -50,7 +50,7 @@ de.learnlib.testsupport - learnlib-oracle-support + learnlib-test-support diff --git a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java index 12b1fbed0c..354cb04fb4 100644 --- a/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java @@ -16,7 +16,7 @@ package de.learnlib.oracle.emptiness; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.oracle.AbstractBFOracleTest; +import de.learnlib.testsupport.AbstractBFOracleTest; import de.learnlib.util.AbstractBFOracle; import net.automatalib.automata.concepts.DetOutputAutomaton; import net.automatalib.ts.simple.SimpleDTS; diff --git a/oracles/equivalence-oracles/pom.xml b/oracles/equivalence-oracles/pom.xml index 5cf2c170a4..12c42ba49a 100644 --- a/oracles/equivalence-oracles/pom.xml +++ b/oracles/equivalence-oracles/pom.xml @@ -104,7 +104,7 @@ limitations under the License. de.learnlib.testsupport - learnlib-oracle-support + learnlib-test-support diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java index 599c7394c9..3658b82f87 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java @@ -16,7 +16,7 @@ package de.learnlib.oracle.equivalence; import de.learnlib.api.query.DefaultQuery; -import de.learnlib.oracle.AbstractBFOracleTest; +import de.learnlib.testsupport.AbstractBFOracleTest; import de.learnlib.util.AbstractBFOracle; import net.automatalib.automata.concepts.DetOutputAutomaton; import net.automatalib.ts.simple.SimpleDTS; diff --git a/pom.xml b/pom.xml index f3d636107d..bf5bba759d 100644 --- a/pom.xml +++ b/pom.xml @@ -534,7 +534,7 @@ limitations under the License. de.learnlib.testsupport - learnlib-oracle-support + learnlib-test-support ${project.version} test diff --git a/test-support/pom.xml b/test-support/pom.xml index ded3174450..61986b803e 100644 --- a/test-support/pom.xml +++ b/test-support/pom.xml @@ -35,7 +35,7 @@ limitations under the License. learning-examples learner-it-support - oracle-support + test-support diff --git a/test-support/oracle-support/pom.xml b/test-support/test-support/pom.xml similarity index 74% rename from test-support/oracle-support/pom.xml rename to test-support/test-support/pom.xml index 12c639fc52..78e72e3857 100644 --- a/test-support/oracle-support/pom.xml +++ b/test-support/test-support/pom.xml @@ -9,11 +9,11 @@ ../pom.xml - learnlib-oracle-support + learnlib-test-support jar - LearnLib :: Test Support :: Oracle Support - Support classes for easily writing integration test cases for oracle algorithms + LearnLib :: Test Support :: Test Support + Support classes for easily writing unit tests for various components of LearnLib @@ -24,6 +24,14 @@ net.automatalib automata-core + + net.automatalib + automata-util + + + de.learnlib + learnlib-api + de.learnlib learnlib-util diff --git a/test-support/oracle-support/src/main/java/de/learnlib/oracle/AbstractBFOracleTest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractBFOracleTest.java similarity index 98% rename from test-support/oracle-support/src/main/java/de/learnlib/oracle/AbstractBFOracleTest.java rename to test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractBFOracleTest.java index 77d9168f06..a3856ded3b 100644 --- a/test-support/oracle-support/src/main/java/de/learnlib/oracle/AbstractBFOracleTest.java +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractBFOracleTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.oracle; +package de.learnlib.testsupport; import de.learnlib.util.AbstractBFOracle; import net.automatalib.ts.simple.SimpleDTS; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java similarity index 93% rename from test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java rename to test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java index 6a851dc7e9..a457a73bc4 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java @@ -21,7 +21,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.membership.SimulatorOracle; +import de.learnlib.api.oracle.QueryAnswerer; import net.automatalib.automata.fsa.DFA; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; @@ -50,7 +50,7 @@ protected DFA getTarget(Alphabet alphabet) { @Override protected MembershipOracle getOracle(DFA target) { - return new SimulatorOracle<>(target); + return ((QueryAnswerer) target::computeSuffixOutput).asOracle(); } } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java similarity index 94% rename from test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java rename to test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java index e78c4a055c..28346a5e0e 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java @@ -21,7 +21,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.membership.SimulatorOracle; +import de.learnlib.api.oracle.QueryAnswerer; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; @@ -54,7 +54,7 @@ protected Collection getAlphabetExtensions() { @Override protected MembershipOracle> getOracle(MealyMachine target) { - return new SimulatorOracle<>(target); + return ((QueryAnswerer>) target::computeSuffixOutput).asOracle(); } } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java similarity index 100% rename from test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java rename to test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java similarity index 93% rename from test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java rename to test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java index da1b676a6f..4e176df887 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java @@ -21,7 +21,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.ResumableLearner; import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.membership.SimulatorOracle; +import de.learnlib.api.oracle.QueryAnswerer; import net.automatalib.automata.fsa.DFA; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; @@ -47,7 +47,7 @@ protected DFA getTarget(Alphabet alphabet) { @Override protected MembershipOracle getOracle(DFA target) { - return new SimulatorOracle<>(target); + return ((QueryAnswerer) target::computeSuffixOutput).asOracle(); } } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java similarity index 93% rename from test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java rename to test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java index db2995aa6f..02b7071780 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java @@ -21,7 +21,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.ResumableLearner; import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.membership.SimulatorOracle; +import de.learnlib.api.oracle.QueryAnswerer; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; @@ -51,6 +51,6 @@ protected Alphabet getInitialAlphabet() { @Override protected MembershipOracle> getOracle(MealyMachine target) { - return new SimulatorOracle<>(target); + return ((QueryAnswerer>) target::computeSuffixOutput).asOracle(); } } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java similarity index 100% rename from test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java rename to test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java From ee40ea6e3b63ad4cb6028b264ed0f19d4f9759b6 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 30 Oct 2018 12:10:13 +0100 Subject: [PATCH 095/125] travis: run 'coverage' and 'deploy' in same stage --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b1c2e546f1..b8431743d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,13 +75,14 @@ jobs: # - export PATH=${JAVA_HOME}/bin:${PATH} # - cinst maven -params 'installdir=C:\\maven' # Run coverage in default environment - - stage: coverage + - stage: Coverage & Deploy + name: Coverage jdk: openjdk8 script: - mvn install -B -Pintegration-tests,code-coverage - mvn coveralls:report # Run deployment in default environment - - stage: deploy + - name: Deploy jdk: openjdk8 # skip regular build and define deployment in deploy phase, which is skipped for pull-requests script: skip From 82aa17d2ebd42efffa943a2e999ea014daae4922 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 30 Oct 2018 14:13:56 +0100 Subject: [PATCH 096/125] adjust to AutomataLib refactorings --- algorithms/active/discrimination-tree-vpda/pom.xml | 4 ---- .../algorithms/discriminationtree/hypothesis/vpda/HypLoc.java | 2 +- algorithms/active/discrimination-tree/pom.xml | 2 +- .../algorithms/discriminationtree/hypothesis/HState.java | 2 +- algorithms/active/kearns-vazirani/pom.xml | 2 +- .../java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java | 2 +- algorithms/active/ttt/pom.xml | 4 ---- .../main/java/de/learnlib/algorithms/ttt/base/TTTState.java | 2 +- .../de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java | 2 +- commons/acex/pom.xml | 2 +- .../de/learnlib/acex/impl/AbstractBaseCounterexample.java | 2 +- datastructures/discrimination-tree/pom.xml | 4 ++++ .../discriminationtree/model/AbstractDiscriminationTree.java | 2 +- datastructures/observation-table/pom.xml | 4 ++++ .../de/learnlib/datastructure/observationtable/RowImpl.java | 2 +- datastructures/pta/pom.xml | 4 ++++ .../learnlib/datastructure/pta/pta/AbstractBasePTAState.java | 2 +- .../java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java | 2 +- oracles/parallelism/pom.xml | 4 ++++ .../oracle/parallelism/DynamicParallelOracleBuilder.java | 2 +- 20 files changed, 30 insertions(+), 22 deletions(-) diff --git a/algorithms/active/discrimination-tree-vpda/pom.xml b/algorithms/active/discrimination-tree-vpda/pom.xml index 0c4d8a0630..4c1fe9206e 100644 --- a/algorithms/active/discrimination-tree-vpda/pom.xml +++ b/algorithms/active/discrimination-tree-vpda/pom.xml @@ -63,10 +63,6 @@ limitations under the License. net.automatalib automata-commons-smartcollections - - net.automatalib - automata-commons-util - diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java index d389591cfc..998704d387 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypLoc.java @@ -20,7 +20,7 @@ import java.util.List; import de.learnlib.api.AccessSequenceProvider; -import net.automatalib.commons.util.array.ArrayStorage; +import net.automatalib.commons.smartcollections.ArrayStorage; import net.automatalib.words.VPDAlphabet; import net.automatalib.words.Word; diff --git a/algorithms/active/discrimination-tree/pom.xml b/algorithms/active/discrimination-tree/pom.xml index a4ef6d6c3a..9be6c87fc7 100644 --- a/algorithms/active/discrimination-tree/pom.xml +++ b/algorithms/active/discrimination-tree/pom.xml @@ -58,7 +58,7 @@ limitations under the License. net.automatalib - automata-commons-util + automata-commons-smartcollections 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 f3bc771779..8c03f4b8bb 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 @@ -23,7 +23,7 @@ import java.util.List; import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; -import net.automatalib.commons.util.array.ResizingArrayStorage; +import net.automatalib.commons.smartcollections.ResizingArrayStorage; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; diff --git a/algorithms/active/kearns-vazirani/pom.xml b/algorithms/active/kearns-vazirani/pom.xml index ff561e85c4..f4427170d6 100644 --- a/algorithms/active/kearns-vazirani/pom.xml +++ b/algorithms/active/kearns-vazirani/pom.xml @@ -45,7 +45,7 @@ limitations under the License. net.automatalib - automata-commons-util + automata-commons-smartcollections diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java index 50bbc53bb5..b04714a078 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java @@ -37,7 +37,7 @@ import de.learnlib.datastructure.discriminationtree.model.LCAInfo; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.fsa.impl.compact.CompactDFA; -import net.automatalib.commons.util.array.ArrayStorage; +import net.automatalib.commons.smartcollections.ArrayStorage; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; diff --git a/algorithms/active/ttt/pom.xml b/algorithms/active/ttt/pom.xml index 905d11c024..63e080502b 100644 --- a/algorithms/active/ttt/pom.xml +++ b/algorithms/active/ttt/pom.xml @@ -74,10 +74,6 @@ limitations under the License. net.automatalib automata-commons-smartcollections - - net.automatalib - automata-commons-util - diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java index d612586ffd..e82756189c 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java @@ -18,7 +18,7 @@ import java.io.Serializable; import de.learnlib.api.AccessSequenceProvider; -import net.automatalib.commons.util.array.ResizingArrayStorage; +import net.automatalib.commons.smartcollections.ResizingArrayStorage; import net.automatalib.words.Word; /** diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java index 09f6b69705..3fa1d7917d 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java @@ -24,7 +24,7 @@ import de.learnlib.algorithms.ttt.base.TTTTransition; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.commons.util.array.ArrayStorage; +import net.automatalib.commons.smartcollections.ArrayStorage; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; diff --git a/commons/acex/pom.xml b/commons/acex/pom.xml index fa39f4a219..0a768ad4fa 100644 --- a/commons/acex/pom.xml +++ b/commons/acex/pom.xml @@ -33,7 +33,7 @@ limitations under the License. net.automatalib - automata-commons-util + automata-commons-smartcollections + 1.8 1.8 diff --git a/archetypes/complete/src/main/resources/archetype-resources/pom.xml b/archetypes/complete/src/main/resources/archetype-resources/pom.xml index f368df0c49..87c042b3d6 100644 --- a/archetypes/complete/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/complete/src/main/resources/archetype-resources/pom.xml @@ -27,7 +27,7 @@ limitations under the License. UTF-8 - + 1.8 1.8 From 5061142ed971f55b14a3caed3b4d5cadaa122445 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 27 Nov 2018 18:48:17 +0100 Subject: [PATCH 102/125] simplify Experiment class revert most changes introduced by the BBCExperiment class, since that class no longer exists --- .../java/de/learnlib/util/Experiment.java | 178 ++++++++---------- 1 file changed, 79 insertions(+), 99 deletions(-) diff --git a/commons/util/src/main/java/de/learnlib/util/Experiment.java b/commons/util/src/main/java/de/learnlib/util/Experiment.java index 247614a57e..553787fd99 100644 --- a/commons/util/src/main/java/de/learnlib/util/Experiment.java +++ b/commons/util/src/main/java/de/learnlib/util/Experiment.java @@ -33,175 +33,155 @@ * runs a learning experiment. * * @param the automaton type - * @param the input type - * @param the output type * * @author falkhowar - * @author Jeroen Meijer */ @ParametersAreNonnullByDefault -public class Experiment { +public class Experiment { public static final String LEARNING_PROFILE_KEY = "Learning"; public static final String COUNTEREXAMPLE_PROFILE_KEY = "Searching for counterexample"; private static final LearnLogger LOGGER = LearnLogger.getLogger(Experiment.class); - + private final ExperimentImpl impl; private boolean logModels; - private boolean profile; - private final Counter rounds = new Counter("learning rounds", "#"); - private A finalHypothesis; - private final LearningAlgorithm learningAlgorithm; - - private final EquivalenceOracle equivalenceAlgorithm; - - private final Alphabet inputs; - - public Experiment(LearningAlgorithm learningAlgorithm, - EquivalenceOracle equivalenceAlgorithm, - Alphabet inputs) { - this.learningAlgorithm = learningAlgorithm; - this.equivalenceAlgorithm = equivalenceAlgorithm; - this.inputs = inputs; + public Experiment(LearningAlgorithm learningAlgorithm, + EquivalenceOracle equivalenceAlgorithm, + Alphabet inputs) { + this.impl = new ExperimentImpl<>(learningAlgorithm, equivalenceAlgorithm, inputs); } - public boolean isLogModels() { - return logModels; - } + @Nonnull + public A run() { + if (this.finalHypothesis != null) { + throw new IllegalStateException("Experiment has already been run"); + } - public Counter getRounds() { - return rounds; + finalHypothesis = impl.run(); + return finalHypothesis; } - public LearningAlgorithm getLearningAlgorithm() { - return learningAlgorithm; + @Nonnull + public A getFinalHypothesis() { + if (finalHypothesis == null) { + throw new IllegalStateException("Experiment has not yet been run"); + } + + return finalHypothesis; } - public EquivalenceOracle getEquivalenceAlgorithm() { - return equivalenceAlgorithm; + private void profileStart(String taskname) { + if (profile) { + SimpleProfiler.start(taskname); + } } - public Alphabet getInputs() { - return inputs; + private void profileStop(String taskname) { + if (profile) { + SimpleProfiler.stop(taskname); + } } + /** + * @param logModels + * flag whether models should be logged + */ public void setLogModels(boolean logModels) { this.logModels = logModels; } + /** + * @param profile + * flag whether learning process should be profiled + */ public void setProfile(boolean profile) { this.profile = profile; } /** - * Returns whether this experiment has already been run. - * - * @return {@code true} if this experiment has been run, {@code false} otherwise. + * @return the rounds */ - public boolean isRun() { - return this.finalHypothesis != null; + @Nonnull + public Counter getRounds() { + return rounds; } - protected void init() { - rounds.increment(); - LOGGER.logPhase("Starting round " + rounds.getCount()); - LOGGER.logPhase("Learning"); - - profileStart(LEARNING_PROFILE_KEY); - learningAlgorithm.startLearning(); - profileStop(LEARNING_PROFILE_KEY); - } + private final class ExperimentImpl { - protected boolean refineHypothesis() { - A hyp = getLearningAlgorithm().getHypothesisModel(); + private final LearningAlgorithm learningAlgorithm; + private final EquivalenceOracle equivalenceAlgorithm; + private final Alphabet inputs; - if (logModels) { - LOGGER.logModel(hyp); + ExperimentImpl(LearningAlgorithm learningAlgorithm, + EquivalenceOracle equivalenceAlgorithm, + Alphabet inputs) { + this.learningAlgorithm = learningAlgorithm; + this.equivalenceAlgorithm = equivalenceAlgorithm; + this.inputs = inputs; } - LOGGER.logPhase("Searching for counterexample"); - - profileStart(COUNTEREXAMPLE_PROFILE_KEY); - DefaultQuery ce = equivalenceAlgorithm.findCounterExample(hyp, getInputs()); - profileStop(COUNTEREXAMPLE_PROFILE_KEY); - - if (ce != null) { - LOGGER.logCounterexample(ce.toString()); - - // next round ... + public A run() { rounds.increment(); - LOGGER.logPhase("Starting round " + getRounds().getCount()); + LOGGER.logPhase("Starting round " + rounds.getCount()); LOGGER.logPhase("Learning"); profileStart(LEARNING_PROFILE_KEY); - final boolean refined = learningAlgorithm.refineHypothesis(ce); + learningAlgorithm.startLearning(); profileStop(LEARNING_PROFILE_KEY); - assert refined; - } + while (true) { + final A hyp = learningAlgorithm.getHypothesisModel(); - return ce != null; - } + if (logModels) { + LOGGER.logModel(hyp); + } - @Nonnull - public A run() { - if (isRun()) { - throw new IllegalStateException("Experiment has already been run"); - } + LOGGER.logPhase("Searching for counterexample"); - init(); + profileStart(COUNTEREXAMPLE_PROFILE_KEY); + DefaultQuery ce = equivalenceAlgorithm.findCounterExample(hyp, inputs); + profileStop(COUNTEREXAMPLE_PROFILE_KEY); - while (refineHypothesis()) { } + if (ce == null) { + return hyp; + } - finalHypothesis = learningAlgorithm.getHypothesisModel(); + LOGGER.logCounterexample(ce.getInput().toString()); - return finalHypothesis; - } + // next round ... + rounds.increment(); + LOGGER.logPhase("Starting round " + rounds.getCount()); + LOGGER.logPhase("Learning"); - protected void setFinalHypothesis(A hyp) { - finalHypothesis = hyp; - } + profileStart(LEARNING_PROFILE_KEY); + final boolean refined = learningAlgorithm.refineHypothesis(ce); + profileStop(LEARNING_PROFILE_KEY); - @Nonnull - public A getFinalHypothesis() { - if (!isRun()) { - throw new IllegalStateException("Experiment has not yet been run"); - } - return finalHypothesis; - } - - protected void profileStart(String taskname) { - if (profile) { - SimpleProfiler.start(taskname); - } - } - - protected void profileStop(String taskname) { - if (profile) { - SimpleProfiler.stop(taskname); + assert refined; + } } } - public static class DFAExperiment extends Experiment, I, Boolean> { - + public static class DFAExperiment extends Experiment> { public DFAExperiment(LearningAlgorithm, I, Boolean> learningAlgorithm, EquivalenceOracle, I, Boolean> equivalenceAlgorithm, Alphabet inputs) { super(learningAlgorithm, equivalenceAlgorithm, inputs); } + } - public static class MealyExperiment extends Experiment, I, Word> { + public static class MealyExperiment extends Experiment> { public MealyExperiment(LearningAlgorithm, I, Word> learningAlgorithm, EquivalenceOracle, I, Word> equivalenceAlgorithm, Alphabet inputs) { super(learningAlgorithm, equivalenceAlgorithm, inputs); } + } } - From eb20987be3ac2e44d38d2a23bf8ef25ad94325b9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 27 Nov 2018 22:48:37 +0100 Subject: [PATCH 103/125] cleanup some equals/hashcode implementations using best practices from "Effective Java" --- .../de/learnlib/api/query/OmegaQuery.java | 16 ++++++++---- .../java/de/learnlib/api/query/Query.java | 26 +++++-------------- .../discriminationtree/model/BooleanMap.java | 13 +++++----- .../de/learnlib/drivers/reflect/Error.java | 15 +++++------ .../learnlib/drivers/reflect/ReturnValue.java | 15 +++++------ 5 files changed, 38 insertions(+), 47 deletions(-) diff --git a/api/src/main/java/de/learnlib/api/query/OmegaQuery.java b/api/src/main/java/de/learnlib/api/query/OmegaQuery.java index 0d5cc55240..dc6ad36f1f 100644 --- a/api/src/main/java/de/learnlib/api/query/OmegaQuery.java +++ b/api/src/main/java/de/learnlib/api/query/OmegaQuery.java @@ -46,7 +46,7 @@ * @see ObservableSUL#getState() */ @ParametersAreNonnullByDefault -public final class OmegaQuery { +public class OmegaQuery { private final Word prefix; private final Word loop; @@ -105,21 +105,27 @@ public String toString() { } @Override - public boolean equals(Object o) { + public final boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof OmegaQuery)) { return false; } - OmegaQuery that = (OmegaQuery) o; + + final OmegaQuery that = (OmegaQuery) o; return periodicity == that.periodicity && Objects.equals(prefix, that.prefix) && Objects.equals(loop, that.loop) && Objects.equals(output, that.output); } @Override - public int hashCode() { - return Objects.hash(prefix, loop, output, periodicity); + public final int hashCode() { + int result = 1; + result = 31 * result + Objects.hashCode(prefix); + result = 31 * result + Objects.hashCode(loop); + result = 31 * result + Objects.hashCode(output); + result = 31 * result + Integer.hashCode(periodicity); + return result; } } diff --git a/api/src/main/java/de/learnlib/api/query/Query.java b/api/src/main/java/de/learnlib/api/query/Query.java index 024b1fc2d6..b069722c2c 100644 --- a/api/src/main/java/de/learnlib/api/query/Query.java +++ b/api/src/main/java/de/learnlib/api/query/Query.java @@ -15,6 +15,8 @@ */ package de.learnlib.api.query; +import java.util.Objects; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -114,37 +116,23 @@ public final int hashCode() { return hashCode; } - Word prefix = getPrefix(), suffix = getSuffix(); - hashCode = 5; - hashCode = 89 * hashCode + prefix.hashCode(); - hashCode = 89 * hashCode + suffix.hashCode(); + hashCode = 1; + hashCode = 31 * hashCode + Objects.hashCode(getPrefix()); + hashCode = 31 * hashCode + Objects.hashCode(getSuffix()); return hashCode; } @Override public final boolean equals(Object o) { - if (o == null) { - return false; - } if (this == o) { return true; } if (!(o instanceof Query)) { return false; } - Query other = (Query) o; - - Word thisPref = getPrefix(); - Word otherPref = other.getPrefix(); - - if (thisPref != otherPref && !thisPref.equals(otherPref)) { - return false; - } - - Word thisSuff = getSuffix(); - Word otherSuff = other.getSuffix(); - return thisSuff == otherSuff || thisSuff.equals(otherSuff); + final Query that = (Query) o; + return Objects.equals(getPrefix(), that.getPrefix()) && Objects.equals(getSuffix(), that.getSuffix()); } /** diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/BooleanMap.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/BooleanMap.java index 98d9828180..81ee4185c5 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/BooleanMap.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/BooleanMap.java @@ -177,7 +177,7 @@ public boolean contains(Object o) { } - private class Entry implements Map.Entry { + private final class Entry implements Map.Entry { private final boolean key; @@ -202,7 +202,7 @@ public V setValue(V value) { @Override public int hashCode() { - return (key) ? 1 : 0; + return Boolean.hashCode(key); } @Override @@ -210,14 +210,13 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!(o instanceof de.learnlib.datastructure.discriminationtree.model.BooleanMap.Entry)) { return false; } - @SuppressWarnings("unchecked") - Entry entry = (Entry) o; - - return getKey().equals(entry.getKey()); + final de.learnlib.datastructure.discriminationtree.model.BooleanMap.Entry that = + (de.learnlib.datastructure.discriminationtree.model.BooleanMap.Entry) o; + return Objects.equals(key, that.key); } } diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Error.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Error.java index 66218d9160..b026525adb 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Error.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/Error.java @@ -34,20 +34,19 @@ public Error(Throwable cause) { } @Override - public int hashCode() { - int hash = 5; - hash = 19 * hash + Objects.hashCode(this.id); - return hash; + public final int hashCode() { + return Objects.hashCode(this.id); } @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; + public final boolean equals(Object obj) { + if (this == obj) { + return true; } - if (getClass() != obj.getClass()) { + if (!(obj instanceof Error)) { return false; } + final Error other = (Error) obj; return Objects.equals(this.id, other.id); } diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ReturnValue.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ReturnValue.java index f1eff98179..413f96c8ae 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ReturnValue.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ReturnValue.java @@ -34,20 +34,19 @@ public ReturnValue(Object ret) { } @Override - public int hashCode() { - int hash = 5; - hash = 19 * hash + Objects.hashCode(this.id); - return hash; + public final int hashCode() { + return Objects.hashCode(this.id); } @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; + public final boolean equals(Object obj) { + if (this == obj) { + return true; } - if (getClass() != obj.getClass()) { + if (!(obj instanceof ReturnValue)) { return false; } + final ReturnValue other = (ReturnValue) obj; return Objects.equals(this.id, other.id); } From 71209bfd96079c710462fbbcb4b92e05a3b094ae Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 3 Jan 2019 14:30:47 +0100 Subject: [PATCH 104/125] bump license header to 2019 --- algorithms/active/adt/pom.xml | 2 +- .../main/java/de/learnlib/algorithms/adt/ads/DefensiveADS.java | 2 +- .../adt/src/main/java/de/learnlib/algorithms/adt/adt/ADT.java | 2 +- .../main/java/de/learnlib/algorithms/adt/adt/ADTLeafNode.java | 2 +- .../src/main/java/de/learnlib/algorithms/adt/adt/ADTNode.java | 2 +- .../main/java/de/learnlib/algorithms/adt/adt/ADTResetNode.java | 2 +- .../main/java/de/learnlib/algorithms/adt/adt/ADTSymbolNode.java | 2 +- .../main/java/de/learnlib/algorithms/adt/api/ADTExtender.java | 2 +- .../main/java/de/learnlib/algorithms/adt/api/LeafSplitter.java | 2 +- .../learnlib/algorithms/adt/api/PartialTransitionAnalyzer.java | 2 +- .../java/de/learnlib/algorithms/adt/api/SubtreeReplacer.java | 2 +- .../de/learnlib/algorithms/adt/automaton/ADTHypothesis.java | 2 +- .../java/de/learnlib/algorithms/adt/automaton/ADTState.java | 2 +- .../de/learnlib/algorithms/adt/automaton/ADTTransition.java | 2 +- .../java/de/learnlib/algorithms/adt/config/ADTExtenders.java | 2 +- .../java/de/learnlib/algorithms/adt/config/LeafSplitters.java | 2 +- .../de/learnlib/algorithms/adt/config/SubtreeReplacers.java | 2 +- .../de/learnlib/algorithms/adt/config/model/ADSCalculator.java | 2 +- .../algorithms/adt/config/model/DefensiveADSCalculator.java | 2 +- .../adt/config/model/calculator/AbstractCalculator.java | 2 +- .../adt/config/model/calculator/BestEffortCalculator.java | 2 +- .../config/model/calculator/BestEffortDefensiveCalculator.java | 2 +- .../adt/config/model/calculator/MinLengthCalculator.java | 2 +- .../adt/config/model/calculator/MinSizeCalculator.java | 2 +- .../algorithms/adt/config/model/extender/DefaultExtender.java | 2 +- .../adt/config/model/replacer/ExhaustiveReplacer.java | 2 +- .../adt/config/model/replacer/LevelOrderReplacer.java | 2 +- .../algorithms/adt/config/model/replacer/SingleReplacer.java | 2 +- .../java/de/learnlib/algorithms/adt/learner/ADTLearner.java | 2 +- .../de/learnlib/algorithms/adt/learner/ADTLearnerState.java | 2 +- .../java/de/learnlib/algorithms/adt/model/ExtensionResult.java | 2 +- .../java/de/learnlib/algorithms/adt/model/ObservationTree.java | 2 +- .../de/learnlib/algorithms/adt/model/ReplacementResult.java | 2 +- .../src/main/java/de/learnlib/algorithms/adt/util/ADTUtil.java | 2 +- .../main/java/de/learnlib/algorithms/adt/util/SQOOTBridge.java | 2 +- .../de/learnlib/algorithms/adt/automaton/ADTHypothesisTest.java | 2 +- .../adt/src/test/java/de/learnlib/algorithms/adt/it/ADTIT.java | 2 +- .../test/java/de/learnlib/algorithms/adt/it/MQ2SQWrapper.java | 2 +- .../learnlib/algorithms/adt/learner/ADTGrowingAlphabetTest.java | 2 +- .../algorithms/adt/learner/ADTResumableLearnerTest.java | 2 +- algorithms/active/dhc/pom.xml | 2 +- .../main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java | 2 +- .../java/de/learnlib/algorithms/dhc/mealy/MealyDHCState.java | 2 +- .../algorithms/dhc/mealy/MealyDHCGrowingAlphabetTest.java | 2 +- .../algorithms/dhc/mealy/MealyDHCResumableLearnerTest.java | 2 +- .../java/de/learnlib/algorithms/dhc/mealy/MealyDHCTest.java | 2 +- .../java/de/learnlib/algorithms/dhc/mealy/it/MealyDHCIT.java | 2 +- algorithms/active/discrimination-tree-vpda/pom.xml | 2 +- .../discriminationtree/hypothesis/vpda/AbstractHypTrans.java | 2 +- .../discriminationtree/hypothesis/vpda/BlockList.java | 2 +- .../discriminationtree/hypothesis/vpda/ContextPair.java | 2 +- .../algorithms/discriminationtree/hypothesis/vpda/DTNode.java | 2 +- .../algorithms/discriminationtree/hypothesis/vpda/DTree.java | 2 +- .../discriminationtree/hypothesis/vpda/HypIntTrans.java | 2 +- .../algorithms/discriminationtree/hypothesis/vpda/HypLoc.java | 2 +- .../discriminationtree/hypothesis/vpda/HypRetTrans.java | 2 +- .../discriminationtree/hypothesis/vpda/OneSEVPAHypothesis.java | 2 +- .../discriminationtree/hypothesis/vpda/TransList.java | 2 +- .../algorithms/discriminationtree/vpda/AbstractVPDALearner.java | 2 +- .../algorithms/discriminationtree/vpda/DTLearnerVPDA.java | 2 +- .../learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java | 2 +- algorithms/active/discrimination-tree/pom.xml | 2 +- .../algorithms/discriminationtree/AbstractDTLearner.java | 2 +- .../learnlib/algorithms/discriminationtree/DTLearnerState.java | 2 +- .../algorithms/discriminationtree/dfa/DTLearnerDFA.java | 2 +- .../algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java | 2 +- .../discriminationtree/hypothesis/DTLearnerHypothesis.java | 2 +- .../algorithms/discriminationtree/hypothesis/HState.java | 2 +- .../algorithms/discriminationtree/hypothesis/HTransition.java | 2 +- .../algorithms/discriminationtree/mealy/DTLearnerMealy.java | 2 +- .../discriminationtree/mealy/HypothesisWrapperMealy.java | 2 +- .../discriminationtree/DTLearnerDFAGrowingAlphabetTest.java | 2 +- .../learnlib/algorithms/discriminationtree/DTLearnerDFAIT.java | 2 +- .../discriminationtree/DTLearnerDFAResumableLearnerTest.java | 2 +- .../discriminationtree/DTLearnerMealyGrowingAlphabetTest.java | 2 +- .../algorithms/discriminationtree/DTLearnerMealyIT.java | 2 +- .../discriminationtree/DTLearnerMealyResumableLearnerTest.java | 2 +- algorithms/active/kearns-vazirani/pom.xml | 2 +- .../src/main/java/de/learnlib/algorithms/kv/StateInfo.java | 2 +- .../java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java | 2 +- .../de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAState.java | 2 +- .../de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java | 2 +- .../learnlib/algorithms/kv/mealy/KearnsVaziraniMealyState.java | 2 +- .../algorithms/kv/dfa/KearnsVaziraniDFAGrowingAlphabetTest.java | 2 +- .../java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAIT.java | 2 +- .../kv/dfa/KearnsVaziraniDFAResumableLearnerTest.java | 2 +- .../kv/mealy/KearnsVaziraniMealyGrowingAlphabetTest.java | 2 +- .../de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyIT.java | 2 +- .../kv/mealy/KearnsVaziraniMealyResumableLearnerTest.java | 2 +- algorithms/active/lstar/pom.xml | 2 +- .../de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java | 2 +- .../algorithms/lstar/AbstractExtensibleAutomatonLStar.java | 2 +- .../main/java/de/learnlib/algorithms/lstar/AbstractLStar.java | 2 +- .../java/de/learnlib/algorithms/lstar/AbstractLStarState.java | 2 +- .../java/de/learnlib/algorithms/lstar/AutomatonLStarState.java | 2 +- .../algorithms/lstar/ce/ObservationTableCEXHandler.java | 2 +- .../algorithms/lstar/ce/ObservationTableCEXHandlers.java | 2 +- .../learnlib/algorithms/lstar/closing/CloseRandomStrategy.java | 2 +- .../de/learnlib/algorithms/lstar/closing/ClosingStrategies.java | 2 +- .../de/learnlib/algorithms/lstar/closing/ClosingStrategy.java | 2 +- .../java/de/learnlib/algorithms/lstar/dfa/ClassicLStarDFA.java | 2 +- .../de/learnlib/algorithms/lstar/dfa/ExtensibleLStarDFA.java | 2 +- .../java/de/learnlib/algorithms/lstar/dfa/LStarDFAUtil.java | 2 +- .../de/learnlib/algorithms/lstar/mealy/ClassicLStarMealy.java | 2 +- .../learnlib/algorithms/lstar/mealy/ExtensibleLStarMealy.java | 2 +- .../java/de/learnlib/algorithms/lstar/mealy/LStarMealyUtil.java | 2 +- .../java/de/learnlib/algorithms/malerpnueli/MalerPnueliDFA.java | 2 +- .../de/learnlib/algorithms/malerpnueli/MalerPnueliMealy.java | 2 +- .../learnlib/algorithms/rivestschapire/RivestSchapireDFA.java | 2 +- .../learnlib/algorithms/rivestschapire/RivestSchapireMealy.java | 2 +- .../algorithms/lstar/ExtensibleLStarDFAGrowingAlphabetTest.java | 2 +- .../lstar/ExtensibleLStarDFAResumableLearnerTest.java | 2 +- .../lstar/ExtensibleLStarMealyGrowingAlphabetTest.java | 2 +- .../lstar/ExtensibleLStarMealyResumableLearnerTest.java | 2 +- .../test/java/de/learnlib/algorithms/lstar/LStarDFATest.java | 2 +- .../test/java/de/learnlib/algorithms/lstar/LStarMealyTest.java | 2 +- .../test/java/de/learnlib/algorithms/lstar/LearningTest.java | 2 +- .../algorithms/lstar/MalerPnueliDFAGrowingAlphabetTest.java | 2 +- .../algorithms/lstar/MalerPnueliDFAResumableLearnerTest.java | 2 +- .../algorithms/lstar/MalerPnueliMealyGrowingAlphabetTest.java | 2 +- .../algorithms/lstar/MalerPnueliMealyResumableLearnerTest.java | 2 +- .../algorithms/lstar/RivestSchapireDFAGrowingAlphabetTest.java | 2 +- .../algorithms/lstar/RivestSchapireDFAResumableLearnerTest.java | 2 +- .../lstar/RivestSchapireMealyGrowingAlphabetTest.java | 2 +- .../lstar/RivestSchapireMealyResumableLearnerTest.java | 2 +- .../de/learnlib/algorithms/lstar/it/ClassicLStarMealyIT.java | 2 +- .../de/learnlib/algorithms/lstar/it/ExtensibleLStarDFAIT.java | 2 +- .../de/learnlib/algorithms/lstar/it/ExtensibleLStarMealyIT.java | 2 +- algorithms/active/nlstar/pom.xml | 2 +- .../main/java/de/learnlib/algorithms/nlstar/Inconsistency.java | 2 +- .../main/java/de/learnlib/algorithms/nlstar/NLStarLearner.java | 2 +- .../java/de/learnlib/algorithms/nlstar/ObservationTable.java | 2 +- .../nlstar/src/main/java/de/learnlib/algorithms/nlstar/Row.java | 2 +- .../src/test/java/de/learnlib/algorithms/nlstar/NLStarIT.java | 2 +- algorithms/active/pom.xml | 2 +- algorithms/active/ttt-vpda/pom.xml | 2 +- .../java/de/learnlib/algorithms/ttt/vpda/ExtractRecord.java | 2 +- .../java/de/learnlib/algorithms/ttt/vpda/GlobalSplitter.java | 2 +- .../main/java/de/learnlib/algorithms/ttt/vpda/NonDetState.java | 2 +- .../de/learnlib/algorithms/ttt/vpda/NondetStackContents.java | 2 +- .../de/learnlib/algorithms/ttt/vpda/OutputInconsistency.java | 2 +- .../src/main/java/de/learnlib/algorithms/ttt/vpda/Splitter.java | 2 +- .../java/de/learnlib/algorithms/ttt/vpda/TTTLearnerVPDA.java | 2 +- .../de/learnlib/algorithms/ttt/dfa/it/TTTLearnerVPDAIT.java | 2 +- algorithms/active/ttt/pom.xml | 2 +- .../de/learnlib/algorithms/ttt/base/AbstractBaseDTNode.java | 2 +- .../de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java | 2 +- .../de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java | 2 +- .../learnlib/algorithms/ttt/base/BaseTTTDiscriminationTree.java | 2 +- .../main/java/de/learnlib/algorithms/ttt/base/BlockList.java | 2 +- .../algorithms/ttt/base/HypothesisChangedException.java | 2 +- .../main/java/de/learnlib/algorithms/ttt/base/IncomingList.java | 2 +- .../de/learnlib/algorithms/ttt/base/OutputInconsistency.java | 2 +- .../java/de/learnlib/algorithms/ttt/base/TTTEventListener.java | 2 +- .../java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java | 2 +- .../src/main/java/de/learnlib/algorithms/ttt/base/TTTState.java | 2 +- .../java/de/learnlib/algorithms/ttt/base/TTTTransition.java | 2 +- .../de/learnlib/algorithms/ttt/dfa/PrefixTTTLearnerDFA.java | 2 +- .../main/java/de/learnlib/algorithms/ttt/dfa/TTTDTNodeDFA.java | 2 +- .../java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java | 2 +- .../main/java/de/learnlib/algorithms/ttt/dfa/TTTLearnerDFA.java | 2 +- .../main/java/de/learnlib/algorithms/ttt/dfa/TTTStateDFA.java | 2 +- .../java/de/learnlib/algorithms/ttt/mealy/TTTDTNodeMealy.java | 2 +- .../de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java | 2 +- .../java/de/learnlib/algorithms/ttt/mealy/TTTLearnerMealy.java | 2 +- .../de/learnlib/algorithms/ttt/mealy/TTTTransitionMealy.java | 2 +- .../de/learnlib/algorithms/ttt/TTTDFAGrowingAlphabetTest.java | 2 +- .../algorithms/ttt/TTTLearnerDFAResumableLearnerTest.java | 2 +- .../algorithms/ttt/TTTLearnerMealyGrowingAlphabetTest.java | 2 +- .../algorithms/ttt/TTTLearnerMealyResumableLearnerTest.java | 2 +- .../learnlib/algorithms/ttt/dfa/it/PrefixTTTLearnerDFAIT.java | 2 +- .../java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerDFAIT.java | 2 +- .../de/learnlib/algorithms/ttt/mealy/it/TTTLearnerMealyIT.java | 2 +- algorithms/passive/pom.xml | 2 +- algorithms/passive/rpni-edsm/pom.xml | 2 +- .../java/de/learnlib/algorithms/rpni/BlueFringeEDSMDFA.java | 2 +- .../src/main/java/de/learnlib/algorithms/rpni/EDSMUtil.java | 2 +- .../test/java/de/learnlib/algorithms/rpni/EDSMScoreTest.java | 2 +- .../src/test/java/de/learnlib/algorithms/rpni/it/EdsmDfaIT.java | 2 +- algorithms/passive/rpni-mdl/pom.xml | 2 +- .../main/java/de/learnlib/algorithms/rpni/BlueFringeMDLDFA.java | 2 +- .../src/main/java/de/learnlib/algorithms/rpni/MDLUtil.java | 2 +- .../src/test/java/de/learnlib/algorithms/rpni/MDLScoreTest.java | 2 +- .../src/test/java/de/learnlib/algorithms/rpni/it/MdlDfaIT.java | 2 +- algorithms/passive/rpni/pom.xml | 2 +- .../de/learnlib/algorithms/rpni/AbstractBlueFringeRPNI.java | 2 +- .../java/de/learnlib/algorithms/rpni/BlueFringeRPNIDFA.java | 2 +- .../java/de/learnlib/algorithms/rpni/BlueFringeRPNIMealy.java | 2 +- .../src/test/java/de/learnlib/algorithms/rpni/it/RpniDfaIT.java | 2 +- .../test/java/de/learnlib/algorithms/rpni/it/RpniMealyIT.java | 2 +- algorithms/pom.xml | 2 +- api/pom.xml | 2 +- api/src/main/java/de/learnlib/api/AccessSequenceProvider.java | 2 +- .../main/java/de/learnlib/api/AccessSequenceTransformer.java | 2 +- api/src/main/java/de/learnlib/api/Mapper.java | 2 +- api/src/main/java/de/learnlib/api/ObservableSUL.java | 2 +- api/src/main/java/de/learnlib/api/SUL.java | 2 +- .../main/java/de/learnlib/api/algorithm/LearningAlgorithm.java | 2 +- api/src/main/java/de/learnlib/api/algorithm/NFALearner.java | 2 +- .../de/learnlib/api/algorithm/PassiveLearningAlgorithm.java | 2 +- .../de/learnlib/api/algorithm/feature/GlobalSuffixFeature.java | 2 +- .../de/learnlib/api/algorithm/feature/GlobalSuffixLearner.java | 2 +- .../de/learnlib/api/algorithm/feature/ResumableLearner.java | 2 +- .../learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java | 2 +- api/src/main/java/de/learnlib/api/exception/SULException.java | 2 +- api/src/main/java/de/learnlib/api/logging/Category.java | 2 +- api/src/main/java/de/learnlib/api/logging/LearnLogger.java | 2 +- .../java/de/learnlib/api/logging/LoggingPropertyOracle.java | 2 +- api/src/main/java/de/learnlib/api/logging/Slf4jDelegator.java | 2 +- api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/Filter.java | 2 +- api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java | 2 +- .../main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/LassoOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java | 2 +- .../main/java/de/learnlib/api/oracle/OmegaMembershipOracle.java | 2 +- .../main/java/de/learnlib/api/oracle/OmegaQueryAnswerer.java | 2 +- api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/QueryAnswerer.java | 2 +- .../java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java | 2 +- api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java | 2 +- api/src/main/java/de/learnlib/api/query/AbstractQuery.java | 2 +- api/src/main/java/de/learnlib/api/query/DefaultQuery.java | 2 +- api/src/main/java/de/learnlib/api/query/OmegaQuery.java | 2 +- api/src/main/java/de/learnlib/api/query/Query.java | 2 +- .../java/de/learnlib/api/setting/LearnLibSettingsSource.java | 2 +- api/src/main/java/de/learnlib/api/statistic/StatisticData.java | 2 +- .../main/java/de/learnlib/api/statistic/StatisticLearner.java | 2 +- .../main/java/de/learnlib/api/statistic/StatisticOracle.java | 2 +- api/src/main/java/de/learnlib/api/statistic/StatisticSUL.java | 2 +- api/src/test/java/de/learnlib/api/logging/LearnLoggerTest.java | 2 +- archetypes/basic/pom.xml | 2 +- .../resources-template/META-INF/maven/archetype-metadata.xml | 2 +- archetypes/basic/src/main/resources/archetype-resources/pom.xml | 2 +- archetypes/complete/pom.xml | 2 +- .../resources-template/META-INF/maven/archetype-metadata.xml | 2 +- .../complete/src/main/resources/archetype-resources/pom.xml | 2 +- archetypes/pom.xml | 2 +- build-parent/pom.xml | 2 +- build-tools/deploy-site.sh | 2 +- build-tools/fix-license.sh | 2 +- build-tools/license-header.txt | 2 +- build-tools/pom.xml | 2 +- .../src/main/resources/automatalib-learnlib-checkstyle.xml | 2 +- .../src/main/resources/learnlib-checkstyle-suppressions.xml | 2 +- .../src/main/resources/learnlib-pmd-exclusions.properties | 2 +- build-tools/src/main/resources/learnlib-pmd-ruleset.xml | 2 +- build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml | 2 +- build-tools/src/main/resources/license-header-java.txt | 2 +- build-tools/src/main/resources/license-header-xml.txt | 2 +- commons/acex/pom.xml | 2 +- .../src/main/java/de/learnlib/acex/AbstractCounterexample.java | 2 +- commons/acex/src/main/java/de/learnlib/acex/AcexAnalyzer.java | 2 +- .../de/learnlib/acex/analyzers/AbstractNamedAcexAnalyzer.java | 2 +- .../java/de/learnlib/acex/analyzers/AcexAnalysisAlgorithms.java | 2 +- .../src/main/java/de/learnlib/acex/analyzers/AcexAnalyzers.java | 2 +- .../java/de/learnlib/acex/impl/AbstractBaseCounterexample.java | 2 +- .../src/test/java/de/learnlib/acex/analyzers/AnalyzersTest.java | 2 +- .../src/test/java/de/learnlib/acex/analyzers/DummyAcex.java | 2 +- commons/counterexamples/pom.xml | 2 +- .../java/de/learnlib/counterexamples/AcexLocalSuffixFinder.java | 2 +- .../java/de/learnlib/counterexamples/GlobalSuffixFinder.java | 2 +- .../java/de/learnlib/counterexamples/GlobalSuffixFinders.java | 2 +- .../java/de/learnlib/counterexamples/LocalSuffixFinder.java | 2 +- .../java/de/learnlib/counterexamples/LocalSuffixFinders.java | 2 +- .../counterexamples/acex/ClassicPrefixTransformAcex.java | 2 +- .../counterexamples/acex/MealyOutInconsPrefixTransformAcex.java | 2 +- .../counterexamples/acex/OutInconsPrefixTransformAcex.java | 2 +- commons/pom.xml | 2 +- commons/settings/pom.xml | 2 +- .../src/main/java/de/learnlib/setting/LearnLibProperty.java | 2 +- .../src/main/java/de/learnlib/setting/LearnLibSettings.java | 2 +- .../LearnLibLocalPropertiesAutomataLibSettingsSource.java | 2 +- .../learnlib/setting/sources/LearnLibLocalPropertiesSource.java | 2 +- .../sources/LearnLibPropertiesAutomataLibSettingsSource.java | 2 +- .../de/learnlib/setting/sources/LearnLibPropertiesSource.java | 2 +- .../setting/sources/LearnLibSystemPropertiesSource.java | 2 +- .../src/test/java/de/learnlib/setting/LearnLibSettingsTest.java | 2 +- commons/util/pom.xml | 2 +- .../util/src/main/java/de/learnlib/util/AbstractBFOracle.java | 2 +- commons/util/src/main/java/de/learnlib/util/Experiment.java | 2 +- commons/util/src/main/java/de/learnlib/util/MQUtil.java | 2 +- .../main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java | 2 +- .../util/src/main/java/de/learnlib/util/mealy/MealyUtil.java | 2 +- .../main/java/de/learnlib/util/mealy/SymbolOracleWrapper.java | 2 +- .../src/main/java/de/learnlib/util/nfa/NFALearnerWrapper.java | 2 +- .../main/java/de/learnlib/util/statistics/SimpleProfiler.java | 2 +- commons/util/src/test/java/de/learnlib/util/ExperimentTest.java | 2 +- datastructures/discrimination-tree/pom.xml | 2 +- .../learnlib/datastructure/discriminationtree/BinaryDTNode.java | 2 +- .../learnlib/datastructure/discriminationtree/BinaryDTree.java | 2 +- .../learnlib/datastructure/discriminationtree/MultiDTNode.java | 2 +- .../learnlib/datastructure/discriminationtree/MultiDTree.java | 2 +- .../de/learnlib/datastructure/discriminationtree/SplitData.java | 2 +- .../iterators/DiscriminationTreeIterators.java | 2 +- .../discriminationtree/iterators/NodeIterator.java | 2 +- .../datastructure/discriminationtree/model/AbstractDTNode.java | 2 +- .../discriminationtree/model/AbstractDiscriminationTree.java | 2 +- .../model/AbstractTemporaryIntrusiveDTNode.java | 2 +- .../discriminationtree/model/AbstractWordBasedDTNode.java | 2 +- .../model/AbstractWordBasedDiscriminationTree.java | 2 +- .../datastructure/discriminationtree/model/BooleanMap.java | 2 +- .../datastructure/discriminationtree/model/LCAInfo.java | 2 +- .../de/learnlib/datastructure/discriminationtree/DummyDT.java | 2 +- .../datastructure/discriminationtree/IteratorsTest.java | 2 +- .../de/learnlib/datastructure/discriminationtree/LCATest.java | 2 +- .../datastructure/discriminationtree/VisualizationTest.java | 2 +- datastructures/list/pom.xml | 2 +- .../main/java/de/learnlib/datastructure/list/IntrusiveList.java | 2 +- .../java/de/learnlib/datastructure/list/IntrusiveListElem.java | 2 +- .../de/learnlib/datastructure/list/IntrusiveListElemImpl.java | 2 +- datastructures/observation-table/pom.xml | 2 +- .../datastructure/observationtable/GenericObservationTable.java | 2 +- .../learnlib/datastructure/observationtable/Inconsistency.java | 2 +- .../datastructure/observationtable/InvalidRowException.java | 2 +- .../datastructure/observationtable/MutableObservationTable.java | 2 +- .../de/learnlib/datastructure/observationtable/OTLearner.java | 2 +- .../de/learnlib/datastructure/observationtable/OTUtils.java | 2 +- .../datastructure/observationtable/ObservationTable.java | 2 +- .../datastructure/observationtable/ObservationTableFeature.java | 2 +- .../java/de/learnlib/datastructure/observationtable/Row.java | 2 +- .../de/learnlib/datastructure/observationtable/RowImpl.java | 2 +- .../observationtable/reader/ObservationTableReader.java | 2 +- .../observationtable/reader/SimpleObservationTable.java | 2 +- .../observationtable/reader/SuffixASCIIReader.java | 2 +- .../observationtable/writer/AbstractObservationTableWriter.java | 2 +- .../observationtable/writer/ObservationTableASCIIWriter.java | 2 +- .../observationtable/writer/ObservationTableHTMLWriter.java | 2 +- .../observationtable/writer/ObservationTableWriter.java | 2 +- .../observationtable/writer/SuffixASCIIWriter.java | 2 +- .../datastructure/observationtable/MockedObservationTable.java | 2 +- .../datastructure/observationtable/ObservationTableSource.java | 2 +- .../observationtable/writer/ObservationTableWriterTest.java | 2 +- .../observationtable/writer/SuffixASCIIWriterTest.java | 2 +- datastructures/pom.xml | 2 +- datastructures/pta/pom.xml | 2 +- .../datastructure/pta/bluefringe/DefaultProcessingOrders.java | 2 +- .../learnlib/datastructure/pta/bluefringe/ProcessingOrder.java | 2 +- .../de/learnlib/datastructure/pta/pta/AbstractBasePTAState.java | 2 +- .../learnlib/datastructure/pta/pta/AbstractBlueFringePTA.java | 2 +- .../datastructure/pta/pta/AbstractBlueFringePTAState.java | 2 +- .../main/java/de/learnlib/datastructure/pta/pta/BasePTA.java | 2 +- .../java/de/learnlib/datastructure/pta/pta/BlueFringePTA.java | 2 +- .../de/learnlib/datastructure/pta/pta/BlueFringePTAState.java | 2 +- .../java/de/learnlib/datastructure/pta/pta/PTATransition.java | 2 +- .../datastructure/pta/pta/PropertyConflictException.java | 2 +- .../java/de/learnlib/datastructure/pta/pta/RedBlueMerge.java | 2 +- .../java/de/learnlib/datastructure/pta/MergedAutomatonTest.java | 2 +- distribution/pom.xml | 2 +- distribution/src/main/assembly/learnlib-bundle.xml | 2 +- distribution/src/main/assembly/learnlib-dependencies-bundle.xml | 2 +- distribution/src/main/assembly/learnlib-sources-jar.xml | 2 +- drivers/basic/pom.xml | 2 +- .../basic/src/main/java/de/learnlib/drivers/api/TestDriver.java | 2 +- .../java/de/learnlib/drivers/reflect/ConcreteMethodInput.java | 2 +- .../basic/src/main/java/de/learnlib/drivers/reflect/Error.java | 2 +- .../src/main/java/de/learnlib/drivers/reflect/MethodInput.java | 2 +- .../src/main/java/de/learnlib/drivers/reflect/MethodOutput.java | 2 +- .../src/main/java/de/learnlib/drivers/reflect/ReturnValue.java | 2 +- .../java/de/learnlib/drivers/reflect/SimplePOJODataMapper.java | 2 +- .../java/de/learnlib/drivers/reflect/SimplePOJOTestDriver.java | 2 +- .../src/main/java/de/learnlib/drivers/reflect/Unobserved.java | 2 +- .../src/test/java/de/learnlib/drivers/reflect/ObjectTest.java | 2 +- .../java/de/learnlib/drivers/reflect/StackWithException.java | 2 +- .../test/java/de/learnlib/drivers/reflect/StackWithNull.java | 2 +- drivers/mapper/pom.xml | 2 +- .../de/learnlib/mapper/AbstractContextExecutableInputSUL.java | 2 +- .../main/java/de/learnlib/mapper/ContextExecutableInputSUL.java | 2 +- .../src/main/java/de/learnlib/mapper/ExecutableInputSUL.java | 2 +- drivers/mapper/src/main/java/de/learnlib/mapper/MappedSUL.java | 2 +- .../src/main/java/de/learnlib/mapper/MapperComposition.java | 2 +- drivers/mapper/src/main/java/de/learnlib/mapper/Mappers.java | 2 +- .../src/main/java/de/learnlib/mapper/SULMapperComposition.java | 2 +- drivers/mapper/src/main/java/de/learnlib/mapper/SULMappers.java | 2 +- .../mapper/src/main/java/de/learnlib/mapper/StringMapper.java | 2 +- .../java/de/learnlib/mapper/api/ContextExecutableInput.java | 2 +- .../src/main/java/de/learnlib/mapper/api/ExecutableInput.java | 2 +- .../mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java | 2 +- .../src/test/java/de/learnlib/mapper/MapperCompositionTest.java | 2 +- .../test/java/de/learnlib/mapper/SULMapperCompositionTest.java | 2 +- drivers/pom.xml | 2 +- drivers/simulator/pom.xml | 2 +- .../main/java/de/learnlib/driver/util/MealySimulatorSUL.java | 2 +- examples/pom.xml | 2 +- examples/src/main/java/de/learnlib/examples/Example1.java | 2 +- examples/src/main/java/de/learnlib/examples/Example2.java | 2 +- examples/src/main/java/de/learnlib/examples/Example3.java | 2 +- examples/src/main/java/de/learnlib/examples/bbc/Example1.java | 2 +- examples/src/main/java/de/learnlib/examples/bbc/Example2.java | 2 +- examples/src/main/java/de/learnlib/examples/bbc/Example3.java | 2 +- examples/src/main/java/de/learnlib/examples/bbc/Example4.java | 2 +- examples/src/test/java/de/learnlib/examples/ExamplesTest.java | 2 +- .../de/learnlib/oracle/emptiness/AbstractBFEmptinessOracle.java | 2 +- .../java/de/learnlib/oracle/emptiness/DFABFEmptinessOracle.java | 2 +- .../learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java | 2 +- .../de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java | 2 +- .../de/learnlib/oracle/emptiness/MealyBFEmptinessOracle.java | 2 +- .../oracle/emptiness/MealyLassoEmptinessOracleImpl.java | 2 +- .../oracle/emptiness/AbstractBFEmptinessOracleTest.java | 2 +- .../oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java | 2 +- .../de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java | 2 +- .../oracle/emptiness/DFALassoEmptinessOracleImplTest.java | 2 +- .../learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.java | 2 +- .../oracle/emptiness/MealyLassoEmptinessOracleImplTest.java | 2 +- oracles/equivalence-oracles/pom.xml | 2 +- .../learnlib/oracle/equivalence/AbstractBFInclusionOracle.java | 2 +- .../learnlib/oracle/equivalence/AbstractTestWordEQOracle.java | 2 +- .../java/de/learnlib/oracle/equivalence/CExFirstOracle.java | 2 +- .../oracle/equivalence/CompleteExplorationEQOracle.java | 2 +- .../de/learnlib/oracle/equivalence/DFABFInclusionOracle.java | 2 +- .../java/de/learnlib/oracle/equivalence/DelegateEQOracle.java | 2 +- .../de/learnlib/oracle/equivalence/DisproveFirstOracle.java | 2 +- .../main/java/de/learnlib/oracle/equivalence/EQOracleChain.java | 2 +- .../java/de/learnlib/oracle/equivalence/EquivalenceQueries.java | 2 +- .../learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java | 2 +- .../de/learnlib/oracle/equivalence/MealyBFInclusionOracle.java | 2 +- .../de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java | 2 +- .../de/learnlib/oracle/equivalence/RandomWordsEQOracle.java | 2 +- .../de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java | 2 +- .../java/de/learnlib/oracle/equivalence/SampleSetEQOracle.java | 2 +- .../java/de/learnlib/oracle/equivalence/SimpleEQOracle.java | 2 +- .../java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java | 2 +- .../java/de/learnlib/oracle/equivalence/WMethodEQOracle.java | 2 +- .../java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java | 2 +- .../learnlib/oracle/equivalence/mealy/RandomWalkEQOracle.java | 2 +- .../oracle/equivalence/mealy/SymbolEQOracleWrapper.java | 2 +- .../oracle/equivalence/vpda/RandomWellMatchedWordsEQOracle.java | 2 +- .../de/learnlib/oracle/equivalence/vpda/SimulatorEQOracle.java | 2 +- .../oracle/equivalence/AbstractBFInclusionOracleTest.java | 2 +- .../de/learnlib/oracle/equivalence/AbstractEQOracleTest.java | 2 +- .../java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java | 2 +- .../learnlib/oracle/equivalence/DFABFInclusionOracleTest.java | 2 +- .../de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java | 2 +- .../learnlib/oracle/equivalence/EmptyAutomatonOracleTest.java | 2 +- .../learnlib/oracle/equivalence/MealyBFInclusionOracleTest.java | 2 +- .../learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java | 2 +- .../de/learnlib/oracle/equivalence/RandomWordsEQOracleTest.java | 2 +- .../learnlib/oracle/equivalence/RandomWpMethodEQOracleTest.java | 2 +- .../de/learnlib/oracle/equivalence/SampleSetEQOracleTest.java | 2 +- .../learnlib/oracle/equivalence/TestWordEQOracleBatchTest.java | 2 +- .../oracle/equivalence/mealy/RandomWalkEQOracleTest.java | 2 +- .../equivalence/vpda/RandomWellMatchedWordsEQOracleTest.java | 2 +- oracles/filters/cache/pom.xml | 2 +- .../src/main/java/de/learnlib/filter/cache/LearningCache.java | 2 +- .../main/java/de/learnlib/filter/cache/LearningCacheOracle.java | 2 +- .../de/learnlib/filter/cache/dfa/DFACacheConsistencyTest.java | 2 +- .../main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java | 2 +- .../src/main/java/de/learnlib/filter/cache/dfa/DFACaches.java | 2 +- .../learnlib/filter/cache/dfa/DFAHashCacheConsistencyTest.java | 2 +- .../java/de/learnlib/filter/cache/dfa/DFAHashCacheOracle.java | 2 +- .../src/main/java/de/learnlib/filter/cache/dfa/ProxyQuery.java | 2 +- .../main/java/de/learnlib/filter/cache/mealy/MasterQuery.java | 2 +- .../learnlib/filter/cache/mealy/MealyCacheConsistencyTest.java | 2 +- .../java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java | 2 +- .../main/java/de/learnlib/filter/cache/mealy/MealyCaches.java | 2 +- .../java/de/learnlib/filter/cache/mealy/SymbolQueryCache.java | 2 +- .../src/main/java/de/learnlib/filter/cache/sul/SULCache.java | 2 +- .../src/main/java/de/learnlib/filter/cache/sul/SULCaches.java | 2 +- .../test/java/de/learnlib/filter/cache/AbstractCacheTest.java | 2 +- .../src/test/java/de/learnlib/filter/cache/CacheTestUtils.java | 2 +- .../java/de/learnlib/filter/cache/dfa/AbstractDFACacheTest.java | 2 +- .../test/java/de/learnlib/filter/cache/dfa/DFADAGCacheTest.java | 2 +- .../java/de/learnlib/filter/cache/dfa/DFAHashCacheTest.java | 2 +- .../java/de/learnlib/filter/cache/dfa/DFATreeCacheTest.java | 2 +- .../de/learnlib/filter/cache/mealy/AbstractMealyCacheTest.java | 2 +- .../java/de/learnlib/filter/cache/mealy/MealyDAGCacheTest.java | 2 +- .../de/learnlib/filter/cache/mealy/MealyDAGMapperCacheTest.java | 2 +- .../java/de/learnlib/filter/cache/mealy/MealyTreeCacheTest.java | 2 +- .../learnlib/filter/cache/mealy/MealyTreeMapperCacheTest.java | 2 +- .../de/learnlib/filter/cache/mealy/SymbolQueryCacheTest.java | 2 +- .../java/de/learnlib/filter/cache/sul/AbstractSULCacheTest.java | 2 +- .../test/java/de/learnlib/filter/cache/sul/SULDAGCacheTest.java | 2 +- .../java/de/learnlib/filter/cache/sul/SULTreeCacheTest.java | 2 +- oracles/filters/pom.xml | 2 +- oracles/filters/reuse/pom.xml | 2 +- .../main/java/de/learnlib/filter/reuse/ReuseCapableOracle.java | 2 +- .../src/main/java/de/learnlib/filter/reuse/ReuseException.java | 2 +- .../src/main/java/de/learnlib/filter/reuse/ReuseOracle.java | 2 +- .../main/java/de/learnlib/filter/reuse/tree/BoundedDeque.java | 2 +- .../src/main/java/de/learnlib/filter/reuse/tree/ReuseEdge.java | 2 +- .../src/main/java/de/learnlib/filter/reuse/tree/ReuseNode.java | 2 +- .../src/main/java/de/learnlib/filter/reuse/tree/ReuseTree.java | 2 +- .../java/de/learnlib/filter/reuse/tree/ReuseTreeDotHelper.java | 2 +- .../java/de/learnlib/filter/reuse/tree/SystemStateHandler.java | 2 +- .../java/de/learnlib/filter/reuse/test/DomainKnowledgeTest.java | 2 +- .../test/java/de/learnlib/filter/reuse/test/LearningTest.java | 2 +- .../test/java/de/learnlib/filter/reuse/test/QuiescenceTest.java | 2 +- .../java/de/learnlib/filter/reuse/test/ReuseOracleTest.java | 2 +- oracles/filters/statistics/pom.xml | 2 +- .../de/learnlib/filter/statistic/AbstractStatisticData.java | 2 +- .../src/main/java/de/learnlib/filter/statistic/Counter.java | 2 +- .../java/de/learnlib/filter/statistic/HistogramDataSet.java | 2 +- .../filter/statistic/learner/RefinementCounterLearner.java | 2 +- .../java/de/learnlib/filter/statistic/oracle/CounterOracle.java | 2 +- .../filter/statistic/oracle/CounterSymbolQueryOracle.java | 2 +- .../de/learnlib/filter/statistic/oracle/HistogramOracle.java | 2 +- .../de/learnlib/filter/statistic/oracle/JointCounterOracle.java | 2 +- .../filter/statistic/sul/ResetCounterObservableSUL.java | 2 +- .../java/de/learnlib/filter/statistic/sul/ResetCounterSUL.java | 2 +- .../filter/statistic/sul/SymbolCounterObservableSUL.java | 2 +- .../java/de/learnlib/filter/statistic/sul/SymbolCounterSUL.java | 2 +- .../java/de/learnlib/filter/statistic/CounterOracleTest.java | 2 +- .../learnlib/filter/statistic/oracles/ConstantOutputOracle.java | 2 +- .../java/de/learnlib/filter/statistic/oracles/NoopOracle.java | 2 +- .../learnlib/filter/statistic/queries/AbstractTestQueries.java | 2 +- .../java/de/learnlib/filter/statistic/queries/NoopQuery.java | 2 +- .../de/learnlib/filter/statistic/queries/UnanswerableQuery.java | 2 +- oracles/membership-oracles/pom.xml | 2 +- .../de/learnlib/oracle/membership/AbstractSULOmegaOracle.java | 2 +- .../main/java/de/learnlib/oracle/membership/FilterChain.java | 2 +- .../main/java/de/learnlib/oracle/membership/MappedOracle.java | 2 +- .../src/main/java/de/learnlib/oracle/membership/SULOracle.java | 2 +- .../de/learnlib/oracle/membership/SULSymbolQueryOracle.java | 2 +- .../de/learnlib/oracle/membership/SimulatorOmegaOracle.java | 2 +- .../java/de/learnlib/oracle/membership/SimulatorOracle.java | 2 +- .../de/learnlib/oracle/membership/SimulatorOmegaOracleTest.java | 2 +- .../java/de/learnlib/oracle/membership/SimulatorOracleTest.java | 2 +- oracles/parallelism/pom.xml | 2 +- .../java/de/learnlib/oracle/parallelism/AbstractQueriesJob.java | 2 +- .../de/learnlib/oracle/parallelism/DynamicParallelOracle.java | 2 +- .../oracle/parallelism/DynamicParallelOracleBuilder.java | 2 +- .../java/de/learnlib/oracle/parallelism/DynamicQueriesJob.java | 2 +- .../java/de/learnlib/oracle/parallelism/ParallelOracle.java | 2 +- .../de/learnlib/oracle/parallelism/ParallelOracleBuilders.java | 2 +- .../oracle/parallelism/ParallelOracleInterruptedException.java | 2 +- .../de/learnlib/oracle/parallelism/StaticParallelOracle.java | 2 +- .../oracle/parallelism/StaticParallelOracleBuilder.java | 2 +- .../java/de/learnlib/oracle/parallelism/StaticQueriesJob.java | 2 +- .../learnlib/oracle/parallelism/DynamicParallelOracleTest.java | 2 +- .../learnlib/oracle/parallelism/StaticParallelOracleTest.java | 2 +- oracles/pom.xml | 2 +- .../de/learnlib/oracle/property/AbstractPropertyOracle.java | 2 +- .../de/learnlib/oracle/property/DFAFinitePropertyOracle.java | 2 +- .../de/learnlib/oracle/property/DFALassoPropertyOracle.java | 2 +- .../de/learnlib/oracle/property/MealyFinitePropertyOracle.java | 2 +- .../de/learnlib/oracle/property/MealyLassoPropertyOracle.java | 2 +- .../java/de/learnlib/oracle/property/PropertyOracleChain.java | 2 +- pom.xml | 2 +- test-support/learner-it-support/pom.xml | 2 +- .../learnlib/testsupport/it/learner/AbstractDFALearnerIT.java | 2 +- .../testsupport/it/learner/AbstractDFAPassiveLearnerIT.java | 2 +- .../learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java | 2 +- .../testsupport/it/learner/AbstractMealyPassiveLearnerIT.java | 2 +- .../testsupport/it/learner/AbstractMealySymLearnerIT.java | 2 +- .../learnlib/testsupport/it/learner/AbstractVPDALearnerIT.java | 2 +- .../java/de/learnlib/testsupport/it/learner/LearnerITUtil.java | 2 +- .../java/de/learnlib/testsupport/it/learner/LearnerVariant.java | 2 +- .../learnlib/testsupport/it/learner/LearnerVariantITCase.java | 2 +- .../de/learnlib/testsupport/it/learner/LearnerVariantList.java | 2 +- .../learnlib/testsupport/it/learner/LearnerVariantListImpl.java | 2 +- .../learnlib/testsupport/it/learner/PassiveLearnerVariant.java | 2 +- .../testsupport/it/learner/PassiveLearnerVariantList.java | 2 +- .../testsupport/it/learner/PassiveLearnerVariantListImpl.java | 2 +- .../testsupport/it/learner/PassiveLearnerVariantTICase.java | 2 +- .../de/learnlib/testsupport/it/learner/VPDALearnerITCase.java | 2 +- test-support/learning-examples/pom.xml | 2 +- .../main/java/de/learnlib/examples/DefaultLearningExample.java | 2 +- .../de/learnlib/examples/DefaultPassiveLearningExample.java | 2 +- .../src/main/java/de/learnlib/examples/LearningExample.java | 2 +- .../src/main/java/de/learnlib/examples/LearningExamples.java | 2 +- .../main/java/de/learnlib/examples/PassiveLearningExample.java | 2 +- .../src/main/java/de/learnlib/examples/dfa/DFABenchmarks.java | 2 +- .../src/main/java/de/learnlib/examples/dfa/ExampleAngluin.java | 2 +- .../src/main/java/de/learnlib/examples/dfa/ExampleKeylock.java | 2 +- .../main/java/de/learnlib/examples/dfa/ExamplePaulAndMary.java | 2 +- .../main/java/de/learnlib/examples/dfa/ExampleRandomDFA.java | 2 +- .../src/main/java/de/learnlib/examples/dfa/ExampleTinyDFA.java | 2 +- .../java/de/learnlib/examples/mealy/ExampleCoffeeMachine.java | 2 +- .../src/main/java/de/learnlib/examples/mealy/ExampleGrid.java | 2 +- .../java/de/learnlib/examples/mealy/ExampleRandomMealy.java | 2 +- .../java/de/learnlib/examples/mealy/ExampleShahbazGroz.java | 2 +- .../src/main/java/de/learnlib/examples/mealy/ExampleStack.java | 2 +- .../main/java/de/learnlib/examples/mealy/ExampleTinyMealy.java | 2 +- test-support/pom.xml | 2 +- .../main/java/de/learnlib/testsupport/AbstractBFOracleTest.java | 2 +- .../de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java | 2 +- .../learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java | 2 +- .../de/learnlib/testsupport/AbstractGrowingAlphabetTest.java | 2 +- .../learnlib/testsupport/AbstractResumableLearnerDFATest.java | 2 +- .../learnlib/testsupport/AbstractResumableLearnerMealyTest.java | 2 +- .../de/learnlib/testsupport/AbstractResumableLearnerTest.java | 2 +- 585 files changed, 585 insertions(+), 585 deletions(-) diff --git a/algorithms/active/adt/pom.xml b/algorithms/active/adt/pom.xml index e7a836c2d2..191dfceba5 100644 --- a/algorithms/active/adt/pom.xml +++ b/algorithms/active/adt/pom.xml @@ -1,6 +1,6 @@ + + org.slf4j + slf4j-api + @@ -113,5 +117,10 @@ limitations under the License. learnlib-membership-oracles test + + de.learnlib + learnlib-drivers-simulator + test + diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java index a46e680773..68f0fc5b2c 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java @@ -77,7 +77,7 @@ public A getHypothesisModel() { protected abstract A exposeInternalHypothesis(); @Override - public final void startLearning() { + public void startLearning() { super.startLearning(); updateInternalHypothesis(); } @@ -126,11 +126,14 @@ protected void updateInternalHypothesis() { I input = alphabet.getSymbol(i); Row succ = sp.getSuccessor(i); - int succId = succ.getRowContentId(); - S succState = stateInfos.get(succId).getState(); + if (succ != null) { + int succId = succ.getRowContentId(); - setTransition(state, input, succState, sp, i); + S succState = stateInfos.get(succId).getState(); + + setTransition(state, input, succState, sp, i); + } } } } diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/PartialLStarMealy.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/PartialLStarMealy.java new file mode 100644 index 0000000000..2bbe572625 --- /dev/null +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/PartialLStarMealy.java @@ -0,0 +1,209 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.lstar.mealy; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import de.learnlib.algorithms.lstar.AbstractExtensibleAutomatonLStar; +import de.learnlib.algorithms.lstar.AutomatonLStarState; +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandler; +import de.learnlib.algorithms.lstar.closing.ClosingStrategy; +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.datastructure.observationtable.ObservationTable; +import de.learnlib.datastructure.observationtable.PartialObservationTable; +import de.learnlib.datastructure.observationtable.Row; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.automata.transducers.impl.compact.CompactMealyTransition; +import net.automatalib.util.automata.transducers.StateLocalInputMealyUtil; +import net.automatalib.words.GrowingAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.SimpleAlphabet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An L* implementation that uses a {@link StateLocalInputMealyOracle} to infer potentially partial {@link + * MealyMachine}s, by analyzing the available input symbols for each state. + *

    + * This may lead to a significant performance improvement compared to classic L* implementations, because transitions + * that are not defined, will not be further explored, hence saving membership queries. + * + * @param + * input symbol class + * @param + * output symbol class + * + * @author Maren Geske + * @author frohme + */ +public class PartialLStarMealy + extends AbstractExtensibleAutomatonLStar, I, Word>, Integer, CompactMealyTransition, Void, O, CompactMealy> { + + private static final Logger LOGGER = LoggerFactory.getLogger(PartialLStarMealy.class); + + private final List> outputTable = new ArrayList<>(); + private final GrowingAlphabet alphabetAsGrowing; + private final StateLocalInputMealyOracle> oracle; + + public PartialLStarMealy(StateLocalInputMealyOracle> oracle, + List> initialSuffixes, + ObservationTableCEXHandler>> cexHandler, + ClosingStrategy>> closingStrategy) { + this(oracle, Collections.singletonList(Word.epsilon()), initialSuffixes, cexHandler, closingStrategy); + } + + @GenerateBuilder(defaults = AbstractExtensibleAutomatonLStar.BuilderDefaults.class) + public PartialLStarMealy(StateLocalInputMealyOracle> oracle, + List> initialPrefixes, + List> initialSuffixes, + ObservationTableCEXHandler>> cexHandler, + ClosingStrategy>> closingStrategy) { + this(new SimpleAlphabet<>(), + oracle, + new CompactMealy<>(new SimpleAlphabet<>()), + initialPrefixes, + initialSuffixes, + cexHandler, + closingStrategy); + } + + private PartialLStarMealy(GrowingAlphabet alphabet, + StateLocalInputMealyOracle> oracle, + CompactMealy internalHypothesis, + List> initialPrefixes, + List> initialSuffixes, + ObservationTableCEXHandler>> cexHandler, + ClosingStrategy>> closingStrategy) { + super(alphabet, + oracle, + internalHypothesis, + initialPrefixes, + new ArrayList<>(initialSuffixes), + cexHandler, + closingStrategy); + this.table = new PartialObservationTable<>(this::propagateNewAlphabetSymbol, oracle::definedInputs); + this.oracle = oracle; + this.alphabetAsGrowing = alphabet; + } + + private void propagateNewAlphabetSymbol(I i) { + this.alphabetAsGrowing.addSymbol(i); + this.internalHyp.addAlphabetSymbol(i); + } + + @Override + public void startLearning() { + final Collection initialInputs = this.oracle.definedInputs(Word.epsilon()); + final List> newSuffixes = LStarMealyUtil.ensureSuffixCompliancy(initialSuffixes, + Alphabets.fromCollection(initialInputs), + cexHandler.needsConsistencyCheck()); + + initialSuffixes.clear(); + initialSuffixes.addAll(newSuffixes); + + super.startLearning(); + } + + @Override + protected StateLocalInputMealyMachine exposeInternalHypothesis() { + return internalHyp; + } + + @Override + protected void updateInternalHypothesis() { + updateOutputs(); + super.updateInternalHypothesis(); + } + + @Override + protected Void stateProperty(ObservationTable>> table, Row stateRow) { + return null; + } + + @Override + protected O transitionProperty(ObservationTable>> table, + Row stateRow, + int inputIdx) { + Row transRow = stateRow.getSuccessor(inputIdx); + return outputTable.get(transRow.getRowId() - 1).getOutput(); + } + + protected void updateOutputs() { + int numOutputs = outputTable.size(); + int numTransRows = table.numberOfRows() - 1; + + int newOutputs = numTransRows - numOutputs; + if (newOutputs == 0) { + return; + } + + List>>> outputQueries = new ArrayList<>(numOutputs); + + for (int i = numOutputs + 1; i <= numTransRows; i++) { + Row row = table.getRow(i); + Word rowPrefix = row.getLabel(); + int prefixLen = rowPrefix.size(); + outputQueries.add(new DefaultQuery<>(rowPrefix.prefix(prefixLen - 1), rowPrefix.suffix(1))); + } + + oracle.processQueries(outputQueries); + + for (int i = 0; i < newOutputs; i++) { + DefaultQuery>> query = outputQueries.get(i); + OutputAndLocalInputs outSym = query.getOutput().getSymbol(0); + + outputTable.add(outSym); + } + } + + @Override + protected SuffixOutput>> hypothesisOutput() { + return StateLocalInputMealyUtil.partialToObservableOutput(internalHyp); + } + + @Override + public void addAlphabetSymbol(I symbol) { + LOGGER.info("Adding new symbols to a system, which already exposes its available actions has no effect"); + LOGGER.info("Skipping ..."); + } + + @Override + public void resume(AutomatonLStarState>, CompactMealy, Integer> state) { + super.resume(state); + final PartialObservationTable observationTable = (PartialObservationTable) super.table; + + final Set inputSymbols = new HashSet<>(); + + for (Row r : observationTable.getAllRows()) { + inputSymbols.addAll(observationTable.cellContents(r, 0).getSymbol(0).getLocalInputs()); + } + + observationTable.setInputAlphabet(new SimpleAlphabet<>(inputSymbols)); + observationTable.setNewAlphabetNotifier(this::propagateNewAlphabetSymbol); + } +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/PartialLStarMealyResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/PartialLStarMealyResumableLearnerTest.java new file mode 100644 index 0000000000..9a56b825a5 --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/PartialLStarMealyResumableLearnerTest.java @@ -0,0 +1,74 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.lstar; + +import java.util.Random; + +import de.learnlib.algorithms.lstar.mealy.PartialLStarMealy; +import de.learnlib.algorithms.lstar.mealy.PartialLStarMealyBuilder; +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.driver.util.StateLocalInputMealySimulatorSUL; +import de.learnlib.oracle.equivalence.mealy.StateLocalInputMealySimulatorEQOracle; +import de.learnlib.oracle.membership.StateLocalInputSULOracle; +import de.learnlib.testsupport.AbstractResumableLearnerTest; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; + +/** + * @author frohme + */ +public class PartialLStarMealyResumableLearnerTest + extends AbstractResumableLearnerTest, StateLocalInputMealyMachine, StateLocalInputMealyOracle>, Integer, Word>, AutomatonLStarState>, CompactMealy, Integer>> { + + @Override + protected Alphabet getInitialAlphabet() { + return Alphabets.integers(1, 5); + } + + @Override + protected StateLocalInputMealyMachine getTarget(Alphabet alphabet) { + return RandomAutomata.randomMealy(new Random(42), 100, alphabet, Alphabets.characters('a', 'd')); + } + + @Override + protected StateLocalInputMealyOracle> getOracle( + StateLocalInputMealyMachine target) { + return new StateLocalInputSULOracle<>(new StateLocalInputMealySimulatorSUL<>(target)); + } + + @Override + protected EquivalenceOracle, Integer, Word>> getEquivalenceOracle( + StateLocalInputMealyMachine target) { + return new StateLocalInputMealySimulatorEQOracle<>(target); + } + + @Override + protected PartialLStarMealy getLearner(StateLocalInputMealyOracle> oracle, + Alphabet alphabet) { + return new PartialLStarMealyBuilder().withOracle(oracle).create(); + } + + @Override + protected int getRounds() { + return 2; + } +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/PartialLStarMealyIT.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/PartialLStarMealyIT.java new file mode 100644 index 0000000000..cb332d879d --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/PartialLStarMealyIT.java @@ -0,0 +1,50 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.lstar.it; + +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandler; +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.closing.ClosingStrategies; +import de.learnlib.algorithms.lstar.closing.ClosingStrategy; +import de.learnlib.algorithms.lstar.mealy.PartialLStarMealyBuilder; +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.testsupport.it.learner.AbstractSLIMealyLearnerIT; +import de.learnlib.testsupport.it.learner.LearnerVariantList.SLIMealyLearnerVariantList; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.words.Word; + +public class PartialLStarMealyIT extends AbstractSLIMealyLearnerIT { + + @Override + protected void addLearnerVariants(StateLocalInputMealyOracle> mqOracle, + SLIMealyLearnerVariantList variants) { + PartialLStarMealyBuilder builder = new PartialLStarMealyBuilder<>(); + builder.setOracle(mqOracle); + + for (ObservationTableCEXHandler>> handler : ObservationTableCEXHandlers + .values()) { + + builder.setCexHandler(handler); + for (ClosingStrategy>> closingStrategy : ClosingStrategies + .values()) { + builder.setClosingStrategy(closingStrategy); + + String variantName = "cexHandler=" + handler + ",closingStrategy=" + closingStrategy; + variants.addLearnerVariant(variantName, builder.create()); + } + } + } +} diff --git a/api/src/main/java/de/learnlib/api/StateLocalInputSUL.java b/api/src/main/java/de/learnlib/api/StateLocalInputSUL.java new file mode 100644 index 0000000000..bd84193614 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/StateLocalInputSUL.java @@ -0,0 +1,43 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api; + +import java.util.Collection; + +import de.learnlib.api.exception.SULException; + +/** + * A System Under Learning (SUL) which can additionally report the inputs that the SUL can process in its current state, + * i.e. inputs that will not trigger a {@link SULException} when used in the next invocation of the {@link + * #step(Object)} method return an otherwise "undefined" behavior. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author Maren Geske + * @author frohme + */ +public interface StateLocalInputSUL extends SUL { + + Collection currentlyEnabledInputs(); + + @Override + default StateLocalInputSUL fork() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } +} diff --git a/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java b/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java index 95ccaeb7fa..001785f9bb 100644 --- a/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java @@ -83,5 +83,16 @@ default MembershipOracle asOracle() { interface DFAMembershipOracle extends MembershipOracle {} + /** + * A specialization of the {@link MembershipOracle} that binds the output domain to {@link Word}s of the specified + * output type. Queries should be answered according to the Mealy output semantics (transition-based). This means an + * input sequence of length {@code n} results in an output word of length {@code n}. + * + * @param + * input symbol type + * @param + * output symbol type + */ interface MealyMembershipOracle extends MembershipOracle> {} + } diff --git a/api/src/main/java/de/learnlib/api/oracle/StateLocalInputOracle.java b/api/src/main/java/de/learnlib/api/oracle/StateLocalInputOracle.java new file mode 100644 index 0000000000..b52d9df7da --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/StateLocalInputOracle.java @@ -0,0 +1,42 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.api.oracle; + +import java.util.Set; + +import net.automatalib.words.Word; + +/** + * A specialization of the {@link MembershipOracle} that adds the possibility to query for what continuations of a word + * the membership function is still defined. That is, the membership function is undefined for any word, that continues + * the queried input sequence with a symbol that is not contained in the returned set. + * + * @param + * input symbol type + * @param + * domain symbol type + * + * @author Maren Geske + * @author frohme + */ +public interface StateLocalInputOracle extends MembershipOracle { + + Set definedInputs(Word input); + + interface StateLocalInputDFAOracle extends StateLocalInputOracle, DFAMembershipOracle {} + + interface StateLocalInputMealyOracle extends StateLocalInputOracle>, MealyMembershipOracle {} +} diff --git a/build-parent/pom.xml b/build-parent/pom.xml index ec89d0678a..62bed6b952 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -51,6 +51,7 @@ limitations under the License. **/KearnsVazirani*Builder.class **/ClassicLStar*Builder.class **/ExtensibleLStar*Builder.class + **/PartialLStarMealyBuilder.class **/MalerPnueli*Builder.class **/RivestSchapire*Builder.class **/NLStarLearnerBuilder.class diff --git a/build-tools/src/main/resources/learnlib-pmd-exclusions.properties b/build-tools/src/main/resources/learnlib-pmd-exclusions.properties index dcbf683f62..e659ae09e9 100644 --- a/build-tools/src/main/resources/learnlib-pmd-exclusions.properties +++ b/build-tools/src/main/resources/learnlib-pmd-exclusions.properties @@ -44,6 +44,8 @@ de.learnlib.drivers.reflect.SimplePOJODataMapper=AvoidThrowingRawExceptionTypes, de.learnlib.examples.Example1=SystemPrintln de.learnlib.examples.Example2=SystemPrintln de.learnlib.examples.Example3=SystemPrintln +de.learnlib.examples.sli.Example1=SystemPrintln +de.learnlib.examples.sli.Example2=SystemPrintln # we want to allow mapping generic RuntimeExceptions de.learnlib.mapper.MappedSUL=AvoidCatchingGenericException diff --git a/datastructures/observation-table/pom.xml b/datastructures/observation-table/pom.xml index 5e6838131a..c2014b9900 100644 --- a/datastructures/observation-table/pom.xml +++ b/datastructures/observation-table/pom.xml @@ -34,6 +34,18 @@ limitations under the License. + + org.slf4j + slf4j-api + + + com.google.guava + guava + + + com.google.code.findbugs + jsr305 + @@ -59,15 +71,6 @@ limitations under the License. automata-commons-smartcollections - - com.google.guava - guava - - - com.google.code.findbugs - jsr305 - - diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java index 2f4ccf41cd..3ce4a6fb47 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java @@ -62,10 +62,10 @@ * * @author Malte Isberner */ -public final class GenericObservationTable implements MutableObservationTable, Serializable { +public class GenericObservationTable implements MutableObservationTable, Serializable { private static final Integer NO_ENTRY = null; // TODO: replace with primitive specialization - private final List> shortPrefixRows = new ArrayList<>(); + protected final List> shortPrefixRows = new ArrayList<>(); // private static final int NO_ENTRY = -1; private final List> longPrefixRows = new ArrayList<>(); private final List> allRows = new ArrayList<>(); @@ -73,12 +73,12 @@ public final class GenericObservationTable implements MutableObservationTa private final List> canonicalRows = new ArrayList<>(); // private final TObjectIntMap> rowContentIds = new TObjectIntHashMap<>(10, 0.75f, NO_ENTRY); private final Map, Integer> rowContentIds = new HashMap<>(); // TODO: replace with primitive specialization - private final Map, RowImpl> rowMap = new HashMap<>(); - private final List> suffixes = new ArrayList<>(); - private final Set> suffixSet = new HashSet<>(); + protected final Map, RowImpl> rowMap = new HashMap<>(); + protected final List> suffixes = new ArrayList<>(); + protected final Set> suffixSet = new HashSet<>(); private transient Alphabet alphabet; private int numRows; - private boolean initialConsistencyCheckRequired; + protected boolean initialConsistencyCheckRequired; /** * Constructor. @@ -90,9 +90,9 @@ public GenericObservationTable(Alphabet alphabet) { this.alphabet = alphabet; } - private static void buildQueries(List> queryList, - Word prefix, - List> suffixes) { + protected static void buildQueries(List> queryList, + Word prefix, + List> suffixes) { for (Word suffix : suffixes) { queryList.add(new DefaultQuery<>(prefix, suffix)); } @@ -102,19 +102,9 @@ private static void buildQueries(List> queryList, public List>> initialize(List> initialShortPrefixes, List> initialSuffixes, MembershipOracle oracle) { - if (!allRows.isEmpty()) { - throw new IllegalStateException("Called initialize, but there are already rows present"); - } - - if (!checkPrefixClosed(initialShortPrefixes)) { - throw new IllegalArgumentException("Initial short prefixes are not prefix-closed"); - } - if (!initialShortPrefixes.get(0).isEmpty()) { - throw new IllegalArgumentException("First initial short prefix MUST be the empty word!"); - } + checkInitialization(initialShortPrefixes, initialSuffixes); - int numSuffixes = initialSuffixes.size(); for (Word suffix : initialSuffixes) { if (suffixSet.add(suffix)) { suffixes.add(suffix); @@ -122,6 +112,7 @@ public List>> initialize(List> initialShortPrefixes, } int numPrefixes = alphabet.size() * initialShortPrefixes.size() + 1; + int numSuffixes = suffixes.size(); List> queries = new ArrayList<>(numPrefixes * numSuffixes); @@ -185,6 +176,20 @@ public List>> initialize(List> initialShortPrefixes, return unclosed; } + protected void checkInitialization(List> initialShortPrefixes, List> initialSuffixes) { + if (!allRows.isEmpty()) { + throw new IllegalStateException("Called initialize, but there are already rows present"); + } + + if (!checkPrefixClosed(initialShortPrefixes)) { + throw new IllegalArgumentException("Initial short prefixes are not prefix-closed"); + } + + if (!initialShortPrefixes.get(0).isEmpty()) { + throw new IllegalArgumentException("First initial short prefix MUST be the empty word!"); + } + } + private static boolean checkPrefixClosed(Collection> initialShortPrefixes) { Set> prefixes = new HashSet<>(initialShortPrefixes); @@ -199,7 +204,7 @@ private static boolean checkPrefixClosed(Collection> initi return true; } - private RowImpl createSpRow(Word prefix) { + protected RowImpl createSpRow(Word prefix) { RowImpl newRow = new RowImpl<>(prefix, numRows++, alphabet.size()); allRows.add(newRow); rowMap.put(prefix, newRow); @@ -207,7 +212,7 @@ private RowImpl createSpRow(Word prefix) { return newRow; } - private RowImpl createLpRow(Word prefix) { + protected RowImpl createLpRow(Word prefix) { RowImpl newRow = new RowImpl<>(prefix, numRows++); allRows.add(newRow); rowMap.put(prefix, newRow); @@ -228,14 +233,14 @@ private RowImpl createLpRow(Word prefix) { * @param numSuffixes * the number of suffixes (queries) */ - private static void fetchResults(Iterator> queryIt, List output, int numSuffixes) { + protected static void fetchResults(Iterator> queryIt, List output, int numSuffixes) { for (int j = 0; j < numSuffixes; j++) { DefaultQuery qry = queryIt.next(); output.add(qry.getOutput()); } } - private boolean processContents(RowImpl row, List rowContents, boolean makeCanonical) { + protected boolean processContents(RowImpl row, List rowContents, boolean makeCanonical) { Integer contentId; // TODO: replace with primitive specialization // int contentId; boolean added = false; @@ -434,7 +439,7 @@ public List>> toShortPrefixes(List> lpRows, MembershipOracle< return unclosed; } - private void makeShort(RowImpl row) { + protected void makeShort(RowImpl row) { if (row.isShortPrefixRow()) { return; } @@ -459,9 +464,9 @@ private void makeShort(RowImpl row) { } } - private static void buildRowQueries(List> queryList, - List> rows, - List> suffixes) { + protected static void buildRowQueries(List> queryList, + List> rows, + List> suffixes) { for (Row row : rows) { buildQueries(queryList, row.getLabel(), suffixes); } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/ObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/ObservationTable.java index de8dfce2d6..1a3d6995b8 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/ObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/ObservationTable.java @@ -313,10 +313,17 @@ default Inconsistency findInconsistency() { } for (int i = 0; i < alphabet.size(); i++) { - int spSuccContent = spRow.getSuccessor(i).getRowContentId(); - int canSuccContent = canRow.getSuccessor(i).getRowContentId(); - if (spSuccContent != canSuccContent) { - return new Inconsistency<>(canRow, spRow, alphabet.getSymbol(i)); + final Row spRowSucc = spRow.getSuccessor(i); + + if (spRowSucc != null) { + final Row canRowSucc = canRow.getSuccessor(i); + assert canRowSucc != null; + + int spSuccContent = spRowSucc.getRowContentId(); + int canSuccContent = canRowSucc.getRowContentId(); + if (spSuccContent != canSuccContent) { + return new Inconsistency<>(canRow, spRow, alphabet.getSymbol(i)); + } } } } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/PartialObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/PartialObservationTable.java new file mode 100644 index 0000000000..98744fd79f --- /dev/null +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/PartialObservationTable.java @@ -0,0 +1,288 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.observationtable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.words.GrowingAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.SimpleAlphabet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A specialized observation table that creates new long-prefix rows depending on the available input symbols of the + * corresponding short-prefix row. + *

    + * The information about available inputs symbols is stored in the first (epsilon) column, despite this being an + * observation table based on Mealy semantics (where an empty input always yields an empty output). The information + * about available inputs are not fetched via conventional membership queries, but by querying the supplied provider. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author Maren Geske + * @author frohme + */ +public class PartialObservationTable extends GenericObservationTable>> { + + private static final Logger LOGGER = LoggerFactory.getLogger(PartialObservationTable.class); + + private final transient GrowingAlphabet alphabet; + private final transient Function, Collection> enabledInputsProvider; + private transient Consumer newAlphabetNotifier; + + public PartialObservationTable(Consumer newAlphabetNotifier, + Function, Collection> enabledInputsProvider) { + this(new SimpleAlphabet<>(), newAlphabetNotifier, enabledInputsProvider); + } + + private PartialObservationTable(GrowingAlphabet alphabet, + Consumer newAlphabetNotifier, + Function, Collection> enabledInputsProvider) { + super(alphabet); + this.alphabet = alphabet; + this.newAlphabetNotifier = newAlphabetNotifier; + this.enabledInputsProvider = enabledInputsProvider; + } + + public void setNewAlphabetNotifier(Consumer newAlphabetNotifier) { + this.newAlphabetNotifier = newAlphabetNotifier; + } + + @Override + public List>> initialize(List> initialShortPrefixes, + List> initialSuffixes, + MembershipOracle>> oracle) { + + checkInitialization(initialShortPrefixes, initialSuffixes); + + suffixes.add(Word.epsilon()); + suffixSet.add(Word.epsilon()); + + for (Word suffix : initialSuffixes) { + if (suffixSet.add(suffix)) { + suffixes.add(suffix); + } + } + + int numPrefixes = alphabet.size() * initialShortPrefixes.size() + 1; + int numNonEmptySuffixes = suffixes.size() - 1; + + List>>> queries = + new ArrayList<>(numPrefixes * numNonEmptySuffixes); + + // PASS 1: Add short prefix rows + for (Word sp : initialShortPrefixes) { + createSpRow(sp); + buildQueries(queries, sp, suffixes.subList(1, suffixes.size())); + } + + oracle.processQueries(queries); + // get enabled inputs for initial state + Iterator>>> queryIt = queries.iterator(); + for (RowImpl spRow : shortPrefixRows) { + List>> rowContents = new ArrayList<>(numNonEmptySuffixes + 1); + + rowContents.add(Word.fromLetter(new OutputAndLocalInputs<>(null, + enabledInputsProvider.apply(spRow.getLabel())))); + + fetchResults(queryIt, rowContents, numNonEmptySuffixes); + if (!processContents(spRow, rowContents, true)) { + initialConsistencyCheckRequired = true; + } + } + + queries.clear(); + + // PASS 2: Add missing long prefix rows + for (RowImpl spRow : shortPrefixRows) { + Word sp = spRow.getLabel(); + for (I sym : getEnabledInputs(spRow)) { + + checkForNewAlphabetSymbol(sym); + + Word lp = sp.append(sym); + RowImpl succRow = rowMap.get(lp); + if (succRow == null) { + succRow = createLpRow(lp); + buildQueries(queries, lp, suffixes.subList(1, suffixes.size())); + } + + int i = alphabet.getSymbolIndex(sym); + spRow.setSuccessor(i, succRow); + } + } + + oracle.processQueries(queries); + + queryIt = queries.iterator(); + + int distinctSpRows = numberOfDistinctRows(); + + List>> unclosed = new ArrayList<>(); + + for (RowImpl spRow : shortPrefixRows) { + for (int i = 0; i < alphabet.size(); i++) { + RowImpl succRow = spRow.getSuccessor(i); + if (succRow == null || succRow.isShortPrefixRow()) { + continue; + } + List>> rowContents = new ArrayList<>(numNonEmptySuffixes + 1); + rowContents.add(Word.fromLetter(new OutputAndLocalInputs<>(null, + enabledInputsProvider.apply(succRow.getLabel())))); + fetchResults(queryIt, rowContents, numNonEmptySuffixes); + if (processContents(succRow, rowContents, false)) { + unclosed.add(new ArrayList<>()); + } + + int id = succRow.getRowContentId(); + + if (id >= distinctSpRows) { + unclosed.get(id - distinctSpRows).add(succRow); + } + } + } + + return unclosed; + } + + @Override + public List>> toShortPrefixes(List> lpRows, + MembershipOracle>> oracle) { + RowImpl freshSpRow = null; + List> freshLpRows = new ArrayList<>(); + + final int numNonEmptySuffixes = suffixes.size() - 1; + + for (Row r : lpRows) { + final RowImpl row = getRow(r.getRowId()); + if (row.isShortPrefixRow()) { + if (row.hasContents()) { + continue; + } + freshSpRow = row; + } else { + makeShort(row); + if (!row.hasContents()) { + freshSpRow = row; + } + } + + // we need to eagerly fetch new sp rows, because we rely on the epsilon column to detect the available + // inputs in the next part + if (freshSpRow != null) { + final List>>> queries = + new ArrayList<>(numNonEmptySuffixes); + buildRowQueries(queries, Collections.singletonList(freshSpRow), suffixes.subList(1, suffixes.size())); + + oracle.processQueries(queries); + Iterator>>> queryIt = queries.iterator(); + + List>> contents = new ArrayList<>(numNonEmptySuffixes + 1); + + contents.add(Word.fromLetter(new OutputAndLocalInputs<>(null, + enabledInputsProvider.apply(freshSpRow.getLabel())))); + fetchResults(queryIt, contents, numNonEmptySuffixes); + processContents(freshSpRow, contents, true); + } + + Word prefix = row.getLabel(); + + for (I sym : getEnabledInputs(row)) { + checkForNewAlphabetSymbol(sym); + + Word lp = prefix.append(sym); + RowImpl lpRow = rowMap.get(lp); + if (lpRow == null) { + lpRow = createLpRow(lp); + freshLpRows.add(lpRow); + } + + int i = alphabet.getSymbolIndex(sym); + row.setSuccessor(i, lpRow); + } + } + + List>>> queries = + new ArrayList<>(freshLpRows.size() * numNonEmptySuffixes); + buildRowQueries(queries, freshLpRows, suffixes.subList(1, suffixes.size())); + + oracle.processQueries(queries); + Iterator>>> queryIt = queries.iterator(); + + int numSpRows = numberOfDistinctRows(); + List>> unclosed = new ArrayList<>(); + + for (RowImpl row : freshLpRows) { + List>> contents = new ArrayList<>(numNonEmptySuffixes + 1); + + contents.add(Word.fromLetter(new OutputAndLocalInputs<>(null, + enabledInputsProvider.apply(row.getLabel())))); + fetchResults(queryIt, contents, numNonEmptySuffixes); + if (processContents(row, contents, false)) { + unclosed.add(new ArrayList<>()); + } + + int id = row.getRowContentId(); + if (id >= numSpRows) { + unclosed.get(id - numSpRows).add(row); + } + } + + return unclosed; + } + + @Override + public List>> addAlphabetSymbol(I symbol, + final MembershipOracle>> oracle) { + LOGGER.info("Adding new symbols to a system, which already exposes its available actions has no effect"); + LOGGER.info("Skipping ..."); + + return Collections.emptyList(); + } + + private void checkForNewAlphabetSymbol(I i) { + if (!alphabet.containsSymbol(i)) { + + alphabet.addSymbol(i); + final int newAlphabetSize = alphabet.size(); + + for (RowImpl prefix : shortPrefixRows) { + prefix.ensureInputCapacity(newAlphabetSize); + } + + newAlphabetNotifier.accept(i); + } + } + + private Collection getEnabledInputs(RowImpl row) { + Word> enabledInputs = cellContents(row, 0); + return enabledInputs.getSymbol(0).getLocalInputs(); + } + +} diff --git a/drivers/simulator/src/main/java/de/learnlib/driver/util/MealySimulatorSUL.java b/drivers/simulator/src/main/java/de/learnlib/driver/util/MealySimulatorSUL.java index 7e6df7e707..c396b8eea8 100644 --- a/drivers/simulator/src/main/java/de/learnlib/driver/util/MealySimulatorSUL.java +++ b/drivers/simulator/src/main/java/de/learnlib/driver/util/MealySimulatorSUL.java @@ -64,7 +64,7 @@ public MealySimulatorSUL(MealyMachine mealy, O noTransOut) { this(new MealySimulatorSULImpl<>(mealy, noTransOut)); } - private MealySimulatorSUL(MealySimulatorSULImpl impl) { + protected MealySimulatorSUL(MealySimulatorSULImpl impl) { this.impl = impl; } @@ -107,7 +107,7 @@ public SUL fork() { * * @author Malte Isberner */ - private static final class MealySimulatorSULImpl implements SUL { + static class MealySimulatorSULImpl implements SUL { private final MealyMachine mealy; private final O noTransOut; @@ -152,6 +152,10 @@ public boolean canFork() { public MealySimulatorSULImpl fork() { return new MealySimulatorSULImpl<>(mealy, noTransOut); } + + S getCurr() { + return curr; + } } } diff --git a/drivers/simulator/src/main/java/de/learnlib/driver/util/StateLocalInputMealySimulatorSUL.java b/drivers/simulator/src/main/java/de/learnlib/driver/util/StateLocalInputMealySimulatorSUL.java new file mode 100644 index 0000000000..eee15fa974 --- /dev/null +++ b/drivers/simulator/src/main/java/de/learnlib/driver/util/StateLocalInputMealySimulatorSUL.java @@ -0,0 +1,68 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.driver.util; + +import java.util.Collection; + +import de.learnlib.api.StateLocalInputSUL; +import de.learnlib.api.exception.SULException; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; + +public class StateLocalInputMealySimulatorSUL extends MealySimulatorSUL + implements StateLocalInputSUL { + + protected final SLIMealySimulatorSULImpl impl; + + public StateLocalInputMealySimulatorSUL(StateLocalInputMealyMachine mealy) { + this(new SLIMealySimulatorSULImpl<>(mealy)); + } + + private StateLocalInputMealySimulatorSUL(SLIMealySimulatorSULImpl impl) { + super(impl); + this.impl = impl; + } + + @Override + public StateLocalInputSUL fork() { + return new StateLocalInputMealySimulatorSUL<>(impl.fork()); + } + + @Override + public Collection currentlyEnabledInputs() throws SULException { + return this.impl.currentlyEnabledInputs(); + } + + private static final class SLIMealySimulatorSULImpl extends MealySimulatorSULImpl + implements StateLocalInputSUL { + + private final StateLocalInputMealyMachine mealy; + + SLIMealySimulatorSULImpl(StateLocalInputMealyMachine mealy) { + super(mealy, null); + this.mealy = mealy; + } + + @Override + public Collection currentlyEnabledInputs() throws SULException { + return this.mealy.getLocalInputs(super.getCurr()); + } + + @Override + public SLIMealySimulatorSULImpl fork() { + return new SLIMealySimulatorSULImpl<>(mealy); + } + } +} diff --git a/examples/pom.xml b/examples/pom.xml index e08170516e..1f4a370f97 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -61,6 +61,10 @@ limitations under the License. de.learnlib learnlib-drivers-basic + + de.learnlib + learnlib-drivers-simulator + de.learnlib learnlib-lstar diff --git a/examples/src/main/java/de/learnlib/examples/sli/Example1.java b/examples/src/main/java/de/learnlib/examples/sli/Example1.java new file mode 100644 index 0000000000..735026bcd1 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/sli/Example1.java @@ -0,0 +1,183 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.sli; + +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealy; +import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealyBuilder; +import de.learnlib.algorithms.lstar.mealy.PartialLStarMealy; +import de.learnlib.algorithms.lstar.mealy.PartialLStarMealyBuilder; +import de.learnlib.api.StateLocalInputSUL; +import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.datastructure.observationtable.writer.ObservationTableASCIIWriter; +import de.learnlib.driver.util.StateLocalInputMealySimulatorSUL; +import de.learnlib.oracle.equivalence.SimulatorEQOracle.MealySimulatorEQOracle; +import de.learnlib.oracle.equivalence.mealy.StateLocalInputMealySimulatorEQOracle; +import de.learnlib.oracle.membership.StateLocalInputSULOracle; +import de.learnlib.util.Experiment; +import de.learnlib.util.Experiment.MealyExperiment; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.util.automata.transducers.StateLocalInputMealyUtil; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * An example showcasing the usage of learning a partial system using the {@link PartialLStarMealy} learning algorithm. + * + * @author frohme + */ +public final class Example1 { + + private static final Alphabet INPUTS; + private static final CompactMealy TARGET; + private static final MealyMachine> TRANSFORMED_TARGET; + private static final StateLocalInputSUL SUL; + + static { + INPUTS = Alphabets.integers(0, 1); + TARGET = constructTarget(); + TRANSFORMED_TARGET = StateLocalInputMealyUtil.partialToObservableOutput(TARGET); + SUL = new StateLocalInputMealySimulatorSUL<>(TARGET); + } + + private Example1() { + // prevent instantiation + } + + public static void main(String[] args) { + runPartialLearner(); + runTransformedLearner(); + } + + /** + * Uses the raw {@link StateLocalInputSUL} to infer a (potentially) partial {@link MealyMachine}. + */ + static void runPartialLearner() { + + // construct a (state local input) simulator membership query oracle + StateLocalInputMealyOracle> mqOracle = + new StateLocalInputSULOracle<>(SUL); + + // construct L* instance + PartialLStarMealy lstar = + new PartialLStarMealyBuilder().withOracle(mqOracle) + .withCexHandler(ObservationTableCEXHandlers.RIVEST_SCHAPIRE) + .create(); + + // here, we simply use an equivalence check for the original automaton model + StateLocalInputMealySimulatorEQOracle eqOracle = + new StateLocalInputMealySimulatorEQOracle<>(TARGET); + + // construct the experiment + // note, we can't use the regular MealyExperiment (or MooreExperiment) because the output type of our hypothesis + // is different from our membership query type + Experiment> experiment = + new Experiment<>(lstar, eqOracle, INPUTS); + + // run experiment + experiment.run(); + + // get learned model + MealyMachine result = experiment.getFinalHypothesis(); + + // report results + System.out.println("-------------------------------------------------------"); + + System.out.println("States: " + result.size()); + System.out.println("Sigma: " + INPUTS.size()); + + System.out.println("-------------------------------------------------------"); + + System.out.println("Final observation table:"); + new ObservationTableASCIIWriter<>().write(lstar.getObservationTable(), System.out); + } + + /** + * Uses the raw {@link StateLocalInputSUL} to infer a complete partial {@link MealyMachine} as in classical automata + * learning. Note: here the {@link MealyMembershipOracle} needs to take care of mapping potentially undefined inputs + * of the system under learning to processable outputs for the learner. + */ + static void runTransformedLearner() { + + // construct a (regular) simulator membership query oracle + MealyMembershipOracle> mqOracle = + new StateLocalInputSULOracle<>(SUL); + + // construct L* instance + ExtensibleLStarMealy> lstar = + new ExtensibleLStarMealyBuilder>().withAlphabet(INPUTS) + .withOracle(mqOracle) + .withCexHandler( + ObservationTableCEXHandlers.RIVEST_SCHAPIRE) + .create(); + + // here, we simply use an equivalence check for the transformed automaton model + MealyEquivalenceOracle> eqOracle = + new MealySimulatorEQOracle<>(TRANSFORMED_TARGET); + + // construct the experiment + MealyExperiment> experiment = + new MealyExperiment<>(lstar, eqOracle, INPUTS); + + // run experiment + experiment.run(); + + // get learned model + MealyMachine> result = experiment.getFinalHypothesis(); + + // report results + System.out.println("-------------------------------------------------------"); + + System.out.println("States: " + result.size()); + System.out.println("Sigma: " + INPUTS.size()); + + System.out.println("-------------------------------------------------------"); + + System.out.println("Final observation table:"); + new ObservationTableASCIIWriter<>().write(lstar.getObservationTable(), System.out); + } + + /** + * creates example from Geske's thesis (fig. 2.1). + * + * @return example (partial) mealy + */ + private static CompactMealy constructTarget() { + // @formatter:off + // create automaton + return AutomatonBuilders.newMealy(INPUTS) + .withInitial("s0") + .from("s0") + .on(0).withOutput('a').to("s2") + .on(1).withOutput('b').to("s1") + .from("s1") + .on(0).withOutput('b').loop() + .on(1).withOutput('a').loop() + .from("s2") + .on(0).withOutput('b').loop() + .on(1).withOutput('a').to("s3") + .from("s3") + .on(0).withOutput('a').to("s1") + .create(); + // @formatter:on + } +} diff --git a/examples/src/main/java/de/learnlib/examples/sli/Example2.java b/examples/src/main/java/de/learnlib/examples/sli/Example2.java new file mode 100644 index 0000000000..53fea12371 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/sli/Example2.java @@ -0,0 +1,173 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.sli; + +import java.util.Random; + +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealy; +import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealyBuilder; +import de.learnlib.algorithms.lstar.mealy.PartialLStarMealy; +import de.learnlib.algorithms.lstar.mealy.PartialLStarMealyBuilder; +import de.learnlib.api.StateLocalInputSUL; +import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.driver.util.StateLocalInputMealySimulatorSUL; +import de.learnlib.examples.mealy.ExampleRandomStateLocalInputMealy; +import de.learnlib.filter.statistic.sul.ResetCounterStateLocalInputSUL; +import de.learnlib.filter.statistic.sul.SymbolCounterStateLocalInputSUL; +import de.learnlib.oracle.equivalence.SimulatorEQOracle.MealySimulatorEQOracle; +import de.learnlib.oracle.equivalence.mealy.StateLocalInputMealySimulatorEQOracle; +import de.learnlib.oracle.membership.StateLocalInputSULOracle; +import de.learnlib.util.Experiment; +import de.learnlib.util.Experiment.MealyExperiment; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.util.automata.transducers.StateLocalInputMealyUtil; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * An example showcasing the performance impact of the {@link PartialLStarMealy} learning algorithm compared to the + * regular {@link ExtensibleLStarMealy} when learning partial systems. + * + * @author frohme + */ +public final class Example2 { + + private static final Alphabet INPUTS; + private static final CompactMealy TARGET; + private static final MealyMachine> TRANSFORMED_TARGET; + private static final StateLocalInputSUL SUL; + + static { + final int alphabetSize = 10; + INPUTS = Alphabets.integers(0, alphabetSize); + + final Character[] outputs = new Character[] {'a', 'b', 'c'}; + final ExampleRandomStateLocalInputMealy example = + ExampleRandomStateLocalInputMealy.createExample(new Random(42), INPUTS, 100, outputs); + + TARGET = example.getReferenceAutomaton(); + TRANSFORMED_TARGET = StateLocalInputMealyUtil.partialToObservableOutput(TARGET); + SUL = new StateLocalInputMealySimulatorSUL<>(TARGET); + } + + private Example2() { + // prevent instantiation + } + + public static void main(String[] args) { + runPartialLearner(); + runTransformedLearner(); + } + + /** + * Uses the raw {@link StateLocalInputSUL} to infer a (potentially) partial {@link MealyMachine}. + */ + static void runPartialLearner() { + + // setup SULs and counters + StateLocalInputSUL target = SUL; + + ResetCounterStateLocalInputSUL resetCounter = + new ResetCounterStateLocalInputSUL<>("Resets", target); + SymbolCounterStateLocalInputSUL symbolCounter = + new SymbolCounterStateLocalInputSUL<>("Symbols", resetCounter); + + // construct a (state local input) simulator membership query oracle + StateLocalInputMealyOracle> mqOracle = + new StateLocalInputSULOracle<>(symbolCounter); + + // construct L* instance + PartialLStarMealy lstar = + new PartialLStarMealyBuilder().withOracle(mqOracle) + .withCexHandler(ObservationTableCEXHandlers.RIVEST_SCHAPIRE) + .create(); + + // here, we simply use an equivalence check for the original automaton model + StateLocalInputMealySimulatorEQOracle eqOracle = + new StateLocalInputMealySimulatorEQOracle<>(TARGET); + + // construct the experiment + // note, we can't use the regular MealyExperiment (or MooreExperiment) because the output type of our hypothesis + // is different from our membership query type + Experiment> experiment = + new Experiment<>(lstar, eqOracle, INPUTS); + + // run experiment + experiment.run(); + + // report results + System.out.println("-------------------------------------------------------"); + + System.out.println(resetCounter.getStatisticalData().getSummary()); + System.out.println(symbolCounter.getStatisticalData().getSummary()); + + System.out.println("-------------------------------------------------------"); + } + + /** + * Uses the raw {@link StateLocalInputSUL} to infer a complete partial {@link MealyMachine} as in classical automata + * learning. Note: here the {@link MealyMembershipOracle} needs to take care of mapping potentially undefined inputs + * of the system under learning to processable outputs for the learner. + */ + static void runTransformedLearner() { + + // setup SULs and counters + StateLocalInputSUL target = SUL; + + ResetCounterStateLocalInputSUL resetCounter = + new ResetCounterStateLocalInputSUL<>("Resets", target); + SymbolCounterStateLocalInputSUL symbolCounter = + new SymbolCounterStateLocalInputSUL<>("Symbols", resetCounter); + + // construct a (regular) simulator membership query oracle + MealyMembershipOracle> mqOracle = + new StateLocalInputSULOracle<>(symbolCounter); + + // construct L* instance + ExtensibleLStarMealy> lstar = + new ExtensibleLStarMealyBuilder>().withAlphabet(INPUTS) + .withOracle(mqOracle) + .withCexHandler( + ObservationTableCEXHandlers.RIVEST_SCHAPIRE) + .create(); + + // here, we simply use an equivalence check for the transformed automaton model + MealyEquivalenceOracle> eqOracle = + new MealySimulatorEQOracle<>(TRANSFORMED_TARGET); + + // construct the experiment + MealyExperiment> experiment = + new MealyExperiment<>(lstar, eqOracle, INPUTS); + + // run experiment + experiment.run(); + + // report results + System.out.println("-------------------------------------------------------"); + + System.out.println(resetCounter.getStatisticalData().getSummary()); + System.out.println(symbolCounter.getStatisticalData().getSummary()); + + System.out.println("-------------------------------------------------------"); + } + +} diff --git a/examples/src/test/java/de/learnlib/examples/ExamplesTest.java b/examples/src/test/java/de/learnlib/examples/ExamplesTest.java index 14c0e7cbf9..3644c2639a 100644 --- a/examples/src/test/java/de/learnlib/examples/ExamplesTest.java +++ b/examples/src/test/java/de/learnlib/examples/ExamplesTest.java @@ -76,6 +76,16 @@ public void testBBCExample4() { de.learnlib.examples.bbc.Example4.main(new String[0]); } + @Test + public void testSLIExample1() { + de.learnlib.examples.sli.Example1.main(new String[0]); + } + + @Test + public void testSLIExample2() { + de.learnlib.examples.sli.Example2.main(new String[0]); + } + @Test public void testExample1() throws Exception { checkJVMCompatibility(); diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/StateLocalInputMealySimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/StateLocalInputMealySimulatorEQOracle.java new file mode 100644 index 0000000000..56b70bed79 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/StateLocalInputMealySimulatorEQOracle.java @@ -0,0 +1,57 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.mealy; + +import java.util.Collection; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.oracle.equivalence.SimulatorEQOracle; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; +import net.automatalib.util.automata.transducers.StateLocalInputMealyUtil; +import net.automatalib.words.Word; + +public class StateLocalInputMealySimulatorEQOracle + implements EquivalenceOracle, I, Word>> { + + private final SimulatorEQOracle> delegate; + private final SuffixOutput>> mealyAsSLIMealy; + + public StateLocalInputMealySimulatorEQOracle(StateLocalInputMealyMachine mealy) { + this.delegate = new SimulatorEQOracle<>(mealy); + + // we can use 'null' as a sink, because we will never traverse this state + this.mealyAsSLIMealy = StateLocalInputMealyUtil.partialToObservableOutput(mealy, null); + } + + @Override + public DefaultQuery>> findCounterExample(StateLocalInputMealyMachine hypothesis, + Collection inputs) { + final DefaultQuery> cex = delegate.findCounterExample(hypothesis, inputs); + + if (cex != null) { + final Word prefix = cex.getPrefix(); + final Word suffix = cex.getSuffix(); + + return new DefaultQuery<>(prefix, suffix, this.mealyAsSLIMealy.computeSuffixOutput(prefix, suffix)); + } + + return null; + } + +} diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/EmptyAutomatonOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/EmptyAutomatonOracleTest.java index 5b61b57b94..219e1c19df 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/EmptyAutomatonOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/EmptyAutomatonOracleTest.java @@ -47,7 +47,7 @@ public void testEmptyMealy() { } private & UniversalDeterministicAutomaton> void testEmptyAutomaton( - LearningExample example, + LearningExample example, AutomatonCreator emptyCreator) { final A automaton = example.getReferenceAutomaton(); diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterStateLocalInputSUL.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterStateLocalInputSUL.java new file mode 100644 index 0000000000..343cf1c01b --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterStateLocalInputSUL.java @@ -0,0 +1,61 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.statistic.sul; + +import java.util.Collection; + +import de.learnlib.api.StateLocalInputSUL; +import de.learnlib.filter.statistic.Counter; + +public class ResetCounterStateLocalInputSUL extends ResetCounterSUL implements StateLocalInputSUL { + + private final StateLocalInputSUL sul; + + public ResetCounterStateLocalInputSUL(String name, StateLocalInputSUL sul) { + super(name, sul); + this.sul = sul; + } + + private ResetCounterStateLocalInputSUL(Counter counter, StateLocalInputSUL sul) { + super(counter, sul); + this.sul = sul; + } + + @Override + public Collection currentlyEnabledInputs() { + return sul.currentlyEnabledInputs(); + } + + @Override + public StateLocalInputSUL fork() { + return new ResetCounterStateLocalInputSUL<>(getStatisticalData(), sul.fork()); + } + + @Override + public boolean equals(Object obj) { + return sul.equals(obj); + } + + @Override + public int hashCode() { + return sul.hashCode(); + } + + @Override + public String toString() { + return sul.toString(); + } +} diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterStateLocalInputSUL.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterStateLocalInputSUL.java new file mode 100644 index 0000000000..da0677aa32 --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterStateLocalInputSUL.java @@ -0,0 +1,62 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.filter.statistic.sul; + +import java.util.Collection; + +import de.learnlib.api.StateLocalInputSUL; +import de.learnlib.filter.statistic.Counter; + +public class SymbolCounterStateLocalInputSUL extends SymbolCounterSUL implements StateLocalInputSUL { + + private final StateLocalInputSUL sul; + + public SymbolCounterStateLocalInputSUL(String name, StateLocalInputSUL sul) { + super(name, sul); + this.sul = sul; + } + + private SymbolCounterStateLocalInputSUL(Counter counter, StateLocalInputSUL sul) { + super(counter, sul); + this.sul = sul; + } + + @Override + public Collection currentlyEnabledInputs() { + return sul.currentlyEnabledInputs(); + } + + @Override + public StateLocalInputSUL fork() { + return new SymbolCounterStateLocalInputSUL<>(getStatisticalData(), sul.fork()); + } + + @Override + public boolean equals(Object obj) { + return sul.equals(obj); + } + + @Override + public int hashCode() { + return sul.hashCode(); + } + + @Override + public String toString() { + return sul.toString(); + } +} + diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/StateLocalInputSULOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/StateLocalInputSULOracle.java new file mode 100644 index 0000000000..bcf2612309 --- /dev/null +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/StateLocalInputSULOracle.java @@ -0,0 +1,119 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.membership; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import de.learnlib.api.StateLocalInputSUL; +import de.learnlib.api.exception.SULException; +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.api.query.Query; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; + +public class StateLocalInputSULOracle implements StateLocalInputMealyOracle> { + + private final StateLocalInputSUL sul; + private final ThreadLocal> localSul; + + public StateLocalInputSULOracle(StateLocalInputSUL sul) { + this.sul = sul; + if (sul.canFork()) { + this.localSul = ThreadLocal.withInitial(sul::fork); + } else { + this.localSul = null; + } + } + + @Override + public void processQueries(Collection>>> queries) { + if (localSul != null) { + processQueries(localSul.get(), queries); + } else { + synchronized (sul) { + processQueries(sul, queries); + } + } + } + + private void processQueries(StateLocalInputSUL sul, + Collection>>> queries) { + for (Query>> q : queries) { + Word> output = answerQuery(sul, q.getPrefix(), q.getSuffix()); + q.answer(output); + } + } + + private Word> answerQuery(StateLocalInputSUL sul, Word prefix, Word suffix) + throws SULException { + try { + sul.pre(); + Collection enabledInputs = sul.currentlyEnabledInputs(); + + for (I sym : prefix) { + if (enabledInputs.contains(sym)) { + sul.step(sym); + enabledInputs = sul.currentlyEnabledInputs(); + } else { + enabledInputs = Collections.emptySet(); + } + } + + final WordBuilder> wb = new WordBuilder<>(suffix.length()); + + for (I sym : suffix) { + if (enabledInputs.contains(sym)) { + final O out = sul.step(sym); + enabledInputs = sul.currentlyEnabledInputs(); + wb.add(new OutputAndLocalInputs<>(out, enabledInputs)); + } else { + enabledInputs = Collections.emptySet(); + wb.add(OutputAndLocalInputs.undefined()); + } + } + + return wb.toWord(); + } finally { + sul.post(); + } + } + + @Override + public Set definedInputs(Word input) { + try { + sul.pre(); + Collection enabledInputs = sul.currentlyEnabledInputs(); + + for (I sym : input) { + if (enabledInputs.contains(sym)) { + sul.step(sym); + enabledInputs = sul.currentlyEnabledInputs(); + } else { + return Collections.emptySet(); + } + } + + return new HashSet<>(enabledInputs); + } finally { + sul.post(); + } + } +} + diff --git a/test-support/learner-it-support/pom.xml b/test-support/learner-it-support/pom.xml index 8c21f6a412..8a118c0e63 100644 --- a/test-support/learner-it-support/pom.xml +++ b/test-support/learner-it-support/pom.xml @@ -40,6 +40,10 @@ limitations under the License. de.learnlib learnlib-membership-oracles + + de.learnlib + learnlib-drivers-simulator + de.learnlib learnlib-equivalence-oracles diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFALearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFALearnerIT.java index e371f78230..57b175749b 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFALearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractDFALearnerIT.java @@ -21,6 +21,7 @@ import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.examples.LearningExample.DFALearningExample; import de.learnlib.examples.LearningExamples; +import de.learnlib.oracle.equivalence.SimulatorEQOracle; import de.learnlib.oracle.membership.SimulatorOracle.DFASimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.DFALearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.DFALearnerVariantListImpl; @@ -58,7 +59,9 @@ private List>> createAllVariantsI final DFALearnerVariantListImpl variants = new DFALearnerVariantListImpl<>(); addLearnerVariants(alphabet, example.getReferenceAutomaton().size(), mqOracle, variants); - return LearnerITUtil.createExampleITCases(example, variants); + return LearnerITUtil.createExampleITCases(example, + variants, + new SimulatorEQOracle<>(example.getReferenceAutomaton())); } /** diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java index f070bf99a7..4a8c9e9390 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyLearnerIT.java @@ -21,6 +21,7 @@ import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.examples.LearningExample.MealyLearningExample; import de.learnlib.examples.LearningExamples; +import de.learnlib.oracle.equivalence.SimulatorEQOracle; import de.learnlib.oracle.membership.SimulatorOracle.MealySimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.MealyLearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.MealyLearnerVariantListImpl; @@ -60,7 +61,9 @@ public Object[] createExampleITCases() { final MealyLearnerVariantListImpl variants = new MealyLearnerVariantListImpl<>(); addLearnerVariants(alphabet, mqOracle, variants); - return LearnerITUtil.createExampleITCases(example, variants); + return LearnerITUtil.createExampleITCases(example, + variants, + new SimulatorEQOracle<>(example.getReferenceAutomaton())); } /** diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java index 6acf8cc648..cb75635354 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java @@ -22,6 +22,7 @@ import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.examples.LearningExample.MealyLearningExample; import de.learnlib.examples.LearningExamples; +import de.learnlib.oracle.equivalence.SimulatorEQOracle; import de.learnlib.oracle.membership.SimulatorOracle.MealySimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.MealySymLearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.MealySymLearnerVariantListImpl; @@ -62,7 +63,9 @@ public Object[] createExampleITCases() { final MealySymLearnerVariantListImpl variants = new MealySymLearnerVariantListImpl<>(); addLearnerVariants(alphabet, MealyUtil.wrapWordOracle(mqOracle), variants); - return LearnerITUtil.createExampleITCases(example, variants.getMealyLearnerVariants()); + return LearnerITUtil.createExampleITCases(example, + variants.getMealyLearnerVariants(), + new SimulatorEQOracle<>(example.getReferenceAutomaton())); } /** diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSLIMealyLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSLIMealyLearnerIT.java new file mode 100644 index 0000000000..bfd0392405 --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSLIMealyLearnerIT.java @@ -0,0 +1,77 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.testsupport.it.learner; + +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.driver.util.StateLocalInputMealySimulatorSUL; +import de.learnlib.examples.LearningExample.StateLocalInputMealyLearningExample; +import de.learnlib.examples.LearningExamples; +import de.learnlib.oracle.equivalence.mealy.StateLocalInputMealySimulatorEQOracle; +import de.learnlib.oracle.membership.StateLocalInputSULOracle; +import de.learnlib.testsupport.it.learner.LearnerVariantList.SLIMealyLearnerVariantList; +import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SLIMealyLearnerVariantListImpl; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; +import net.automatalib.words.Word; +import org.testng.annotations.Factory; + +/** + * Abstract integration test for {@link StateLocalInputMealyMachine} learning algorithms. + * + * @author frohme + */ +public abstract class AbstractSLIMealyLearnerIT { + + @Factory + public Object[] createExampleITCases() { + final List> result = new ArrayList<>(); + final List> examples = LearningExamples.createSLIMealyExamples(); + + for (StateLocalInputMealyLearningExample example : examples) { + result.addAll(createAllVariantsITCase(example)); + } + + return result.toArray(); + } + + private List>, StateLocalInputMealyMachine>> createAllVariantsITCase( + StateLocalInputMealyLearningExample example) { + + final StateLocalInputMealyOracle> mqOracle = + new StateLocalInputSULOracle<>(new StateLocalInputMealySimulatorSUL<>(example.getReferenceAutomaton())); + final SLIMealyLearnerVariantListImpl variants = new SLIMealyLearnerVariantListImpl<>(); + addLearnerVariants(mqOracle, variants); + + return LearnerITUtil.createExampleITCases(example, + variants, + new StateLocalInputMealySimulatorEQOracle<>(example.getReferenceAutomaton())); + } + + /** + * Adds, for a given setup, all the variants of the Mealy machine learner to be tested to the specified {@link + * LearnerVariantList variant list}. + * + * @param mqOracle + * the membership oracle + * @param variants + * list to add the learner variants to + */ + protected abstract void addLearnerVariants(StateLocalInputMealyOracle> mqOracle, + SLIMealyLearnerVariantList variants); +} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java index 84ac53f3b8..46fe443393 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Random; +import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.examples.LearningExample; import de.learnlib.examples.PassiveLearningExample; @@ -30,7 +31,6 @@ import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; - /** * Utility class for integration tests for a learning algorithm (or "learner"). *

    @@ -53,15 +53,16 @@ private LearnerITUtil() { * * @return the list of test cases, one for each example */ - public static & SuffixOutput> List> createExampleITCases( - LearningExample example, - LearnerVariantListImpl variants) { + public static > List> createExampleITCases( + LearningExample example, + LearnerVariantListImpl variants, + EquivalenceOracle eqOracle) { final List> variantList = variants.getLearnerVariants(); final List> result = new ArrayList<>(variantList.size()); for (LearnerVariant variant : variantList) { - result.add(new LearnerVariantITCase<>(variant, example)); + result.add(new LearnerVariantITCase<>(variant, example, eqOracle)); } return result; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantITCase.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantITCase.java index 54077fb64b..52d36a5a6d 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantITCase.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantITCase.java @@ -19,9 +19,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.examples.LearningExample; -import de.learnlib.oracle.equivalence.SimulatorEQOracle; import net.automatalib.automata.UniversalDeterministicAutomaton; -import net.automatalib.automata.concepts.SuffixOutput; import net.automatalib.util.automata.Automata; import net.automatalib.words.Alphabet; import org.slf4j.Logger; @@ -30,8 +28,7 @@ import org.testng.ITest; import org.testng.annotations.Test; -final class LearnerVariantITCase & SuffixOutput> - implements ITest { +final class LearnerVariantITCase> implements ITest { private static final Logger LOGGER = LoggerFactory.getLogger(LearnerVariantITCase.class); @@ -39,11 +36,15 @@ final class LearnerVariantITCase variant; - private final LearningExample example; + private final LearningExample example; + private final EquivalenceOracle eqOracle; - LearnerVariantITCase(LearnerVariant variant, LearningExample example) { + LearnerVariantITCase(LearnerVariant variant, + LearningExample example, + EquivalenceOracle eqOracle) { this.variant = variant; this.example = example; + this.eqOracle = eqOracle; } @Test @@ -57,8 +58,6 @@ public void testLearning() { maxRounds = example.getReferenceAutomaton().size(); } - EquivalenceOracle eqOracle = new SimulatorEQOracle<>(example.getReferenceAutomaton()); - long start = System.nanoTime(); learner.startLearning(); diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantList.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantList.java index f11765ec17..32c6a39699 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantList.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantList.java @@ -18,6 +18,8 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Word; @@ -73,6 +75,9 @@ interface MealyLearnerVariantList extends LearnerVariantList extends LearnerVariantList, I, O> {} + interface SLIMealyLearnerVariantList + extends LearnerVariantList, I, Word>> {} + interface OneSEVPALearnerVariantList extends LearnerVariantList, I, Boolean> {} } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantListImpl.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantListImpl.java index 94f328545f..61bddbc34d 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantListImpl.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantListImpl.java @@ -22,6 +22,8 @@ import de.learnlib.util.mealy.MealyUtil; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Word; @@ -51,6 +53,10 @@ public static class MealyLearnerVariantListImpl extends LearnerVariantListImpl, I, Word> implements MealyLearnerVariantList {} + public static class SLIMealyLearnerVariantListImpl + extends LearnerVariantListImpl, I, Word>> + implements SLIMealyLearnerVariantList {} + public static class OneSEVPALearnerVariantListImpl extends LearnerVariantListImpl, I, Boolean> implements OneSEVPALearnerVariantList {} diff --git a/test-support/learning-examples/pom.xml b/test-support/learning-examples/pom.xml index c352d04acc..1018485f6a 100644 --- a/test-support/learning-examples/pom.xml +++ b/test-support/learning-examples/pom.xml @@ -54,6 +54,10 @@ limitations under the License. net.automatalib automata-core + + net.automatalib + automata-commons-util + net.automatalib automata-util diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/DefaultLearningExample.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/DefaultLearningExample.java index 241cf5020a..8574011507 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/DefaultLearningExample.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/DefaultLearningExample.java @@ -37,7 +37,7 @@ * @author Malte Isberner */ public class DefaultLearningExample & SuffixOutput> - implements LearningExample { + implements LearningExample { private final Alphabet alphabet; private final A referenceAutomaton; diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExample.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExample.java index a18ed4822f..cce906eb2a 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExample.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExample.java @@ -16,20 +16,22 @@ package de.learnlib.examples; import net.automatalib.automata.UniversalAutomaton; -import net.automatalib.automata.concepts.SuffixOutput; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -public interface LearningExample & SuffixOutput> { +public interface LearningExample> { A getReferenceAutomaton(); Alphabet getAlphabet(); - interface DFALearningExample extends LearningExample> {} + interface DFALearningExample extends LearningExample> {} - interface MealyLearningExample extends LearningExample, MealyMachine> {} + interface MealyLearningExample extends LearningExample> {} + + interface StateLocalInputMealyLearningExample + extends LearningExample> {} } diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java index 0216f0d59d..2aa5a7ee4b 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java @@ -16,11 +16,13 @@ package de.learnlib.examples; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Random; import de.learnlib.examples.LearningExample.DFALearningExample; import de.learnlib.examples.LearningExample.MealyLearningExample; +import de.learnlib.examples.LearningExample.StateLocalInputMealyLearningExample; import de.learnlib.examples.dfa.ExampleAngluin; import de.learnlib.examples.dfa.ExampleKeylock; import de.learnlib.examples.dfa.ExamplePaulAndMary; @@ -28,6 +30,7 @@ import de.learnlib.examples.mealy.ExampleCoffeeMachine; import de.learnlib.examples.mealy.ExampleGrid; import de.learnlib.examples.mealy.ExampleRandomMealy; +import de.learnlib.examples.mealy.ExampleRandomStateLocalInputMealy; import de.learnlib.examples.mealy.ExampleShahbazGroz; import de.learnlib.examples.mealy.ExampleStack; import de.learnlib.examples.mealy.ExampleTinyMealy; @@ -68,4 +71,11 @@ public static List> createDFAExamples() { ExampleTinyMealy.createExample()); } + public static List> createSLIMealyExamples() { + return Collections.singletonList(ExampleRandomStateLocalInputMealy.createExample(new Random(RANDOM_SEED), + RANDOM_ALPHABET, + RANDOM_SIZE, + RANDOM_MEALY_OUTPUTS)); + } + } diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleRandomStateLocalInputMealy.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleRandomStateLocalInputMealy.java new file mode 100644 index 0000000000..87f7995d75 --- /dev/null +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleRandomStateLocalInputMealy.java @@ -0,0 +1,72 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.mealy; + +import java.util.Arrays; +import java.util.Random; + +import de.learnlib.examples.LearningExample.StateLocalInputMealyLearningExample; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.commons.util.random.RandomUtil; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.Alphabet; + +public class ExampleRandomStateLocalInputMealy implements StateLocalInputMealyLearningExample { + + private final CompactMealy automaton; + + @SafeVarargs + public ExampleRandomStateLocalInputMealy(Alphabet alphabet, int size, O... outputs) { + this(new Random(), alphabet, size, outputs); + } + + @SafeVarargs + public ExampleRandomStateLocalInputMealy(Random random, Alphabet alphabet, int size, O... outputs) { + this.automaton = RandomAutomata.randomDeterministic(random, + size, + alphabet, + null, + Arrays.asList(outputs), + new CompactMealy<>(alphabet)); + + final int alphabetSize = alphabet.size(); + + for (int i = 0; i < size; i++) { + // randomly remove some transitions + for (int idx : RandomUtil.distinctIntegers(random.nextInt(alphabetSize), alphabetSize, random)) { + this.automaton.removeAllTransitions(i, alphabet.getSymbol(idx)); + } + } + } + + @SafeVarargs + public static ExampleRandomStateLocalInputMealy createExample(Random random, + Alphabet alphabet, + int size, + O... outputs) { + return new ExampleRandomStateLocalInputMealy<>(random, alphabet, size, outputs); + } + + @Override + public CompactMealy getReferenceAutomaton() { + return this.automaton; + } + + @Override + public Alphabet getAlphabet() { + return this.automaton.getInputAlphabet(); + } +} diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java index f043d914ee..09757aeef8 100644 --- a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java @@ -20,11 +20,15 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.ResumableLearner; +import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.QueryAnswerer; +import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; +import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; /** @@ -50,4 +54,15 @@ protected MembershipOracle getOracle(DFA targe return ((QueryAnswerer) target::computeSuffixOutput).asOracle(); } + @Override + protected DFAEquivalenceOracle getEquivalenceOracle(DFA target) { + return (dfa, inputs) -> { + final Word separatingWord = Automata.findSeparatingWord(target, dfa, inputs); + if (separatingWord == null) { + return null; + } + return new DefaultQuery<>(separatingWord, target.computeOutput(separatingWord)); + }; + } + } diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java index 2902150c3e..ad8f86a29e 100644 --- a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java @@ -20,9 +20,12 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.ResumableLearner; +import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.QueryAnswerer; +import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -53,4 +56,15 @@ protected Alphabet getInitialAlphabet() { protected MembershipOracle> getOracle(MealyMachine target) { return ((QueryAnswerer>) target::computeSuffixOutput).asOracle(); } + + @Override + protected MealyEquivalenceOracle getEquivalenceOracle(MealyMachine target) { + return (mealy, inputs) -> { + final Word separatingWord = Automata.findSeparatingWord(target, mealy, inputs); + if (separatingWord == null) { + return null; + } + return new DefaultQuery<>(Word.epsilon(), separatingWord, target.computeOutput(separatingWord)); + }; + } } diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java index 162315bb52..4a20e169a5 100644 --- a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java @@ -23,12 +23,11 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.ResumableLearner; +import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.UniversalDeterministicAutomaton; -import net.automatalib.automata.concepts.Output; import net.automatalib.util.automata.Automata; import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -36,9 +35,22 @@ /** * Test class that checks the workflow of a learning algorithm that implements {@link ResumableLearner}. * + * @param + * learner type + * @param + * hypothesis type + * @param + * membership oracle type + * @param + * input symbol type + * @param + * output domain type + * @param + * serializable state type + * * @author bainczyk */ -public abstract class AbstractResumableLearnerTest & LearningAlgorithm, M extends UniversalDeterministicAutomaton & Output, OR, I, D, T extends Serializable> { +public abstract class AbstractResumableLearnerTest & LearningAlgorithm, M extends UniversalDeterministicAutomaton, OR, I, D, T extends Serializable> { protected static final int RANDOM_SEED = 42; @@ -68,6 +80,8 @@ public void setup() { protected abstract OR getOracle(M target); + protected abstract EquivalenceOracle getEquivalenceOracle(M target); + protected abstract L getLearner(OR oracle, Alphabet alphabet); protected abstract int getRounds(); @@ -81,13 +95,15 @@ public void testSuspendAndResumeLearner() throws Exception { int roundsPre = 0, roundsPost = 0; + EquivalenceOracle equivalenceOracle = getEquivalenceOracle(target); + while (true) { - final Word separatingWord = - Automata.findSeparatingWord(target, learner.getHypothesisModel(), inputAlphabet); - if (separatingWord == null) { + final M hyp = learner.getHypothesisModel(); + final DefaultQuery ce = equivalenceOracle.findCounterExample(hyp, inputAlphabet); + if (ce == null) { break; } - learner.refineHypothesis(new DefaultQuery<>(separatingWord, target.computeOutput(separatingWord))); + learner.refineHypothesis(ce); roundsPre++; if (roundsPre == rounds) { @@ -110,11 +126,12 @@ public void testSuspendAndResumeLearner() throws Exception { learner2.resume(serializedState); while (true) { - final Word word = Automata.findSeparatingWord(target, learner2.getHypothesisModel(), inputAlphabet); - if (word == null) { + final M hyp = learner2.getHypothesisModel(); + final DefaultQuery ce = equivalenceOracle.findCounterExample(hyp, inputAlphabet); + if (ce == null) { break; } - learner2.refineHypothesis(new DefaultQuery<>(word, target.computeOutput(word))); + learner2.refineHypothesis(ce); roundsPost++; } From 8083aab2f8cf410f6aca95ca190bf0f3a745d1f9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 19 Jan 2019 18:55:38 +0100 Subject: [PATCH 111/125] partially revert 71f2bf3 Move Resumable* and Growing* tests back to the learner-it module so we can use SimulatorEQOracless again and Caches for the future. --- algorithms/active/adt/pom.xml | 5 ----- algorithms/active/dhc/pom.xml | 4 ---- algorithms/active/discrimination-tree-vpda/pom.xml | 4 ---- algorithms/active/discrimination-tree/pom.xml | 4 ---- algorithms/active/kearns-vazirani/pom.xml | 4 ---- algorithms/active/lstar/pom.xml | 4 ---- algorithms/active/nlstar/pom.xml | 4 ---- algorithms/active/ttt-vpda/pom.xml | 4 ---- algorithms/active/ttt/pom.xml | 4 ---- .../testsupport/AbstractGrowingAlphabetDFATest.java | 0 .../AbstractGrowingAlphabetMealyTest.java | 0 .../testsupport/AbstractGrowingAlphabetTest.java | 0 .../testsupport/AbstractResumableLearnerDFATest.java | 12 ++---------- .../AbstractResumableLearnerMealyTest.java | 11 ++--------- .../testsupport/AbstractResumableLearnerTest.java | 0 test-support/test-support/pom.xml | 8 -------- 16 files changed, 4 insertions(+), 64 deletions(-) rename test-support/{test-support => learner-it-support}/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java (100%) rename test-support/{test-support => learner-it-support}/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java (100%) rename test-support/{test-support => learner-it-support}/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java (100%) rename test-support/{test-support => learner-it-support}/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java (83%) rename test-support/{test-support => learner-it-support}/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java (85%) rename test-support/{test-support => learner-it-support}/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java (100%) diff --git a/algorithms/active/adt/pom.xml b/algorithms/active/adt/pom.xml index 191dfceba5..0e10f411d9 100644 --- a/algorithms/active/adt/pom.xml +++ b/algorithms/active/adt/pom.xml @@ -95,11 +95,6 @@ limitations under the License. learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - - de.learnlib learnlib-drivers-simulator diff --git a/algorithms/active/dhc/pom.xml b/algorithms/active/dhc/pom.xml index aac4379ac7..906714dd09 100644 --- a/algorithms/active/dhc/pom.xml +++ b/algorithms/active/dhc/pom.xml @@ -103,10 +103,6 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - diff --git a/algorithms/active/discrimination-tree-vpda/pom.xml b/algorithms/active/discrimination-tree-vpda/pom.xml index 18a91d22a5..436e200b6d 100644 --- a/algorithms/active/discrimination-tree-vpda/pom.xml +++ b/algorithms/active/discrimination-tree-vpda/pom.xml @@ -86,9 +86,5 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - diff --git a/algorithms/active/discrimination-tree/pom.xml b/algorithms/active/discrimination-tree/pom.xml index 4fa64a1215..a94716763e 100644 --- a/algorithms/active/discrimination-tree/pom.xml +++ b/algorithms/active/discrimination-tree/pom.xml @@ -76,10 +76,6 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - de.learnlib learnlib-membership-oracles diff --git a/algorithms/active/kearns-vazirani/pom.xml b/algorithms/active/kearns-vazirani/pom.xml index dee85566c4..0a6125f158 100644 --- a/algorithms/active/kearns-vazirani/pom.xml +++ b/algorithms/active/kearns-vazirani/pom.xml @@ -69,10 +69,6 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - com.github.misberner.buildergen buildergen diff --git a/algorithms/active/lstar/pom.xml b/algorithms/active/lstar/pom.xml index 31991c2285..6514804d87 100644 --- a/algorithms/active/lstar/pom.xml +++ b/algorithms/active/lstar/pom.xml @@ -103,10 +103,6 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - de.learnlib learnlib-equivalence-oracles diff --git a/algorithms/active/nlstar/pom.xml b/algorithms/active/nlstar/pom.xml index d6cfa0f1cd..39769a45b2 100644 --- a/algorithms/active/nlstar/pom.xml +++ b/algorithms/active/nlstar/pom.xml @@ -59,10 +59,6 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - org.testng testng diff --git a/algorithms/active/ttt-vpda/pom.xml b/algorithms/active/ttt-vpda/pom.xml index 17cb2dff12..1371469403 100644 --- a/algorithms/active/ttt-vpda/pom.xml +++ b/algorithms/active/ttt-vpda/pom.xml @@ -92,9 +92,5 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - diff --git a/algorithms/active/ttt/pom.xml b/algorithms/active/ttt/pom.xml index 859be7c356..b6f72079d0 100644 --- a/algorithms/active/ttt/pom.xml +++ b/algorithms/active/ttt/pom.xml @@ -101,10 +101,6 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - - de.learnlib.testsupport - learnlib-test-support - diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java similarity index 100% rename from test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java rename to test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java similarity index 100% rename from test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java rename to test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java similarity index 100% rename from test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java rename to test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java similarity index 83% rename from test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java rename to test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java index 09757aeef8..ce5d412f5f 100644 --- a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java @@ -23,12 +23,10 @@ import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.QueryAnswerer; -import de.learnlib.api.query.DefaultQuery; +import de.learnlib.oracle.equivalence.SimulatorEQOracle.DFASimulatorEQOracle; import net.automatalib.automata.fsa.DFA; -import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; /** @@ -56,13 +54,7 @@ protected MembershipOracle getOracle(DFA targe @Override protected DFAEquivalenceOracle getEquivalenceOracle(DFA target) { - return (dfa, inputs) -> { - final Word separatingWord = Automata.findSeparatingWord(target, dfa, inputs); - if (separatingWord == null) { - return null; - } - return new DefaultQuery<>(separatingWord, target.computeOutput(separatingWord)); - }; + return new DFASimulatorEQOracle<>(target); } } diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java similarity index 85% rename from test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java rename to test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java index ad8f86a29e..af0d7994ef 100644 --- a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java @@ -23,9 +23,8 @@ import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.QueryAnswerer; -import de.learnlib.api.query.DefaultQuery; +import de.learnlib.oracle.equivalence.SimulatorEQOracle.MealySimulatorEQOracle; import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -59,12 +58,6 @@ protected MembershipOracle> getOracle(MealyMachine getEquivalenceOracle(MealyMachine target) { - return (mealy, inputs) -> { - final Word separatingWord = Automata.findSeparatingWord(target, mealy, inputs); - if (separatingWord == null) { - return null; - } - return new DefaultQuery<>(Word.epsilon(), separatingWord, target.computeOutput(separatingWord)); - }; + return new MealySimulatorEQOracle<>(target); } } diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java similarity index 100% rename from test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java rename to test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerTest.java diff --git a/test-support/test-support/pom.xml b/test-support/test-support/pom.xml index 78e72e3857..eea5e4f35f 100644 --- a/test-support/test-support/pom.xml +++ b/test-support/test-support/pom.xml @@ -24,14 +24,6 @@ net.automatalib automata-core - - net.automatalib - automata-util - - - de.learnlib - learnlib-api - de.learnlib learnlib-util From 1df2b25f7fdd3f9bd5bc515de7cf7e0d45aae399 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 19 Jan 2019 21:49:16 +0100 Subject: [PATCH 112/125] update functionality revolving new input symbols - In order to use the SupportsGrowingAlphabet#addAlphabetSymbol functionality, structures now need to be initialized with a GrowingAlphabet (to make sure the user decides the alphabet implementation). Otherwise an exception will be thrown. - The different learner implementations no longer early-exit if the alphabet already contains the symbol. They now always check if enough memory is allocated for handling all input symbols at the time of calling #addAlphabetSymbol. This allows a more fail-safe handling of a shared mutable state (i.e. GrowingAlphabet). - Add SupportsGrowingAlphabet support for caches (fixes #56) --- .../algorithms/adt/learner/ADTLearner.java | 36 +++++------ .../adt/learner/ADTGrowingAlphabetTest.java | 10 +++ .../algorithms/dhc/mealy/MealyDHC.java | 36 ++++++----- .../discriminationtree/AbstractDTLearner.java | 38 +++++------ .../hypothesis/DTLearnerHypothesis.java | 29 ++++++--- .../algorithms/kv/dfa/KearnsVaziraniDFA.java | 46 ++++++------- .../kv/mealy/KearnsVaziraniMealy.java | 58 ++++++++--------- .../lstar/AbstractAutomatonLStar.java | 17 ++--- .../algorithms/lstar/AbstractLStar.java | 16 ++--- .../lstar/mealy/PartialLStarMealy.java | 3 +- .../ttt/base/AbstractTTTHypothesis.java | 21 ++++-- .../ttt/base/AbstractTTTLearner.java | 42 ++++++------ .../feature/SupportsGrowingAlphabet.java | 4 +- .../GenericObservationTable.java | 64 +++++++++++-------- .../filter/cache/dfa/DFACacheOracle.java | 8 ++- .../filter/cache/mealy/MealyCacheOracle.java | 9 ++- test-support/learner-it-support/pom.xml | 4 ++ .../AbstractGrowingAlphabetDFATest.java | 13 ++++ .../AbstractGrowingAlphabetMealyTest.java | 12 ++++ .../AbstractGrowingAlphabetTest.java | 61 ++++++++++++++---- 20 files changed, 314 insertions(+), 213 deletions(-) diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java index dfa4d0ace1..4b65b8ab0b 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java @@ -61,11 +61,11 @@ import de.learnlib.util.MQUtil; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import net.automatalib.words.impl.Alphabets; -import net.automatalib.words.impl.SymbolHidingAlphabet; /** * The main learning algorithm. @@ -83,7 +83,7 @@ public class ADTLearner implements LearningAlgorithm.MealyLearner, SupportsGrowingAlphabet, ResumableLearner, I, O>> { - private Alphabet alphabet; + private final Alphabet alphabet; private final SQOOTBridge oracle; private final LeafSplitter leafSplitter; private final ADTExtender adtExtender; @@ -111,7 +111,7 @@ public ADTLearner(final Alphabet alphabet, final SubtreeReplacer subtreeReplacer, final boolean useObservationTree) { - this.alphabet = SymbolHidingAlphabet.wrapIfMutable(alphabet); + this.alphabet = alphabet; this.observationTree = new ObservationTree<>(this.alphabet); this.oracle = new SQOOTBridge<>(this.observationTree, oracle, useObservationTree); @@ -376,29 +376,25 @@ public boolean isTransitionDefined(ADTState state, I input) { } @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); } this.hypothesis.addAlphabetSymbol(symbol); + this.observationTree.getObservationTree().addAlphabetSymbol(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) { + for (final ADTState s : this.hypothesis.getStates()) { + this.openTransitions.add(this.hypothesis.createOpenTransition(s, symbol, this.adt.getRoot())); + } - SymbolHidingAlphabet.runWhileHiding(alphabet, - symbol, - () -> this.observationTree.getObservationTree().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); - } - - for (final ADTState s : this.hypothesis.getStates()) { - this.openTransitions.add(this.hypothesis.createOpenTransition(s, symbol, this.adt.getRoot())); + this.closeTransitions(); } - - this.closeTransitions(); } @Override diff --git a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/learner/ADTGrowingAlphabetTest.java b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/learner/ADTGrowingAlphabetTest.java index 7b56cff65b..bbfa8367a5 100644 --- a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/learner/ADTGrowingAlphabetTest.java +++ b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/learner/ADTGrowingAlphabetTest.java @@ -16,7 +16,9 @@ package de.learnlib.algorithms.adt.learner; import java.util.Collection; +import java.util.List; import java.util.Random; +import java.util.function.Consumer; import de.learnlib.algorithms.adt.config.ADTExtenders; import de.learnlib.algorithms.adt.config.LeafSplitters; @@ -67,4 +69,12 @@ protected ADTLearner getLearner(SymbolQueryOracle getCachedOracle(Alphabet alphabet, + SymbolQueryOracle original, + List> symbolListener) { + // ADT learner already uses a cache internally. + return original; + } + } diff --git a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java index 9a9323048f..dc08df94c3 100644 --- a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java +++ b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java @@ -43,6 +43,7 @@ import net.automatalib.automata.transducers.impl.compact.CompactMealy; import net.automatalib.commons.util.mappings.MapMapping; import net.automatalib.commons.util.mappings.MutableMapping; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -60,7 +61,7 @@ public class MealyDHC implements MealyLearner, private static final Logger LOG = LoggerFactory.getLogger(MealyDHC.class); private final MembershipOracle> oracle; - private Alphabet alphabet; + private final Alphabet alphabet; private LinkedHashSet> splitters = new LinkedHashSet<>(); private CompactMealy hypothesis; private MutableMapping> accessSequences; @@ -249,30 +250,31 @@ public CompactMealy getHypothesisModel() { } @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 Iterator> splitterIterator = this.splitters.iterator(); - final LinkedHashSet> newSplitters = Sets.newLinkedHashSetWithExpectedSize(this.splitters.size() + 1); + if (!this.splitters.contains(Word.fromLetter(symbol))) { + final Iterator> splitterIterator = this.splitters.iterator(); + final LinkedHashSet> newSplitters = Sets.newLinkedHashSetWithExpectedSize(this.splitters.size() + 1); - // see initial initialization of the splitters - for (int i = 0; i < this.alphabet.size(); i++) { - newSplitters.add(splitterIterator.next()); - } + // see initial initialization of the splitters + for (int i = 0; i < this.alphabet.size() - 1; i++) { + newSplitters.add(splitterIterator.next()); + } - newSplitters.add(Word.fromLetter(symbol)); + newSplitters.add(Word.fromLetter(symbol)); - while (splitterIterator.hasNext()) { - newSplitters.add(splitterIterator.next()); - } + while (splitterIterator.hasNext()) { + newSplitters.add(splitterIterator.next()); + } - this.alphabet = Alphabets.withNewSymbol(this.alphabet, symbol); - this.splitters = newSplitters; + this.splitters = newSplitters; - this.startLearning(); + this.startLearning(); + } } @Override 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 72758b31e1..bf47fc9338 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 @@ -35,6 +35,7 @@ import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree; import de.learnlib.util.MQUtil; 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; @@ -44,7 +45,7 @@ public abstract class AbstractDTLearner, I, D, SP, SupportsGrowingAlphabet, ResumableLearner> { - protected Alphabet alphabet; + protected final Alphabet alphabet; private final MembershipOracle oracle; private final LocalSuffixFinder suffixFinder; private final boolean repeatedCounterexampleEvaluation; @@ -69,7 +70,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"); @@ -228,30 +229,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 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 357f93229a..c954adaaca 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 @@ -55,18 +55,24 @@ public class DTLearnerHypothesis GrowableAlphabetAutomaton, 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/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java index 252b7c58c6..c2dacdbb38 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java @@ -38,6 +38,7 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.fsa.impl.compact.CompactDFA; import net.automatalib.commons.smartcollections.ArrayStorage; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -54,7 +55,7 @@ public class KearnsVaziraniDFA implements DFALearner, SupportsGrowingAlphabet, ResumableLearner> { - private Alphabet alphabet; + private final Alphabet alphabet; private final MembershipOracle oracle; private final boolean repeatedCounterexampleEvaluation; private final AcexAnalyzer ceAnalyzer; @@ -293,38 +294,37 @@ private List> sift(List> transAs = new ArrayList<>(this.stateInfos.size()); + for (final StateInfo si : this.stateInfos) { + transAs.add(si.accessSequence.append(symbol)); + } - // use new list to prevent concurrent modification exception - final List> transAs = new ArrayList<>(this.stateInfos.size()); - for (final StateInfo si : this.stateInfos) { - transAs.add(si.accessSequence.append(symbol)); - } + final List> succs = sift(transAs); - final List> succs = sift(transAs); + final Iterator> stateIter = this.stateInfos.iterator(); + final Iterator> leafsIter = succs.iterator(); + final int inputIdx = this.alphabet.getSymbolIndex(symbol); - final Iterator> stateIter = this.stateInfos.iterator(); - final Iterator> leafsIter = succs.iterator(); + while (stateIter.hasNext() && leafsIter.hasNext()) { + setTransition(stateIter.next().id, inputIdx, leafsIter.next()); + } - while (stateIter.hasNext() && leafsIter.hasNext()) { - setTransition(stateIter.next().id, inputIdx, leafsIter.next()); + assert !stateIter.hasNext(); + assert !leafsIter.hasNext(); } - - assert !stateIter.hasNext(); - assert !leafsIter.hasNext(); } @Override diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java index 7f6c2a365c..9175696f07 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java @@ -39,6 +39,7 @@ import de.learnlib.util.mealy.MealyUtil; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -56,7 +57,7 @@ public class KearnsVaziraniMealy implements MealyLearner, SupportsGrowingAlphabet, ResumableLearner> { - private Alphabet alphabet; + private final Alphabet alphabet; private final MembershipOracle> oracle; private final boolean repeatedCounterexampleEvaluation; private final AcexAnalyzer ceAnalyzer; @@ -308,42 +309,41 @@ private List>> sift(List } @Override - public void addAlphabetSymbol(I symbol) { + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { - if (this.alphabet.containsSymbol(symbol)) { - return; - } - - final int inputIdx = 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); + Alphabets.toGrowingAlphabetOrThrowException(this.alphabet).addSymbol(symbol); } - // use new list to prevent concurrent modification exception - final List> transAs = new ArrayList<>(this.stateInfos.size()); - final List>> outputQueries = new ArrayList<>(this.stateInfos.size()); + this.hypothesis.addAlphabetSymbol(symbol); - for (final StateInfo> si : this.stateInfos) { - transAs.add(si.accessSequence.append(symbol)); - outputQueries.add(new DefaultQuery<>(si.accessSequence, Word.fromLetter(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) { + // use new list to prevent concurrent modification exception + final List> transAs = new ArrayList<>(this.stateInfos.size()); + final List>> outputQueries = new ArrayList<>(this.stateInfos.size()); + + for (final StateInfo> si : this.stateInfos) { + transAs.add(si.accessSequence.append(symbol)); + outputQueries.add(new DefaultQuery<>(si.accessSequence, Word.fromLetter(symbol))); + } - final List>> succs = sift(transAs); - this.oracle.processQueries(outputQueries); + final List>> succs = sift(transAs); + this.oracle.processQueries(outputQueries); - final Iterator>> stateIter = this.stateInfos.iterator(); - final Iterator>> leafsIter = succs.iterator(); - final Iterator>> outputsIter = outputQueries.iterator(); + final Iterator>> stateIter = this.stateInfos.iterator(); + final Iterator>> leafsIter = succs.iterator(); + final Iterator>> outputsIter = outputQueries.iterator(); + final int inputIdx = this.alphabet.getSymbolIndex(symbol); - while (stateIter.hasNext() && leafsIter.hasNext()) { - setTransition(stateIter.next().id, - inputIdx, - leafsIter.next(), - outputsIter.next().getOutput().firstSymbol()); + while (stateIter.hasNext() && leafsIter.hasNext()) { + setTransition(stateIter.next().id, + inputIdx, + leafsIter.next(), + outputsIter.next().getOutput().firstSymbol()); + } } } diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java index 68f0fc5b2c..1a41056663 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java @@ -27,8 +27,8 @@ import de.learnlib.datastructure.observationtable.Row; import net.automatalib.automata.GrowableAlphabetAutomaton; import net.automatalib.automata.MutableDeterministic; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.SymbolHidingAlphabet; /** * Abstract base class for algorithms that produce (subclasses of) {@link MutableDeterministic} automata. @@ -64,7 +64,7 @@ public abstract class AbstractAutomatonLStar alphabet, MembershipOracle oracle, AI internalHyp) { - super(SymbolHidingAlphabet.wrapIfMutable(alphabet), oracle); + super(alphabet, oracle); this.internalHyp = internalHyp; internalHyp.clear(); } @@ -189,17 +189,14 @@ protected void refineHypothesisInternal(DefaultQuery ceQuery) { } @Override - public void addAlphabetSymbol(I symbol) { - - if (alphabet.containsSymbol(symbol)) { - return; - } + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + super.addAlphabetSymbol(symbol); this.internalHyp.addAlphabetSymbol(symbol); - SymbolHidingAlphabet.runWhileHiding(alphabet, symbol, () -> super.addAlphabetSymbol(symbol)); - - this.updateInternalHypothesis(); + if (this.table.isInitialized()) { + this.updateInternalHypothesis(); + } } @Override diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java index f28bdf9ab2..e3883caa6d 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java @@ -33,6 +33,7 @@ import de.learnlib.datastructure.observationtable.Row; import de.learnlib.util.MQUtil; 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; @@ -56,7 +57,7 @@ public abstract class AbstractLStar implements OTLearner, GlobalSuffixLearner, SupportsGrowingAlphabet { - protected Alphabet alphabet; + protected final Alphabet alphabet; protected final MembershipOracle oracle; protected GenericObservationTable table; @@ -226,20 +227,13 @@ public ObservationTable getObservationTable() { } @Override - public void addAlphabetSymbol(I symbol) { + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { - if (this.alphabet.containsSymbol(symbol)) { - return; - } - - final List>> unclosed = this.table.addAlphabetSymbol(symbol, oracle); - - // since we share the alphabet instance with our observation table, 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); + Alphabets.toGrowingAlphabetOrThrowException(this.alphabet).addSymbol(symbol); } + final List>> unclosed = this.table.addAlphabetSymbol(symbol, oracle); completeConsistentTable(unclosed, true); } } diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/PartialLStarMealy.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/PartialLStarMealy.java index 2bbe572625..729001ecb2 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/PartialLStarMealy.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/PartialLStarMealy.java @@ -38,6 +38,7 @@ import net.automatalib.automata.transducers.StateLocalInputMealyMachine; import net.automatalib.automata.transducers.impl.compact.CompactMealy; import net.automatalib.automata.transducers.impl.compact.CompactMealyTransition; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.util.automata.transducers.StateLocalInputMealyUtil; import net.automatalib.words.GrowingAlphabet; import net.automatalib.words.Word; @@ -187,7 +188,7 @@ protected SuffixOutput>> hypothesisOutput() { } @Override - public void addAlphabetSymbol(I symbol) { + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { LOGGER.info("Adding new symbols to a system, which already exposes its available actions has no effect"); LOGGER.info("Skipping ..."); } diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java index e6af8d672d..29a27eb7ab 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java @@ -30,6 +30,7 @@ import net.automatalib.visualization.DefaultVisualizationHelper; import net.automatalib.visualization.VisualizationHelper; import net.automatalib.words.Alphabet; +import net.automatalib.words.GrowingAlphabet; import net.automatalib.words.impl.Alphabets; /** @@ -49,6 +50,7 @@ public abstract class AbstractTTTHypothesis implements DeterministicAut protected final List> states = new ArrayList<>(); protected transient Alphabet alphabet; + private int alphabetSize; private TTTState initialState; @@ -60,6 +62,7 @@ public abstract class AbstractTTTHypothesis implements DeterministicAut */ public AbstractTTTHypothesis(Alphabet alphabet) { this.alphabet = alphabet; + this.alphabetSize = this.alphabet.size(); } @Override @@ -77,7 +80,7 @@ public T getTransition(int stateId, int symIdx) { @Override public T getTransition(TTTState state, I input) { TTTTransition trans = getInternalTransition(state, input); - return mapTransition(trans); + return trans == null ? null : mapTransition(trans); } /** @@ -173,16 +176,20 @@ public DeterministicAutomaton.FullIntAbstraction fullIntAbstraction(Alphabet< @Override public void addAlphabetSymbol(I symbol) { - if (this.alphabet.containsSymbol(symbol)) { - return; + final GrowingAlphabet growingAlphabet = Alphabets.toGrowingAlphabetOrThrowException(this.alphabet); + + if (!growingAlphabet.containsSymbol(symbol)) { + growingAlphabet.addSymbol(symbol); } - this.alphabet = Alphabets.withNewSymbol(this.alphabet, symbol); + final int newAlphabetSize = growingAlphabet.size(); - final int alphabetSize = this.alphabet.size(); + if (alphabetSize < newAlphabetSize) { + for (final TTTState s : this.getStates()) { + s.ensureInputCapacity(newAlphabetSize); + } - for (final TTTState s : this.getStates()) { - s.ensureInputCapacity(alphabetSize); + alphabetSize = newAlphabetSize; } } diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java index 80f0b52f21..60788ab355 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java @@ -44,6 +44,7 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.commons.smartcollections.ElementReference; import net.automatalib.commons.smartcollections.UnorderedCollection; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -59,7 +60,7 @@ public abstract class AbstractTTTLearner implements LearningAlgorithm, SupportsGrowingAlphabet, ResumableLearner> { - protected Alphabet alphabet; + protected final Alphabet alphabet; protected final MembershipOracle oracle; protected final AcexAnalyzer analyzer; /** @@ -230,10 +231,7 @@ protected boolean refineHypothesisSingle(DefaultQuery ceQuery) { * @param tempDiscriminator * the temporary discriminator */ - private void splitState(TTTTransition transition, - Word tempDiscriminator, - D oldOut, - D newOut) { + private void splitState(TTTTransition transition, Word tempDiscriminator, D oldOut, D newOut) { assert !transition.isTree(); notifyPreSplit(transition, tempDiscriminator); @@ -987,30 +985,30 @@ public void removeEventListener(TTTEventListener listener) { } @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) { - for (final TTTState s : this.hypothesis.getStates()) { - final TTTTransition trans = createTransition(s, symbol); - trans.setNonTreeTarget(dtree.getRoot()); - s.setTransition(newSymbolIdx, trans); - openTransitions.insertIncoming(trans); - } + final int newSymbolIdx = this.alphabet.getSymbolIndex(symbol); - this.closeTransitions(); + for (final TTTState s : this.hypothesis.getStates()) { + final TTTTransition trans = createTransition(s, symbol); + trans.setNonTreeTarget(dtree.getRoot()); + s.setTransition(newSymbolIdx, trans); + openTransitions.insertIncoming(trans); + } + + this.closeTransitions(); + } } protected abstract AbstractBaseDTNode createNewNode(AbstractBaseDTNode parent, D parentOutput); diff --git a/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java b/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java index 0671293563..d42dfcc50c 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java +++ b/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java @@ -15,11 +15,13 @@ */ package de.learnlib.api.algorithm.feature; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; + /** * @author Maik Merten */ public interface SupportsGrowingAlphabet { - void addAlphabetSymbol(I symbol); + void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException; } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java index 3ce4a6fb47..a0e845ac02 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java @@ -51,7 +51,8 @@ * In order to derive a well-defined hypothesis from an observation table, it must satisfy two properties: closedness * and consistency.

    * @@ -77,6 +78,7 @@ public class GenericObservationTable implements MutableObservationTable> suffixes = new ArrayList<>(); protected final Set> suffixSet = new HashSet<>(); private transient Alphabet alphabet; + private transient int alphabetSize; private int numRows; protected boolean initialConsistencyCheckRequired; @@ -88,6 +90,7 @@ public class GenericObservationTable implements MutableObservationTable alphabet) { this.alphabet = alphabet; + this.alphabetSize = alphabet.size(); } protected static void buildQueries(List> queryList, @@ -549,48 +552,53 @@ private boolean isCanonical(Row row) { @Override public List>> addAlphabetSymbol(I symbol, final MembershipOracle oracle) { - if (this.alphabet.containsSymbol(symbol)) { - return Collections.emptyList(); + if (!this.alphabet.containsSymbol(symbol)) { + Alphabets.toGrowingAlphabetOrThrowException(this.alphabet).addSymbol(symbol); } - this.alphabet = Alphabets.withNewSymbol(this.alphabet, symbol); final int newAlphabetSize = this.alphabet.size(); - final int newSymbolIdx = this.alphabet.getSymbolIndex(symbol); - final List> shortPrefixes = shortPrefixRows; - final List> newLongPrefixes = new ArrayList<>(shortPrefixes.size()); + if (this.isInitialized() && this.alphabetSize < newAlphabetSize) { + this.alphabetSize = newAlphabetSize; + final int newSymbolIdx = this.alphabet.getSymbolIndex(symbol); - for (RowImpl prefix : shortPrefixes) { - prefix.ensureInputCapacity(newAlphabetSize); + final List> shortPrefixes = shortPrefixRows; + final List> newLongPrefixes = new ArrayList<>(shortPrefixes.size()); - final Word newLongPrefix = prefix.getLabel().append(symbol); - final RowImpl longPrefixRow = createLpRow(newLongPrefix); + for (RowImpl prefix : shortPrefixes) { + prefix.ensureInputCapacity(newAlphabetSize); - newLongPrefixes.add(longPrefixRow); - prefix.setSuccessor(newSymbolIdx, longPrefixRow); - } + final Word newLongPrefix = prefix.getLabel().append(symbol); + final RowImpl longPrefixRow = createLpRow(newLongPrefix); - final int numLongPrefixes = newLongPrefixes.size(); - final int numSuffixes = this.numberOfSuffixes(); - final List> queries = new ArrayList<>(numLongPrefixes * numSuffixes); + newLongPrefixes.add(longPrefixRow); + prefix.setSuccessor(newSymbolIdx, longPrefixRow); + } - buildRowQueries(queries, newLongPrefixes, suffixes); - oracle.processQueries(queries); + final int numLongPrefixes = newLongPrefixes.size(); + final int numSuffixes = this.numberOfSuffixes(); + final List> queries = new ArrayList<>(numLongPrefixes * numSuffixes); - final Iterator> queryIterator = queries.iterator(); - final List>> result = new ArrayList<>(numLongPrefixes); + buildRowQueries(queries, newLongPrefixes, suffixes); + oracle.processQueries(queries); - for (RowImpl row : newLongPrefixes) { - final List contents = new ArrayList<>(numSuffixes); + final Iterator> queryIterator = queries.iterator(); + final List>> result = new ArrayList<>(numLongPrefixes); - fetchResults(queryIterator, contents, numSuffixes); + for (RowImpl row : newLongPrefixes) { + final List contents = new ArrayList<>(numSuffixes); - if (processContents(row, contents, false)) { - result.add(Collections.singletonList(row)); + fetchResults(queryIterator, contents, numSuffixes); + + if (processContents(row, contents, false)) { + result.add(Collections.singletonList(row)); + } } - } - return result; + return result; + } else { + return Collections.emptyList(); + } } @Nonnull diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java index f3afc39484..871ed8f2a4 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java @@ -23,9 +23,11 @@ import javax.annotation.ParametersAreNonnullByDefault; +import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.filter.cache.LearningCacheOracle.DFALearningCacheOracle; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.incremental.dfa.Acceptance; import net.automatalib.incremental.dfa.IncrementalDFABuilder; import net.automatalib.incremental.dfa.dag.IncrementalDFADAGBuilder; @@ -46,7 +48,7 @@ * @author Malte Isberner */ @ParametersAreNonnullByDefault -public class DFACacheOracle implements DFALearningCacheOracle { +public class DFACacheOracle implements DFALearningCacheOracle, SupportsGrowingAlphabet { private final IncrementalDFABuilder incDfa; private final Lock incDfaLock; @@ -180,4 +182,8 @@ public void processQueries(Collection> queries) { } } + @Override + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + incDfa.addAlphabetSymbol(symbol); + } } diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java index 44c229cec4..2aea38c81c 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java @@ -24,11 +24,13 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; import net.automatalib.commons.util.comparison.CmpUtil; import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.incremental.mealy.IncrementalMealyBuilder; import net.automatalib.incremental.mealy.dag.IncrementalMealyDAGBuilder; import net.automatalib.incremental.mealy.tree.IncrementalMealyTreeBuilder; @@ -56,7 +58,7 @@ * * @author Malte Isberner */ -public class MealyCacheOracle implements MealyLearningCacheOracle { +public class MealyCacheOracle implements MealyLearningCacheOracle, SupportsGrowingAlphabet { private final MembershipOracle> delegate; private final IncrementalMealyBuilder incMealy; @@ -218,6 +220,11 @@ private void postProcess(MasterQuery master) { } } + @Override + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + incMealy.addAlphabetSymbol(symbol); + } + private static final class ReverseLexCmp implements Comparator>, Serializable { private final Alphabet alphabet; diff --git a/test-support/learner-it-support/pom.xml b/test-support/learner-it-support/pom.xml index 8a118c0e63..5dfa2df630 100644 --- a/test-support/learner-it-support/pom.xml +++ b/test-support/learner-it-support/pom.xml @@ -44,6 +44,10 @@ limitations under the License. de.learnlib learnlib-drivers-simulator + + de.learnlib + learnlib-cache + de.learnlib learnlib-equivalence-oracles diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java index 77f87cbedb..2fc87af6fc 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java @@ -16,12 +16,16 @@ package de.learnlib.testsupport; import java.util.Collection; +import java.util.List; import java.util.Random; +import java.util.function.Consumer; import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.QueryAnswerer; +import de.learnlib.filter.cache.dfa.DFACacheOracle; +import de.learnlib.filter.cache.dfa.DFACaches; import net.automatalib.automata.fsa.DFA; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; @@ -53,4 +57,13 @@ protected MembershipOracle getOracle(DFA targe return ((QueryAnswerer) target::computeSuffixOutput).asOracle(); } + @Override + protected MembershipOracle getCachedOracle(Alphabet alphabet, + MembershipOracle original, + List> symbolListener) { + final DFACacheOracle cache = DFACaches.createDAGCache(alphabet, original); + symbolListener.add(cache::addAlphabetSymbol); + return cache; + } + } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java index 2f71faa25a..ca86ecb897 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java @@ -16,12 +16,16 @@ package de.learnlib.testsupport; import java.util.Collection; +import java.util.List; import java.util.Random; +import java.util.function.Consumer; import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.QueryAnswerer; +import de.learnlib.filter.cache.mealy.MealyCacheOracle; +import de.learnlib.filter.cache.mealy.MealyCaches; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; @@ -57,4 +61,12 @@ protected MembershipOracle> getOracle(MealyMachine>) target::computeSuffixOutput).asOracle(); } + @Override + protected MembershipOracle> getCachedOracle(Alphabet alphabet, + MembershipOracle> source, + List> symbolListener) { + final MealyCacheOracle cache = MealyCaches.createDAGCache(alphabet, source); + symbolListener.add(cache::addAlphabetSymbol); + return cache; + } } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java index adea1fbb1e..41e88a9453 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java @@ -17,15 +17,19 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.function.Consumer; import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.Output; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.util.automata.Automata; import net.automatalib.words.Alphabet; +import net.automatalib.words.GrowingAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; import net.automatalib.words.impl.SimpleAlphabet; @@ -50,12 +54,14 @@ public abstract class AbstractGrowingAlphabetTest initialAlphabet; - private Collection alphabetExtensions; + private List alphabetExtensions; @BeforeClass public void setup() { initialAlphabet = getInitialAlphabet(); - alphabetExtensions = getAlphabetExtensions(); + alphabetExtensions = new ArrayList<>(getAlphabetExtensions()); + + assert alphabetExtensions.size() > 2 : "At least 3 symbols need to be added for proper coverage"; final List compoundAlphabet = new ArrayList<>(initialAlphabet.size() + alphabetExtensions.size()); compoundAlphabet.addAll(initialAlphabet); @@ -73,25 +79,45 @@ public void setup() { protected abstract OR getOracle(M target); + protected abstract OR getCachedOracle(Alphabet alphabet, OR source, List> symbolListener); + protected abstract L getLearner(OR oracle, Alphabet alphabet); - @Test + @Test(expectedExceptions = GrowingAlphabetNotSupportedException.class) public void testInitialAlphabet() { - testAlphabet(initialAlphabet); + final L leaner = getLearner(oracle, initialAlphabet); + + testAlphabet(initialAlphabet, leaner, Collections.singletonList(leaner::addAlphabetSymbol)); } /** - * In case of passing a growing alphabet, the learners may use the existing - * {@link net.automatalib.words.GrowingAlphabet#addSymbol(Object)} functionality. Due to references, this may alter - * their behavior. Check it! + * In case of passing a growing alphabet, the learners may use the existing {@link + * net.automatalib.words.GrowingAlphabet#addSymbol(Object)} functionality. Due to references, this may alter their + * behavior. Check it! */ @Test - public void testGrowingAlphabetAlphabet() { - testAlphabet(new SimpleAlphabet<>(initialAlphabet)); + public void testGrowingAlphabet() { + final GrowingAlphabet alphabet = new SimpleAlphabet<>(initialAlphabet); + final L leaner = getLearner(oracle, alphabet); + + testAlphabet(alphabet, leaner, Collections.singletonList(leaner::addAlphabetSymbol)); + } + + @Test + public void testGrowingAlphabetWithCache() { + final GrowingAlphabet alphabet = new SimpleAlphabet<>(initialAlphabet); + final List> symbolListener = new ArrayList<>(); + final OR cachedOracle = getCachedOracle(alphabet, oracle, symbolListener); + final L learner = getLearner(cachedOracle, alphabet); + symbolListener.add(learner::addAlphabetSymbol); + + testAlphabet(alphabet, learner, symbolListener); } - private void testAlphabet(Alphabet alphabet) { - final L learner = getLearner(oracle, alphabet); + private void testAlphabet(Alphabet alphabet, L learner, List> symbolListener) { + + // add the first symbol before actually starting the learning process + symbolListener.forEach(c -> c.accept(alphabetExtensions.get(0))); learner.startLearning(); this.performLearnLoopAndCheck(learner, alphabet); @@ -99,9 +125,17 @@ private void testAlphabet(Alphabet alphabet) { final List currentAlphabet = new ArrayList<>(alphabet.size() + alphabetExtensions.size()); currentAlphabet.addAll(alphabet); + boolean duplicateAdd = false; + for (final I i : alphabetExtensions) { currentAlphabet.add(i); - learner.addAlphabetSymbol(i); + symbolListener.forEach(c -> c.accept(i)); + + if (duplicateAdd) { + learner.addAlphabetSymbol(i); + } + // add every second symbol twice + duplicateAdd = !duplicateAdd; final UniversalDeterministicAutomaton hyp = learner.getHypothesisModel(); @@ -129,7 +163,8 @@ private void performLearnLoopAndCheck(final L learner, final Collection void checkCompletenessOfHypothesis(final UniversalDeterministicAutomaton hypothesis, final Collection alphabet) { + private void checkCompletenessOfHypothesis(final UniversalDeterministicAutomaton hypothesis, + final Collection alphabet) { for (final S s : hypothesis.getStates()) { for (final I i : alphabet) { final T trans = hypothesis.getTransition(s, i); From bcd9d4d23f5c5db897dff5d1e42a63d891ede1e9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 19 Jan 2019 23:10:43 +0100 Subject: [PATCH 113/125] refactor SupportsGrowingAlphabet Use the AutomataLib version to reduce redundancy. --- .../algorithms/adt/learner/ADTLearner.java | 2 +- .../algorithms/dhc/mealy/MealyDHC.java | 5 ++-- .../discriminationtree/AbstractDTLearner.java | 2 +- .../hypothesis/DTLearnerHypothesis.java | 4 +-- .../algorithms/kv/dfa/KearnsVaziraniDFA.java | 2 +- .../kv/mealy/KearnsVaziraniMealy.java | 2 +- .../lstar/AbstractAutomatonLStar.java | 4 +-- .../AbstractExtensibleAutomatonLStar.java | 4 +-- .../algorithms/lstar/AbstractLStar.java | 2 +- .../ttt/base/AbstractTTTHypothesis.java | 4 +-- .../ttt/base/AbstractTTTLearner.java | 2 +- .../feature/SupportsGrowingAlphabet.java | 27 ------------------- .../filter/cache/dfa/DFACacheOracle.java | 2 +- .../filter/cache/mealy/MealyCacheOracle.java | 2 +- .../AbstractGrowingAlphabetDFATest.java | 2 +- .../AbstractGrowingAlphabetMealyTest.java | 2 +- .../AbstractGrowingAlphabetTest.java | 2 +- 17 files changed, 22 insertions(+), 48 deletions(-) delete mode 100644 api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java index 4b65b8ab0b..cba8d1b12a 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java @@ -54,11 +54,11 @@ import de.learnlib.algorithms.adt.util.SQOOTBridge; 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.SymbolQueryOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.counterexamples.LocalSuffixFinders; import de.learnlib.util.MQUtil; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; import net.automatalib.exception.GrowingAlphabetNotSupportedException; diff --git a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java index dc08df94c3..1bd0ede11e 100644 --- a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java +++ b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java @@ -35,11 +35,11 @@ import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; import de.learnlib.api.algorithm.feature.GlobalSuffixLearner.GlobalSuffixLearnerMealy; 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.counterexamples.GlobalSuffixFinder; import de.learnlib.counterexamples.GlobalSuffixFinders; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.transducers.impl.compact.CompactMealy; import net.automatalib.commons.util.mappings.MapMapping; import net.automatalib.commons.util.mappings.MutableMapping; @@ -258,7 +258,8 @@ public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedExcept if (!this.splitters.contains(Word.fromLetter(symbol))) { final Iterator> splitterIterator = this.splitters.iterator(); - final LinkedHashSet> newSplitters = Sets.newLinkedHashSetWithExpectedSize(this.splitters.size() + 1); + final LinkedHashSet> newSplitters = + Sets.newLinkedHashSetWithExpectedSize(this.splitters.size() + 1); // see initial initialization of the splitters for (int i = 0; i < this.alphabet.size() - 1; i++) { 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 bf47fc9338..02e4cf03f8 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 @@ -25,7 +25,6 @@ import de.learnlib.algorithms.discriminationtree.hypothesis.HTransition; 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,6 +33,7 @@ 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; 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 c954adaaca..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 @@ -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,7 +52,7 @@ public class DTLearnerHypothesis implements UniversalDeterministicAutomaton, I, HTransition, SP, TP>, AccessSequenceTransformer, StateIDs>, - GrowableAlphabetAutomaton, + SupportsGrowingAlphabet, Serializable { private final Alphabet alphabet; diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java index c2dacdbb38..9285114fd3 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java @@ -29,12 +29,12 @@ import de.learnlib.algorithms.kv.StateInfo; import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; 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.datastructure.discriminationtree.BinaryDTree; import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; import de.learnlib.datastructure.discriminationtree.model.LCAInfo; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.fsa.impl.compact.CompactDFA; import net.automatalib.commons.smartcollections.ArrayStorage; diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java index 9175696f07..064cb2ba2b 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java @@ -30,13 +30,13 @@ import de.learnlib.algorithms.kv.StateInfo; import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; 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.datastructure.discriminationtree.MultiDTree; import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; import de.learnlib.datastructure.discriminationtree.model.LCAInfo; import de.learnlib.util.mealy.MealyUtil; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.automata.transducers.impl.compact.CompactMealy; import net.automatalib.exception.GrowingAlphabetNotSupportedException; diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java index 1a41056663..2604729519 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java @@ -25,7 +25,7 @@ import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.observationtable.ObservationTable; import de.learnlib.datastructure.observationtable.Row; -import net.automatalib.automata.GrowableAlphabetAutomaton; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.MutableDeterministic; import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; @@ -49,7 +49,7 @@ * * @author Malte Isberner */ -public abstract class AbstractAutomatonLStar & GrowableAlphabetAutomaton> +public abstract class AbstractAutomatonLStar & SupportsGrowingAlphabet> extends AbstractLStar implements ResumableLearner> { protected AI internalHyp; diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java index 8944a9f1e0..b07133dd9f 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java @@ -25,12 +25,12 @@ import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.observationtable.Row; -import net.automatalib.automata.GrowableAlphabetAutomaton; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.MutableDeterministic; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -public abstract class AbstractExtensibleAutomatonLStar & GrowableAlphabetAutomaton> +public abstract class AbstractExtensibleAutomatonLStar & SupportsGrowingAlphabet> extends AbstractAutomatonLStar { protected final ObservationTableCEXHandler cexHandler; diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java index e3883caa6d..741611b155 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java @@ -23,7 +23,6 @@ import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; import de.learnlib.api.algorithm.feature.GlobalSuffixLearner; -import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.observationtable.GenericObservationTable; @@ -32,6 +31,7 @@ import de.learnlib.datastructure.observationtable.ObservationTable; import de.learnlib.datastructure.observationtable.Row; 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; diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java index 29a27eb7ab..df7a5173b8 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java @@ -22,9 +22,9 @@ import java.util.List; import java.util.Map; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.DeterministicAutomaton; import net.automatalib.automata.FiniteAlphabetAutomaton; -import net.automatalib.automata.GrowableAlphabetAutomaton; import net.automatalib.automata.fsa.DFA; import net.automatalib.graphs.Graph; import net.automatalib.visualization.DefaultVisualizationHelper; @@ -44,7 +44,7 @@ public abstract class AbstractTTTHypothesis implements DeterministicAutomaton, I, T>, FiniteAlphabetAutomaton, I, T>, DeterministicAutomaton.FullIntAbstraction, - GrowableAlphabetAutomaton, + SupportsGrowingAlphabet, Serializable { protected final List> states = new ArrayList<>(); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java index 60788ab355..6ffb989cbc 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java @@ -36,11 +36,11 @@ import de.learnlib.api.AccessSequenceProvider; 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.counterexamples.acex.OutInconsPrefixTransformAcex; import de.learnlib.datastructure.discriminationtree.SplitData; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.fsa.DFA; import net.automatalib.commons.smartcollections.ElementReference; import net.automatalib.commons.smartcollections.UnorderedCollection; diff --git a/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java b/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java deleted file mode 100644 index d42dfcc50c..0000000000 --- a/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java +++ /dev/null @@ -1,27 +0,0 @@ -/* 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"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.api.algorithm.feature; - -import net.automatalib.exception.GrowingAlphabetNotSupportedException; - -/** - * @author Maik Merten - */ -public interface SupportsGrowingAlphabet { - - void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException; - -} diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java index 871ed8f2a4..49a88de855 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheOracle.java @@ -23,10 +23,10 @@ import javax.annotation.ParametersAreNonnullByDefault; -import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.filter.cache.LearningCacheOracle.DFALearningCacheOracle; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.incremental.dfa.Acceptance; import net.automatalib.incremental.dfa.IncrementalDFABuilder; diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java index 2aea38c81c..90e0486dc2 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheOracle.java @@ -24,10 +24,10 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.commons.util.comparison.CmpUtil; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.exception.GrowingAlphabetNotSupportedException; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java index 2fc87af6fc..8577a47af7 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetDFATest.java @@ -21,11 +21,11 @@ import java.util.function.Consumer; import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.QueryAnswerer; import de.learnlib.filter.cache.dfa.DFACacheOracle; import de.learnlib.filter.cache.dfa.DFACaches; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.fsa.DFA; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java index ca86ecb897..99cc7e6e00 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMealyTest.java @@ -21,11 +21,11 @@ import java.util.function.Consumer; import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.QueryAnswerer; import de.learnlib.filter.cache.mealy.MealyCacheOracle; import de.learnlib.filter.cache.mealy.MealyCaches; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java index 41e88a9453..0a1e81a114 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetTest.java @@ -22,8 +22,8 @@ import java.util.function.Consumer; import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.query.DefaultQuery; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.Output; import net.automatalib.exception.GrowingAlphabetNotSupportedException; From cf3b46ccdbbef19b1057b0089245aee22f8048be Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sun, 20 Jan 2019 00:28:01 +0100 Subject: [PATCH 114/125] travis: switch to new xenial container --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 64fed94e00..60f6904163 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: java -sudo: false -dist: trusty +dist: xenial cache: directories: From 73cd47c0ff88f6614212292fe59c0f04ea1b8dba Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 24 Jan 2019 14:42:37 +0100 Subject: [PATCH 115/125] add SupportsGrowingAlphabet interface to SULCache --- .../de/learnlib/filter/cache/sul/SULCache.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCache.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCache.java index c851049b56..0415bf8258 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCache.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCache.java @@ -28,6 +28,8 @@ import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; import de.learnlib.filter.cache.mealy.MealyCacheConsistencyTest; import de.learnlib.oracle.membership.SULOracle; +import net.automatalib.SupportsGrowingAlphabet; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.incremental.mealy.IncrementalMealyBuilder; import net.automatalib.incremental.mealy.dag.IncrementalMealyDAGBuilder; import net.automatalib.incremental.mealy.tree.IncrementalMealyTreeBuilder; @@ -54,7 +56,7 @@ * @author Malte Isberner */ @ParametersAreNonnullByDefault -public class SULCache implements SUL, MealyLearningCacheOracle { +public class SULCache implements SUL, MealyLearningCacheOracle, SupportsGrowingAlphabet { private final SULCacheImpl impl; @@ -99,6 +101,11 @@ public void processQueries(Collection>> queries) { SULOracle.processQueries(impl, queries); } + @Override + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + impl.addAlphabetSymbol(symbol); + } + /** * Implementation class; we need this to bind the {@code T} and {@code S} type parameters of the transition system * returned by {@link IncrementalMealyBuilder#asTransitionSystem()}. @@ -115,7 +122,8 @@ public void processQueries(Collection>> queries) { * @author Malte Isberner */ @ParametersAreNonnullByDefault - private static final class SULCacheImpl implements SUL, MealyLearningCache { + private static final class SULCacheImpl + implements SUL, MealyLearningCache, SupportsGrowingAlphabet { private final IncrementalMealyBuilder incMealy; private final MealyTransitionSystem mealyTs; @@ -208,6 +216,11 @@ public void post() { public MealyCacheConsistencyTest createCacheConsistencyTest() { return new MealyCacheConsistencyTest<>(incMealy, incMealyLock); } + + @Override + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + incMealy.addAlphabetSymbol(symbol); + } } } From 1f3e66a96251b07931415fdbc436a66c690c37f0 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 29 Jan 2019 20:47:20 +0100 Subject: [PATCH 116/125] refactor ObservationTable hierarchy No longer let the PartialObservationTable inherit from the GenericObservationTable, because the partial one is in fact NOT a generic one (thus previously breaking the Liskov substitution principle). Rather extract the shared functionality to an common super class and have both implementations exist side-by-side. --- .../algorithms/lstar/AbstractLStar.java | 3 +- .../algorithms/lstar/AbstractLStarState.java | 8 +- .../algorithms/lstar/AutomatonLStarState.java | 4 +- .../learnlib-pmd-exclusions.properties | 2 +- .../AbstractObservationTable.java | 432 ++++++++++++++++++ .../GenericObservationTable.java | 403 +--------------- .../observationtable/Inconsistency.java | 2 +- .../PartialObservationTable.java | 21 +- 8 files changed, 470 insertions(+), 405 deletions(-) create mode 100644 datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/AbstractObservationTable.java diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java index 741611b155..6ed094f1b7 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStar.java @@ -25,6 +25,7 @@ import de.learnlib.api.algorithm.feature.GlobalSuffixLearner; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; +import de.learnlib.datastructure.observationtable.AbstractObservationTable; import de.learnlib.datastructure.observationtable.GenericObservationTable; import de.learnlib.datastructure.observationtable.Inconsistency; import de.learnlib.datastructure.observationtable.OTLearner; @@ -59,7 +60,7 @@ public abstract class AbstractLStar protected final Alphabet alphabet; protected final MembershipOracle oracle; - protected GenericObservationTable table; + protected AbstractObservationTable table; /** * Constructor. diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStarState.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStarState.java index 09419bc5a2..0370eaa739 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStarState.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStarState.java @@ -17,7 +17,7 @@ import java.io.Serializable; -import de.learnlib.datastructure.observationtable.GenericObservationTable; +import de.learnlib.datastructure.observationtable.AbstractObservationTable; /** * Class that contains all data that represent the internal state of the {@link AbstractLStar} learner. @@ -31,13 +31,13 @@ */ public abstract class AbstractLStarState implements Serializable { - private final GenericObservationTable observationTable; + private final AbstractObservationTable observationTable; - AbstractLStarState(final GenericObservationTable observationTable) { + AbstractLStarState(final AbstractObservationTable observationTable) { this.observationTable = observationTable; } - GenericObservationTable getObservationTable() { + AbstractObservationTable getObservationTable() { return observationTable; } } diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AutomatonLStarState.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AutomatonLStarState.java index 73968a02de..3548e99086 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AutomatonLStarState.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AutomatonLStarState.java @@ -18,7 +18,7 @@ import java.util.List; import de.learnlib.algorithms.lstar.AbstractAutomatonLStar.StateInfo; -import de.learnlib.datastructure.observationtable.GenericObservationTable; +import de.learnlib.datastructure.observationtable.AbstractObservationTable; /** * Class that contains all data that represent the internal state of the {@link AbstractAutomatonLStar} learner and its @@ -40,7 +40,7 @@ public class AutomatonLStarState extends AbstractLStarState { private final AI hypothesis; private final List> stateInfos; - AutomatonLStarState(final GenericObservationTable observationTable, + AutomatonLStarState(final AbstractObservationTable observationTable, final AI hypothesis, final List> stateInfos) { super(observationTable); diff --git a/build-tools/src/main/resources/learnlib-pmd-exclusions.properties b/build-tools/src/main/resources/learnlib-pmd-exclusions.properties index e659ae09e9..9767af8530 100644 --- a/build-tools/src/main/resources/learnlib-pmd-exclusions.properties +++ b/build-tools/src/main/resources/learnlib-pmd-exclusions.properties @@ -34,7 +34,7 @@ de.learnlib.algorithms.ttt.base.AbstractTTTLearner=EmptyCatchBlock,ExcessiveClas de.learnlib.api.logging.Slf4jDelegator=LoggerIsNotStaticFinal,MoreThanOneLogger # we want to store the size of the list before changing it -de.learnlib.datastructure.observationtable.GenericObservationTable=PrematureDeclaration +de.learnlib.datastructure.observationtable.AbstractObservationTable=PrematureDeclaration # RuntimeExceptions are the type of exceptions we allow to handle, therefore we should throw them de.learnlib.drivers.reflect.ConcreteMethodInput=AvoidThrowingRawExceptionTypes,PreserveStackTrace diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/AbstractObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/AbstractObservationTable.java new file mode 100644 index 0000000000..46402f2634 --- /dev/null +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/AbstractObservationTable.java @@ -0,0 +1,432 @@ +/* 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"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.datastructure.observationtable; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nonnull; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * Observation table class. + *

    + * An observation table (OT) is the central data structure used by Angluin's L* algorithm, as described in the paper + * "Learning Regular Sets from Queries and Counterexamples". + *

    + * An observation table is a two-dimensional table, with rows indexed by prefixes, and columns indexed by suffixes. For + * a prefix u and a suffix v, the respective cell contains the result of the membership query + * (u, v). + *

    + * The set of prefixes (row labels) is divided into two disjoint sets: short and long prefixes. Each long prefix is a + * one-letter extension of a short prefix; conversely, every time a prefix is added to the set of short prefixes, all + * possible one-letter extensions are added to the set of long prefixes. + *

    + * In order to derive a well-defined hypothesis from an observation table, it must satisfy two properties: closedness + * and consistency.

    • An observation table is closed iff for each long prefix u there exists + * a short prefix u' such that the row contents for both prefixes are equal.
    • An observation table is + * consistent iff for every two short prefixes u and u' with identical row contents, it + * holds that for every input symbol a the rows indexed by ua and u'a also have + * identical contents.
    + * + * @param + * input symbol type + * @param + * output domain type + * + * @author Malte Isberner + */ +public abstract class AbstractObservationTable implements MutableObservationTable, Serializable { + + private static final Integer NO_ENTRY = null; // TODO: replace with primitive specialization + protected final List> shortPrefixRows = new ArrayList<>(); + // private static final int NO_ENTRY = -1; + private final List> longPrefixRows = new ArrayList<>(); + private final List> allRows = new ArrayList<>(); + private final List> allRowContents = new ArrayList<>(); + private final List> canonicalRows = new ArrayList<>(); + // private final TObjectIntMap> rowContentIds = new TObjectIntHashMap<>(10, 0.75f, NO_ENTRY); + private final Map, Integer> rowContentIds = new HashMap<>(); // TODO: replace with primitive specialization + private final Map, RowImpl> rowMap = new HashMap<>(); + private final List> suffixes = new ArrayList<>(); + private final Set> suffixSet = new HashSet<>(); + private transient Alphabet alphabet; + private int numRows; + protected boolean initialConsistencyCheckRequired; + + /** + * Constructor. + * + * @param alphabet + * the learning alphabet. + */ + public AbstractObservationTable(Alphabet alphabet) { + this.alphabet = alphabet; + } + + protected static void buildQueries(List> queryList, + Word prefix, + List> suffixes) { + for (Word suffix : suffixes) { + queryList.add(new DefaultQuery<>(prefix, suffix)); + } + } + + protected void checkInitialShortPrefixes(List> initialShortPrefixes) { + if (!allRows.isEmpty()) { + throw new IllegalStateException("Called initialize, but there are already rows present"); + } + + if (!checkPrefixClosed(initialShortPrefixes)) { + throw new IllegalArgumentException("Initial short prefixes are not prefix-closed"); + } + + if (!initialShortPrefixes.get(0).isEmpty()) { + throw new IllegalArgumentException("First initial short prefix MUST be the empty word!"); + } + } + + protected List> initializeSuffixes(List> initialSuffixes) { + if (!suffixSet.isEmpty() || !suffixes.isEmpty()) { + throw new IllegalStateException("Trying to initialize suffixes, but there are already suffixes present"); + } + + for (Word suffix : initialSuffixes) { + if (suffixSet.add(suffix)) { + suffixes.add(suffix); + } + } + + return suffixes; + } + + private static boolean checkPrefixClosed(Collection> initialShortPrefixes) { + Set> prefixes = new HashSet<>(initialShortPrefixes); + + for (Word pref : initialShortPrefixes) { + if (!pref.isEmpty()) { + if (!prefixes.contains(pref.prefix(-1))) { + return false; + } + } + } + + return true; + } + + protected RowImpl createSpRow(Word prefix) { + RowImpl newRow = new RowImpl<>(prefix, numRows++, alphabet.size()); + allRows.add(newRow); + rowMap.put(prefix, newRow); + shortPrefixRows.add(newRow); + return newRow; + } + + protected RowImpl createLpRow(Word prefix) { + RowImpl newRow = new RowImpl<>(prefix, numRows++); + allRows.add(newRow); + rowMap.put(prefix, newRow); + int idx = longPrefixRows.size(); + longPrefixRows.add(newRow); + newRow.setLpIndex(idx); + return newRow; + } + + /** + * Fetches the given number of query responses and adds them to the specified output list. Also, the query iterator + * is advanced accordingly. + * + * @param queryIt + * the query iterator + * @param output + * the output list to write to + * @param numSuffixes + * the number of suffixes (queries) + */ + protected static void fetchResults(Iterator> queryIt, List output, int numSuffixes) { + for (int j = 0; j < numSuffixes; j++) { + DefaultQuery qry = queryIt.next(); + output.add(qry.getOutput()); + } + } + + protected boolean processContents(RowImpl row, List rowContents, boolean makeCanonical) { + Integer contentId; // TODO: replace with primitive specialization + // int contentId; + boolean added = false; + contentId = rowContentIds.get(rowContents); + if (contentId == NO_ENTRY) { + contentId = numberOfDistinctRows(); + rowContentIds.put(rowContents, contentId); + allRowContents.add(rowContents); + added = true; + if (makeCanonical) { + canonicalRows.add(row); + } else { + canonicalRows.add(null); + } + } + row.setRowContentId(contentId); + return added; + } + + @Override + public int numberOfDistinctRows() { + return allRowContents.size(); + } + + @Override + public List>> addSuffix(Word suffix, MembershipOracle oracle) { + return addSuffixes(Collections.singletonList(suffix), oracle); + } + + @Override + public List>> addSuffixes(Collection> newSuffixes, MembershipOracle oracle) { + int oldSuffixCount = suffixes.size(); + // we need a stable iteration order, and only List guarantees this + List> newSuffixList = new ArrayList<>(); + for (Word suffix : newSuffixes) { + if (suffixSet.add(suffix)) { + newSuffixList.add(suffix); + } + } + + if (newSuffixList.isEmpty()) { + return Collections.emptyList(); + } + + int numNewSuffixes = newSuffixList.size(); + + int numSpRows = shortPrefixRows.size(); + int rowCount = numSpRows + longPrefixRows.size(); + + List> queries = new ArrayList<>(rowCount * numNewSuffixes); + + for (RowImpl row : shortPrefixRows) { + buildQueries(queries, row.getLabel(), newSuffixList); + } + + for (RowImpl row : longPrefixRows) { + buildQueries(queries, row.getLabel(), newSuffixList); + } + + oracle.processQueries(queries); + + Iterator> queryIt = queries.iterator(); + + for (RowImpl row : shortPrefixRows) { + List rowContents = allRowContents.get(row.getRowContentId()); + if (rowContents.size() == oldSuffixCount) { + rowContentIds.remove(rowContents); + fetchResults(queryIt, rowContents, numNewSuffixes); + rowContentIds.put(rowContents, row.getRowContentId()); + } else { + List newContents = new ArrayList<>(oldSuffixCount + numNewSuffixes); + newContents.addAll(rowContents.subList(0, oldSuffixCount)); + fetchResults(queryIt, newContents, numNewSuffixes); + processContents(row, newContents, true); + } + } + + List>> unclosed = new ArrayList<>(); + numSpRows = numberOfDistinctRows(); + + for (RowImpl row : longPrefixRows) { + List rowContents = allRowContents.get(row.getRowContentId()); + if (rowContents.size() == oldSuffixCount) { + rowContentIds.remove(rowContents); + fetchResults(queryIt, rowContents, numNewSuffixes); + rowContentIds.put(rowContents, row.getRowContentId()); + } else { + List newContents = new ArrayList<>(oldSuffixCount + numNewSuffixes); + newContents.addAll(rowContents.subList(0, oldSuffixCount)); + fetchResults(queryIt, newContents, numNewSuffixes); + if (processContents(row, newContents, false)) { + unclosed.add(new ArrayList<>()); + } + + int id = row.getRowContentId(); + if (id >= numSpRows) { + unclosed.get(id - numSpRows).add(row); + } + } + } + + this.suffixes.addAll(newSuffixList); + + return unclosed; + } + + @Override + public boolean isInitialConsistencyCheckRequired() { + return initialConsistencyCheckRequired; + } + + @Override + public List>> addShortPrefixes(List> shortPrefixes, MembershipOracle oracle) { + List> toSpRows = new ArrayList<>(); + + for (Word sp : shortPrefixes) { + RowImpl row = rowMap.get(sp); + if (row != null) { + if (row.isShortPrefixRow()) { + continue; + } + } else { + row = createSpRow(sp); + } + toSpRows.add(row); + } + + return toShortPrefixes(toSpRows, oracle); + } + + protected void makeShort(RowImpl row) { + if (row.isShortPrefixRow()) { + return; + } + + int lastIdx = longPrefixRows.size() - 1; + RowImpl last = longPrefixRows.get(lastIdx); + int rowIdx = row.getLpIndex(); + longPrefixRows.remove(lastIdx); + if (last != row) { + longPrefixRows.set(rowIdx, last); + last.setLpIndex(rowIdx); + } + + shortPrefixRows.add(row); + row.makeShort(alphabet.size()); + + if (row.hasContents()) { + int cid = row.getRowContentId(); + if (canonicalRows.get(cid) == null) { + canonicalRows.set(cid, row); + } + } + } + + protected static void buildRowQueries(List> queryList, + List> rows, + List> suffixes) { + for (Row row : rows) { + buildQueries(queryList, row.getLabel(), suffixes); + } + } + + @Override + public List rowContents(Row row) { + return allRowContents.get(row.getRowContentId()); + } + + @Override + public RowImpl getRow(int rowId) { + return allRows.get(rowId); + } + + @Override + public RowImpl getRow(Word prefix) { + return rowMap.get(prefix); + } + + @Override + public int numberOfRows() { + return shortPrefixRows.size() + longPrefixRows.size(); + } + + @Override + public List> getSuffixes() { + return suffixes; + } + + @Override + public boolean isInitialized() { + return !allRows.isEmpty(); + } + + @Override + public Alphabet getInputAlphabet() { + return alphabet; + } + + /** + * This is an internal method used for de-serializing. Do not deliberately set input alphabets. + * + * @param alphabet + * the input alphabet corresponding to the previously serialized one. + */ + public void setInputAlphabet(Alphabet alphabet) { + this.alphabet = alphabet; + } + + @Override + public Word transformAccessSequence(Word word) { + Row current = shortPrefixRows.get(0); + + for (I sym : word) { + current = getRowSuccessor(current, sym); + current = canonicalRows.get(current.getRowContentId()); + } + + return current.getLabel(); + } + + @Override + public boolean isAccessSequence(Word word) { + Row current = shortPrefixRows.get(0); + + for (I sym : word) { + current = getRowSuccessor(current, sym); + if (!isCanonical(current)) { + return false; + } + } + + return true; + } + + private boolean isCanonical(Row row) { + if (!row.isShortPrefixRow()) { + return false; + } + int contentId = row.getRowContentId(); + return (canonicalRows.get(contentId) == row); + } + + @Nonnull + @Override + public List> getShortPrefixRows() { + return Collections.unmodifiableList(shortPrefixRows); + } + + @Nonnull + @Override + public Collection> getLongPrefixRows() { + return Collections.unmodifiableList(longPrefixRows); + } +} diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java index a0e845ac02..1f76d20af1 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/GenericObservationTable.java @@ -15,18 +15,10 @@ */ package de.learnlib.datastructure.observationtable; -import java.io.Serializable; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.Nonnull; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; @@ -35,52 +27,16 @@ import net.automatalib.words.impl.Alphabets; /** - * Observation table class. - *

    - * An observation table (OT) is the central data structure used by Angluin's L* algorithm, as described in the paper - * "Learning Regular Sets from Queries and Counterexamples". - *

    - * An observation table is a two-dimensional table, with rows indexed by prefixes, and columns indexed by suffixes. For - * a prefix u and a suffix v, the respective cell contains the result of the membership query - * (u, v). - *

    - * The set of prefixes (row labels) is divided into two disjoint sets: short and long prefixes. Each long prefix is a - * one-letter extension of a short prefix; conversely, every time a prefix is added to the set of short prefixes, all - * possible one-letter extensions are added to the set of long prefixes. - *

    - * In order to derive a well-defined hypothesis from an observation table, it must satisfy two properties: closedness - * and consistency.

    • An observation table is closed iff for each long prefix u there exists - * a short prefix u' such that the row contents for both prefixes are equal.
    • An observation table is - * consistent iff for every two short prefixes u and u' with identical row contents, - * it - * holds that for every input symbol a the rows indexed by ua and u'a also have - * identical contents.
    + * A generic observation table, that implements the classical OT semantics for fully specified systems. * * @param * input symbol type * @param * output domain type - * - * @author Malte Isberner */ -public class GenericObservationTable implements MutableObservationTable, Serializable { - - private static final Integer NO_ENTRY = null; // TODO: replace with primitive specialization - protected final List> shortPrefixRows = new ArrayList<>(); - // private static final int NO_ENTRY = -1; - private final List> longPrefixRows = new ArrayList<>(); - private final List> allRows = new ArrayList<>(); - private final List> allRowContents = new ArrayList<>(); - private final List> canonicalRows = new ArrayList<>(); - // private final TObjectIntMap> rowContentIds = new TObjectIntHashMap<>(10, 0.75f, NO_ENTRY); - private final Map, Integer> rowContentIds = new HashMap<>(); // TODO: replace with primitive specialization - protected final Map, RowImpl> rowMap = new HashMap<>(); - protected final List> suffixes = new ArrayList<>(); - protected final Set> suffixSet = new HashSet<>(); - private transient Alphabet alphabet; +public final class GenericObservationTable extends AbstractObservationTable { + private transient int alphabetSize; - private int numRows; - protected boolean initialConsistencyCheckRequired; /** * Constructor. @@ -89,31 +45,20 @@ public class GenericObservationTable implements MutableObservationTable alphabet) { - this.alphabet = alphabet; + super(alphabet); this.alphabetSize = alphabet.size(); } - protected static void buildQueries(List> queryList, - Word prefix, - List> suffixes) { - for (Word suffix : suffixes) { - queryList.add(new DefaultQuery<>(prefix, suffix)); - } - } - @Override public List>> initialize(List> initialShortPrefixes, List> initialSuffixes, MembershipOracle oracle) { - checkInitialization(initialShortPrefixes, initialSuffixes); + checkInitialShortPrefixes(initialShortPrefixes); - for (Word suffix : initialSuffixes) { - if (suffixSet.add(suffix)) { - suffixes.add(suffix); - } - } + final List> suffixes = initializeSuffixes(initialSuffixes); + final Alphabet alphabet = getInputAlphabet(); int numPrefixes = alphabet.size() * initialShortPrefixes.size() + 1; int numSuffixes = suffixes.size(); @@ -131,7 +76,7 @@ public List>> initialize(List> initialShortPrefixes, for (int i = 0; i < alphabet.size(); i++) { I sym = alphabet.getSymbol(i); Word lp = sp.append(sym); - RowImpl succRow = rowMap.get(lp); + RowImpl succRow = getRow(lp); if (succRow == null) { succRow = createLpRow(lp); buildQueries(queries, lp, suffixes); @@ -179,208 +124,14 @@ public List>> initialize(List> initialShortPrefixes, return unclosed; } - protected void checkInitialization(List> initialShortPrefixes, List> initialSuffixes) { - if (!allRows.isEmpty()) { - throw new IllegalStateException("Called initialize, but there are already rows present"); - } - - if (!checkPrefixClosed(initialShortPrefixes)) { - throw new IllegalArgumentException("Initial short prefixes are not prefix-closed"); - } - - if (!initialShortPrefixes.get(0).isEmpty()) { - throw new IllegalArgumentException("First initial short prefix MUST be the empty word!"); - } - } - - private static boolean checkPrefixClosed(Collection> initialShortPrefixes) { - Set> prefixes = new HashSet<>(initialShortPrefixes); - - for (Word pref : initialShortPrefixes) { - if (!pref.isEmpty()) { - if (!prefixes.contains(pref.prefix(-1))) { - return false; - } - } - } - - return true; - } - - protected RowImpl createSpRow(Word prefix) { - RowImpl newRow = new RowImpl<>(prefix, numRows++, alphabet.size()); - allRows.add(newRow); - rowMap.put(prefix, newRow); - shortPrefixRows.add(newRow); - return newRow; - } - - protected RowImpl createLpRow(Word prefix) { - RowImpl newRow = new RowImpl<>(prefix, numRows++); - allRows.add(newRow); - rowMap.put(prefix, newRow); - int idx = longPrefixRows.size(); - longPrefixRows.add(newRow); - newRow.setLpIndex(idx); - return newRow; - } - - /** - * Fetches the given number of query responses and adds them to the specified output list. Also, the query iterator - * is advanced accordingly. - * - * @param queryIt - * the query iterator - * @param output - * the output list to write to - * @param numSuffixes - * the number of suffixes (queries) - */ - protected static void fetchResults(Iterator> queryIt, List output, int numSuffixes) { - for (int j = 0; j < numSuffixes; j++) { - DefaultQuery qry = queryIt.next(); - output.add(qry.getOutput()); - } - } - - protected boolean processContents(RowImpl row, List rowContents, boolean makeCanonical) { - Integer contentId; // TODO: replace with primitive specialization - // int contentId; - boolean added = false; - contentId = rowContentIds.get(rowContents); - if (contentId == NO_ENTRY) { - contentId = numberOfDistinctRows(); - rowContentIds.put(rowContents, contentId); - allRowContents.add(rowContents); - added = true; - if (makeCanonical) { - canonicalRows.add(row); - } else { - canonicalRows.add(null); - } - } - row.setRowContentId(contentId); - return added; - } - - @Override - public int numberOfDistinctRows() { - return allRowContents.size(); - } - - @Override - public List>> addSuffix(Word suffix, MembershipOracle oracle) { - return addSuffixes(Collections.singletonList(suffix), oracle); - } - - @Override - public List>> addSuffixes(Collection> newSuffixes, MembershipOracle oracle) { - int oldSuffixCount = suffixes.size(); - // we need a stable iteration order, and only List guarantees this - List> newSuffixList = new ArrayList<>(); - for (Word suffix : newSuffixes) { - if (suffixSet.add(suffix)) { - newSuffixList.add(suffix); - } - } - - if (newSuffixList.isEmpty()) { - return Collections.emptyList(); - } - - int numNewSuffixes = newSuffixList.size(); - - int numSpRows = shortPrefixRows.size(); - int rowCount = numSpRows + longPrefixRows.size(); - - List> queries = new ArrayList<>(rowCount * numNewSuffixes); - - for (RowImpl row : shortPrefixRows) { - buildQueries(queries, row.getLabel(), newSuffixList); - } - - for (RowImpl row : longPrefixRows) { - buildQueries(queries, row.getLabel(), newSuffixList); - } - - oracle.processQueries(queries); - - Iterator> queryIt = queries.iterator(); - - for (RowImpl row : shortPrefixRows) { - List rowContents = allRowContents.get(row.getRowContentId()); - if (rowContents.size() == oldSuffixCount) { - rowContentIds.remove(rowContents); - fetchResults(queryIt, rowContents, numNewSuffixes); - rowContentIds.put(rowContents, row.getRowContentId()); - } else { - List newContents = new ArrayList<>(oldSuffixCount + numNewSuffixes); - newContents.addAll(rowContents.subList(0, oldSuffixCount)); - fetchResults(queryIt, newContents, numNewSuffixes); - processContents(row, newContents, true); - } - } - - List>> unclosed = new ArrayList<>(); - numSpRows = numberOfDistinctRows(); - - for (RowImpl row : longPrefixRows) { - List rowContents = allRowContents.get(row.getRowContentId()); - if (rowContents.size() == oldSuffixCount) { - rowContentIds.remove(rowContents); - fetchResults(queryIt, rowContents, numNewSuffixes); - rowContentIds.put(rowContents, row.getRowContentId()); - } else { - List newContents = new ArrayList<>(oldSuffixCount + numNewSuffixes); - newContents.addAll(rowContents.subList(0, oldSuffixCount)); - fetchResults(queryIt, newContents, numNewSuffixes); - if (processContents(row, newContents, false)) { - unclosed.add(new ArrayList<>()); - } - - int id = row.getRowContentId(); - if (id >= numSpRows) { - unclosed.get(id - numSpRows).add(row); - } - } - } - - this.suffixes.addAll(newSuffixList); - - return unclosed; - } - - @Override - public boolean isInitialConsistencyCheckRequired() { - return initialConsistencyCheckRequired; - } - - @Override - public List>> addShortPrefixes(List> shortPrefixes, MembershipOracle oracle) { - List> toSpRows = new ArrayList<>(); - - for (Word sp : shortPrefixes) { - RowImpl row = rowMap.get(sp); - if (row != null) { - if (row.isShortPrefixRow()) { - continue; - } - } else { - row = createSpRow(sp); - } - toSpRows.add(row); - } - - return toShortPrefixes(toSpRows, oracle); - } - @Override public List>> toShortPrefixes(List> lpRows, MembershipOracle oracle) { List> freshSpRows = new ArrayList<>(); List> freshLpRows = new ArrayList<>(); + Alphabet alphabet = getInputAlphabet(); for (Row r : lpRows) { - final RowImpl row = allRows.get(r.getRowId()); + final RowImpl row = getRow(r.getRowId()); if (row.isShortPrefixRow()) { if (row.hasContents()) { continue; @@ -398,7 +149,7 @@ public List>> toShortPrefixes(List> lpRows, MembershipOracle< for (int i = 0; i < alphabet.size(); i++) { I sym = alphabet.getSymbol(i); Word lp = prefix.append(sym); - RowImpl lpRow = rowMap.get(lp); + RowImpl lpRow = getRow(lp); if (lpRow == null) { lpRow = createLpRow(lp); freshLpRows.add(lpRow); @@ -407,6 +158,7 @@ public List>> toShortPrefixes(List> lpRows, MembershipOracle< } } + List> suffixes = getSuffixes(); int numSuffixes = suffixes.size(); int numFreshRows = freshSpRows.size() + freshLpRows.size(); @@ -442,125 +194,20 @@ public List>> toShortPrefixes(List> lpRows, MembershipOracle< return unclosed; } - protected void makeShort(RowImpl row) { - if (row.isShortPrefixRow()) { - return; - } - - int lastIdx = longPrefixRows.size() - 1; - RowImpl last = longPrefixRows.get(lastIdx); - int rowIdx = row.getLpIndex(); - longPrefixRows.remove(lastIdx); - if (last != row) { - longPrefixRows.set(rowIdx, last); - last.setLpIndex(rowIdx); - } - - shortPrefixRows.add(row); - row.makeShort(alphabet.size()); - - if (row.hasContents()) { - int cid = row.getRowContentId(); - if (canonicalRows.get(cid) == null) { - canonicalRows.set(cid, row); - } - } - } - - protected static void buildRowQueries(List> queryList, - List> rows, - List> suffixes) { - for (Row row : rows) { - buildQueries(queryList, row.getLabel(), suffixes); - } - } - - @Override - public List rowContents(Row row) { - return allRowContents.get(row.getRowContentId()); - } - - @Override - public RowImpl getRow(int rowId) { - return allRows.get(rowId); - } - - @Override - public int numberOfRows() { - return shortPrefixRows.size() + longPrefixRows.size(); - } - - @Override - public List> getSuffixes() { - return suffixes; - } - - @Override - public boolean isInitialized() { - return !allRows.isEmpty(); - } - - @Override - public Alphabet getInputAlphabet() { - return alphabet; - } - - /** - * This is an internal method used for de-serializing. Do not deliberately set input alphabets. - * - * @param alphabet - * the input alphabet corresponding to the previously serialized one. - */ - public void setInputAlphabet(Alphabet alphabet) { - this.alphabet = alphabet; - } - - @Override - public Word transformAccessSequence(Word word) { - Row current = shortPrefixRows.get(0); - - for (I sym : word) { - current = getRowSuccessor(current, sym); - current = canonicalRows.get(current.getRowContentId()); - } - - return current.getLabel(); - } - - @Override - public boolean isAccessSequence(Word word) { - Row current = shortPrefixRows.get(0); - - for (I sym : word) { - current = getRowSuccessor(current, sym); - if (!isCanonical(current)) { - return false; - } - } - - return true; - } - - private boolean isCanonical(Row row) { - if (!row.isShortPrefixRow()) { - return false; - } - int contentId = row.getRowContentId(); - return (canonicalRows.get(contentId) == row); - } - @Override public List>> addAlphabetSymbol(I symbol, final MembershipOracle oracle) { - if (!this.alphabet.containsSymbol(symbol)) { - Alphabets.toGrowingAlphabetOrThrowException(this.alphabet).addSymbol(symbol); + final Alphabet alphabet = getInputAlphabet(); + + if (!alphabet.containsSymbol(symbol)) { + Alphabets.toGrowingAlphabetOrThrowException(alphabet).addSymbol(symbol); } - final int newAlphabetSize = this.alphabet.size(); + final int newAlphabetSize = alphabet.size(); if (this.isInitialized() && this.alphabetSize < newAlphabetSize) { this.alphabetSize = newAlphabetSize; - final int newSymbolIdx = this.alphabet.getSymbolIndex(symbol); + final int newSymbolIdx = alphabet.getSymbolIndex(symbol); final List> shortPrefixes = shortPrefixRows; final List> newLongPrefixes = new ArrayList<>(shortPrefixes.size()); @@ -579,7 +226,7 @@ public List>> addAlphabetSymbol(I symbol, final MembershipOracle> queries = new ArrayList<>(numLongPrefixes * numSuffixes); - buildRowQueries(queries, newLongPrefixes, suffixes); + buildRowQueries(queries, newLongPrefixes, getSuffixes()); oracle.processQueries(queries); final Iterator> queryIterator = queries.iterator(); @@ -600,16 +247,4 @@ public List>> addAlphabetSymbol(I symbol, final MembershipOracle> getShortPrefixRows() { - return Collections.unmodifiableList(shortPrefixRows); - } - - @Nonnull - @Override - public Collection> getLongPrefixRows() { - return Collections.unmodifiableList(longPrefixRows); - } } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/Inconsistency.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/Inconsistency.java index b7a9aae42f..bcccd27f87 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/Inconsistency.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/Inconsistency.java @@ -19,7 +19,7 @@ import javax.annotation.Nullable; /** - * A description of an inconsistency in an {@link GenericObservationTable}. An inconsistency consists of two short + * A description of an inconsistency in an {@link AbstractObservationTable}. An inconsistency consists of two short * prefixes u, u' with identical contents, and an input symbol a, such that the * rows for ua and u'a have different contents. * diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/PartialObservationTable.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/PartialObservationTable.java index 98744fd79f..354b11f987 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/PartialObservationTable.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/PartialObservationTable.java @@ -48,7 +48,7 @@ * @author Maren Geske * @author frohme */ -public class PartialObservationTable extends GenericObservationTable>> { +public final class PartialObservationTable extends AbstractObservationTable>> { private static final Logger LOGGER = LoggerFactory.getLogger(PartialObservationTable.class); @@ -79,16 +79,12 @@ public List>> initialize(List> initialShortPrefixes, List> initialSuffixes, MembershipOracle>> oracle) { - checkInitialization(initialShortPrefixes, initialSuffixes); + checkInitialShortPrefixes(initialShortPrefixes); - suffixes.add(Word.epsilon()); - suffixSet.add(Word.epsilon()); - - for (Word suffix : initialSuffixes) { - if (suffixSet.add(suffix)) { - suffixes.add(suffix); - } - } + final List> initialSuffixesWithEpsilon = new ArrayList<>(initialSuffixes.size() + 1); + initialSuffixesWithEpsilon.add(Word.epsilon()); + initialSuffixesWithEpsilon.addAll(initialSuffixes); + final List> suffixes = initializeSuffixes(initialSuffixesWithEpsilon); int numPrefixes = alphabet.size() * initialShortPrefixes.size() + 1; int numNonEmptySuffixes = suffixes.size() - 1; @@ -127,7 +123,7 @@ public List>> initialize(List> initialShortPrefixes, checkForNewAlphabetSymbol(sym); Word lp = sp.append(sym); - RowImpl succRow = rowMap.get(lp); + RowImpl succRow = getRow(lp); if (succRow == null) { succRow = createLpRow(lp); buildQueries(queries, lp, suffixes.subList(1, suffixes.size())); @@ -177,6 +173,7 @@ public List>> toShortPrefixes(List> lpRows, RowImpl freshSpRow = null; List> freshLpRows = new ArrayList<>(); + final List> suffixes = getSuffixes(); final int numNonEmptySuffixes = suffixes.size() - 1; for (Row r : lpRows) { @@ -217,7 +214,7 @@ public List>> toShortPrefixes(List> lpRows, checkForNewAlphabetSymbol(sym); Word lp = prefix.append(sym); - RowImpl lpRow = rowMap.get(lp); + RowImpl lpRow = getRow(lp); if (lpRow == null) { lpRow = createLpRow(lp); freshLpRows.add(lpRow); From b9ceb582451971e9935ebf1bb7f9bdcbfa9e84e4 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 5 Feb 2019 09:44:34 +0100 Subject: [PATCH 117/125] README: add information about BBC and ParitalL* --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 498ef7f005..e79eb40637 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ TTT | `DFA` `Mealy` `VPDA` Additionally, LearnLib offers a variety of tools to ease the practical application of automata learning on real-world systems. This includes drivers and mappers for interfacing software systems with the LearnLib API as well as caches and parallelization for improving the overall performance of the learning setup. +Also, more nuanced setups such as Black-Box-Checking (via [LTSMin][ltsmin]) or inferring partial machines are possible. While we strive to deliver code at a high quality, please note, that there exist parts of the library that still need thorough testing. Contributions -- whether it is in the form of new features, better documentation or tests -- are welcome. @@ -114,3 +115,4 @@ For developing the code base of LearnLib, it is suggested to use one of the majo [maven-central-distr]: http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.learnlib.distribution%22 [intellij]: https://www.jetbrains.com/idea/ [eclipse]: https://www.eclipse.org/ +[ltsmin]: https://ltsmin.utwente.nl/ From 70f95e38978e58237272457b037ffea475dc1b33 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 5 Feb 2019 13:45:53 +0100 Subject: [PATCH 118/125] added support for resumable caches - this includes a refactoring of `ResumableLearner` to `Resumable` - the `SymbolQueryCache` now uses a `CompactMealy` internally instead of a `FastMealy` --- .../algorithms/adt/learner/ADTLearner.java | 4 +- .../algorithms/dhc/mealy/MealyDHC.java | 4 +- .../discriminationtree/AbstractDTLearner.java | 6 +- .../algorithms/kv/dfa/KearnsVaziraniDFA.java | 4 +- .../kv/mealy/KearnsVaziraniMealy.java | 4 +- .../lstar/AbstractAutomatonLStar.java | 4 +- .../ttt/base/AbstractTTTLearner.java | 4 +- .../ResumableLearner.java => Resumable.java} | 18 ++---- oracles/filters/cache/pom.xml | 5 ++ .../filter/cache/dfa/DFACacheOracle.java | 45 ++++++++++++- .../learnlib/filter/cache/dfa/DFACaches.java | 3 +- .../filter/cache/dfa/DFAHashCacheOracle.java | 30 ++++++++- .../filter/cache/mealy/MealyCacheOracle.java | 44 ++++++++++++- .../filter/cache/mealy/SymbolQueryCache.java | 49 ++++++++++---- .../learnlib/filter/cache/sul/SULCache.java | 64 +++++++++++++++++-- .../filter/cache/AbstractCacheTest.java | 62 +++++++++++++++++- .../cache/dfa/AbstractDFACacheTest.java | 16 +++-- .../filter/cache/dfa/DFAHashCacheTest.java | 53 +++++++++++++-- .../cache/mealy/AbstractMealyCacheTest.java | 15 +++-- .../cache/mealy/MealyDAGMapperCacheTest.java | 5 ++ .../cache/mealy/MealyTreeMapperCacheTest.java | 5 ++ .../cache/mealy/SymbolQueryCacheTest.java | 12 +++- .../cache/sul/AbstractSULCacheTest.java | 15 +++-- .../filter/cache/sul/SULDAGCacheTest.java | 3 +- .../filter/cache/sul/SULTreeCacheTest.java | 3 +- .../AbstractResumableLearnerDFATest.java | 4 +- .../AbstractResumableLearnerMealyTest.java | 4 +- .../AbstractResumableLearnerTest.java | 6 +- 28 files changed, 403 insertions(+), 88 deletions(-) rename api/src/main/java/de/learnlib/api/{algorithm/feature/ResumableLearner.java => Resumable.java} (55%) diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java index cba8d1b12a..befa975bf5 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearner.java @@ -52,8 +52,8 @@ import de.learnlib.algorithms.adt.model.ReplacementResult; import de.learnlib.algorithms.adt.util.ADTUtil; import de.learnlib.algorithms.adt.util.SQOOTBridge; +import de.learnlib.api.Resumable; import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.algorithm.feature.ResumableLearner; import de.learnlib.api.oracle.SymbolQueryOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.counterexamples.LocalSuffixFinders; @@ -81,7 +81,7 @@ public class ADTLearner implements LearningAlgorithm.MealyLearner, PartialTransitionAnalyzer, I>, SupportsGrowingAlphabet, - ResumableLearner, I, O>> { + Resumable, I, O>> { private final Alphabet alphabet; private final SQOOTBridge oracle; diff --git a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java index 1bd0ede11e..0fc580194e 100644 --- a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java +++ b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHC.java @@ -32,9 +32,9 @@ import com.google.common.collect.Interners; import com.google.common.collect.Sets; import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.Resumable; import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; import de.learnlib.api.algorithm.feature.GlobalSuffixLearner.GlobalSuffixLearnerMealy; -import de.learnlib.api.algorithm.feature.ResumableLearner; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.counterexamples.GlobalSuffixFinder; @@ -57,7 +57,7 @@ public class MealyDHC implements MealyLearner, AccessSequenceTransformer, GlobalSuffixLearnerMealy, SupportsGrowingAlphabet, - ResumableLearner> { + Resumable> { private static final Logger LOG = LoggerFactory.getLogger(MealyDHC.class); private final MembershipOracle> oracle; 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 02e4cf03f8..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 @@ -23,8 +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.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.Query; @@ -41,9 +41,7 @@ import net.automatalib.words.impl.Alphabets; public abstract class AbstractDTLearner, I, D, SP, TP> - implements LearningAlgorithm, - SupportsGrowingAlphabet, - ResumableLearner> { + implements LearningAlgorithm, SupportsGrowingAlphabet, Resumable> { protected final Alphabet alphabet; private final MembershipOracle oracle; diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java index 9285114fd3..8e73d14e70 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFA.java @@ -27,8 +27,8 @@ import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.acex.impl.AbstractBaseCounterexample; import de.learnlib.algorithms.kv.StateInfo; +import de.learnlib.api.Resumable; import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; -import de.learnlib.api.algorithm.feature.ResumableLearner; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.discriminationtree.BinaryDTree; @@ -53,7 +53,7 @@ * @author Malte Isberner */ public class KearnsVaziraniDFA - implements DFALearner, SupportsGrowingAlphabet, ResumableLearner> { + implements DFALearner, SupportsGrowingAlphabet, Resumable> { private final Alphabet alphabet; private final MembershipOracle oracle; diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java index 064cb2ba2b..2959d042f9 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealy.java @@ -28,8 +28,8 @@ import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.acex.impl.AbstractBaseCounterexample; import de.learnlib.algorithms.kv.StateInfo; +import de.learnlib.api.Resumable; import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; -import de.learnlib.api.algorithm.feature.ResumableLearner; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.discriminationtree.MultiDTree; @@ -55,7 +55,7 @@ * @author Malte Isberner */ public class KearnsVaziraniMealy - implements MealyLearner, SupportsGrowingAlphabet, ResumableLearner> { + implements MealyLearner, SupportsGrowingAlphabet, Resumable> { private final Alphabet alphabet; private final MembershipOracle> oracle; diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java index 2604729519..1a80aa38ee 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractAutomatonLStar.java @@ -20,7 +20,7 @@ import java.util.Collections; import java.util.List; -import de.learnlib.api.algorithm.feature.ResumableLearner; +import de.learnlib.api.Resumable; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.observationtable.ObservationTable; @@ -50,7 +50,7 @@ * @author Malte Isberner */ public abstract class AbstractAutomatonLStar & SupportsGrowingAlphabet> - extends AbstractLStar implements ResumableLearner> { + extends AbstractLStar implements Resumable> { protected AI internalHyp; protected List> stateInfos = new ArrayList<>(); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java index 6ffb989cbc..ba1b623ac9 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java @@ -34,8 +34,8 @@ import de.learnlib.acex.AcexAnalyzer; import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.api.AccessSequenceProvider; +import de.learnlib.api.Resumable; import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.algorithm.feature.ResumableLearner; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.counterexamples.acex.OutInconsPrefixTransformAcex; @@ -58,7 +58,7 @@ * @author Malte Isberner */ public abstract class AbstractTTTLearner - implements LearningAlgorithm, SupportsGrowingAlphabet, ResumableLearner> { + implements LearningAlgorithm, SupportsGrowingAlphabet, Resumable> { protected final Alphabet alphabet; protected final MembershipOracle oracle; diff --git a/api/src/main/java/de/learnlib/api/algorithm/feature/ResumableLearner.java b/api/src/main/java/de/learnlib/api/Resumable.java similarity index 55% rename from api/src/main/java/de/learnlib/api/algorithm/feature/ResumableLearner.java rename to api/src/main/java/de/learnlib/api/Resumable.java index 9fcf65a1bf..505778e271 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/feature/ResumableLearner.java +++ b/api/src/main/java/de/learnlib/api/Resumable.java @@ -13,34 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.api.algorithm.feature; +package de.learnlib.api; import java.io.Serializable; /** - * Learning algorithms that implement this interface can be "suspended" by means of exposing a serializable state object - * that contains all data that is necessary to resume learning process from a previous state. + * Data structures that implement this interface can be "suspended" by means of exposing a serializable state object + * that contains all data that is necessary to resume from this state at a later point in time. * * @param * The type of the serializable learner state. * * @author bainczyk */ -public interface ResumableLearner { +public interface Resumable { /** - * Expose the serializable learner state object. - *

    - * Does not stop a running learning process. Since most data structures that are used during learning are mutable, - * use this method inside of a learning loop with care. + * Expose the serializable state object. * - * @return The learner state. + * @return The state. */ T suspend(); /** - * Does not get the learner to continue learning. Instead, the learner updates its internal state according to the - * given state object. + * Resume the datastructure from a previously serialized point in time. * * @param state * The learner state. diff --git a/oracles/filters/cache/pom.xml b/oracles/filters/cache/pom.xml index 515673bb5c..9a61bf674d 100644 --- a/oracles/filters/cache/pom.xml +++ b/oracles/filters/cache/pom.xml @@ -73,6 +73,11 @@ limitations under the License. jsr305 + + + org.slf4j + slf4j-api + 4.0.0 @@ -71,7 +55,7 @@ limitations under the License. net.automatalib - automata-dot-visualizer + automata-jung-visualizer runtime diff --git a/archetypes/basic/src/main/resources/archetype-resources/src/main/java/Example.java b/archetypes/basic/src/main/resources/archetype-resources/src/main/java/Example.java new file mode 100644 index 0000000000..603a9942fc --- /dev/null +++ b/archetypes/basic/src/main/resources/archetype-resources/src/main/java/Example.java @@ -0,0 +1,128 @@ +package ${package}; + +import java.io.IOException; + +import de.learnlib.algorithms.lstar.dfa.ClassicLStarDFA; +import de.learnlib.algorithms.lstar.dfa.ClassicLStarDFABuilder; +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.datastructure.observationtable.OTUtils; +import de.learnlib.datastructure.observationtable.writer.ObservationTableASCIIWriter; +import de.learnlib.filter.statistic.oracle.CounterOracle.DFACounterOracle; +import de.learnlib.oracle.equivalence.WMethodEQOracle.DFAWMethodEQOracle; +import de.learnlib.oracle.membership.SimulatorOracle.DFASimulatorOracle; +import de.learnlib.util.Experiment.DFAExperiment; +import de.learnlib.util.statistics.SimpleProfiler; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.visualization.Visualization; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * This example shows the usage of a learning algorithm and an equivalence test as part of an experiment in order to + * learn a simulated SUL (system under learning). + * + * @author falkhowar + */ +public final class Example { + + private static final int EXPLORATION_DEPTH = 4; + + private Example() { + // prevent instantiation + } + + public static void main(String[] args) throws IOException { + + // load DFA and alphabet + CompactDFA target = constructSUL(); + Alphabet inputs = target.getInputAlphabet(); + + // construct a simulator membership query oracle + // input - Character (determined by example) + DFAMembershipOracle sul = new DFASimulatorOracle<>(target); + + // oracle for counting queries wraps SUL + DFACounterOracle mqOracle = new DFACounterOracle<>(sul, "membership queries"); + + // construct L* instance + ClassicLStarDFA lstar = + new ClassicLStarDFABuilder().withAlphabet(inputs) // input alphabet + .withOracle(mqOracle) // membership oracle + .create(); + + // construct a W-method conformance test + // exploring the system up to depth 4 from + // every state of a hypothesis + DFAWMethodEQOracle wMethod = new DFAWMethodEQOracle<>(mqOracle, EXPLORATION_DEPTH); + + // construct a learning experiment from + // the learning algorithm and the conformance test. + // The experiment will execute the main loop of + // active learning + DFAExperiment experiment = new DFAExperiment<>(lstar, wMethod, inputs); + + // turn on time profiling + experiment.setProfile(true); + + // enable logging of models + experiment.setLogModels(true); + + // run experiment + experiment.run(); + + // get learned model + DFA result = experiment.getFinalHypothesis(); + + // report results + System.out.println("-------------------------------------------------------"); + + // profiling + System.out.println(SimpleProfiler.getResults()); + + // learning statistics + System.out.println(experiment.getRounds().getSummary()); + System.out.println(mqOracle.getStatisticalData().getSummary()); + + // model statistics + System.out.println("States: " + result.size()); + System.out.println("Sigma: " + inputs.size()); + + // show model + Visualization.visualize(result, inputs); + + System.out.println("-------------------------------------------------------"); + + System.out.println("Final observation table:"); + new ObservationTableASCIIWriter<>().write(lstar.getObservationTable(), System.out); + } + + /** + * creates example from Angluin's seminal paper. + * + * @return example dfa + */ + private static CompactDFA constructSUL() { + // input alphabet contains characters 'a'..'b' + Alphabet sigma = Alphabets.characters('a', 'b'); + + // create automaton + return AutomatonBuilders.newDFA(sigma) + .withInitial("q0") + .from("q0") + .on('a').to("q1") + .on('b').to("q2") + .from("q1") + .on('a').to("q0") + .on('b').to("q3") + .from("q2") + .on('a').to("q3") + .on('b').to("q0") + .from("q3") + .on('a').to("q2") + .on('b').to("q1") + .withAccepting("q0") + .create(); + } +} diff --git a/archetypes/basic/src/main/resources/archetype-resources/src/main/resources/automatalib.properties b/archetypes/basic/src/main/resources/archetype-resources/src/main/resources/automatalib.properties new file mode 100644 index 0000000000..8e82d79e33 --- /dev/null +++ b/archetypes/basic/src/main/resources/archetype-resources/src/main/resources/automatalib.properties @@ -0,0 +1,6 @@ +# Sample AutomataLib properties file, controlling Word representation +automatalib.word.delim.left=\u00ab +automatalib.word.delim.right=\u00bb +automatalib.word.symbol.delim.left=' +automatalib.word.symbol.delim.right=' +automatalib.word.symbol.separator=\u2423 diff --git a/archetypes/basic/src/main/resources/archetype-resources/src/main/resources/logback.xml b/archetypes/basic/src/main/resources/archetype-resources/src/main/resources/logback.xml new file mode 100644 index 0000000000..c6e779da9e --- /dev/null +++ b/archetypes/basic/src/main/resources/archetype-resources/src/main/resources/logback.xml @@ -0,0 +1,11 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %30.30(%logger{30}) - %msg%n + + + + + + + \ No newline at end of file diff --git a/archetypes/basic/src/test/resources-template/projects/basic/goal.txt b/archetypes/basic/src/test/resources/projects/basic/goal.txt similarity index 100% rename from archetypes/basic/src/test/resources-template/projects/basic/goal.txt rename to archetypes/basic/src/test/resources/projects/basic/goal.txt diff --git a/archetypes/complete/src/main/resources-template/META-INF/maven/archetype-metadata.xml b/archetypes/complete/src/main/resources-template/META-INF/maven/archetype-metadata.xml index 3a26bdbf64..0bf53b13e4 100644 --- a/archetypes/complete/src/main/resources-template/META-INF/maven/archetype-metadata.xml +++ b/archetypes/complete/src/main/resources-template/META-INF/maven/archetype-metadata.xml @@ -33,10 +33,10 @@ limitations under the License. **/*.java - - src/test/java + + src/main/resources - **/*.java + **/* diff --git a/archetypes/complete/src/main/resources/archetype-resources/pom.xml b/archetypes/complete/src/main/resources/archetype-resources/pom.xml index 79a1ef321f..6d1cf3ca3b 100644 --- a/archetypes/complete/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/complete/src/main/resources/archetype-resources/pom.xml @@ -1,20 +1,4 @@ - 4.0.0 diff --git a/archetypes/complete/src/main/resources/archetype-resources/src/main/java/Example.java b/archetypes/complete/src/main/resources/archetype-resources/src/main/java/Example.java new file mode 100644 index 0000000000..603a9942fc --- /dev/null +++ b/archetypes/complete/src/main/resources/archetype-resources/src/main/java/Example.java @@ -0,0 +1,128 @@ +package ${package}; + +import java.io.IOException; + +import de.learnlib.algorithms.lstar.dfa.ClassicLStarDFA; +import de.learnlib.algorithms.lstar.dfa.ClassicLStarDFABuilder; +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.datastructure.observationtable.OTUtils; +import de.learnlib.datastructure.observationtable.writer.ObservationTableASCIIWriter; +import de.learnlib.filter.statistic.oracle.CounterOracle.DFACounterOracle; +import de.learnlib.oracle.equivalence.WMethodEQOracle.DFAWMethodEQOracle; +import de.learnlib.oracle.membership.SimulatorOracle.DFASimulatorOracle; +import de.learnlib.util.Experiment.DFAExperiment; +import de.learnlib.util.statistics.SimpleProfiler; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.visualization.Visualization; +import net.automatalib.words.Alphabet; +import net.automatalib.words.impl.Alphabets; + +/** + * This example shows the usage of a learning algorithm and an equivalence test as part of an experiment in order to + * learn a simulated SUL (system under learning). + * + * @author falkhowar + */ +public final class Example { + + private static final int EXPLORATION_DEPTH = 4; + + private Example() { + // prevent instantiation + } + + public static void main(String[] args) throws IOException { + + // load DFA and alphabet + CompactDFA target = constructSUL(); + Alphabet inputs = target.getInputAlphabet(); + + // construct a simulator membership query oracle + // input - Character (determined by example) + DFAMembershipOracle sul = new DFASimulatorOracle<>(target); + + // oracle for counting queries wraps SUL + DFACounterOracle mqOracle = new DFACounterOracle<>(sul, "membership queries"); + + // construct L* instance + ClassicLStarDFA lstar = + new ClassicLStarDFABuilder().withAlphabet(inputs) // input alphabet + .withOracle(mqOracle) // membership oracle + .create(); + + // construct a W-method conformance test + // exploring the system up to depth 4 from + // every state of a hypothesis + DFAWMethodEQOracle wMethod = new DFAWMethodEQOracle<>(mqOracle, EXPLORATION_DEPTH); + + // construct a learning experiment from + // the learning algorithm and the conformance test. + // The experiment will execute the main loop of + // active learning + DFAExperiment experiment = new DFAExperiment<>(lstar, wMethod, inputs); + + // turn on time profiling + experiment.setProfile(true); + + // enable logging of models + experiment.setLogModels(true); + + // run experiment + experiment.run(); + + // get learned model + DFA result = experiment.getFinalHypothesis(); + + // report results + System.out.println("-------------------------------------------------------"); + + // profiling + System.out.println(SimpleProfiler.getResults()); + + // learning statistics + System.out.println(experiment.getRounds().getSummary()); + System.out.println(mqOracle.getStatisticalData().getSummary()); + + // model statistics + System.out.println("States: " + result.size()); + System.out.println("Sigma: " + inputs.size()); + + // show model + Visualization.visualize(result, inputs); + + System.out.println("-------------------------------------------------------"); + + System.out.println("Final observation table:"); + new ObservationTableASCIIWriter<>().write(lstar.getObservationTable(), System.out); + } + + /** + * creates example from Angluin's seminal paper. + * + * @return example dfa + */ + private static CompactDFA constructSUL() { + // input alphabet contains characters 'a'..'b' + Alphabet sigma = Alphabets.characters('a', 'b'); + + // create automaton + return AutomatonBuilders.newDFA(sigma) + .withInitial("q0") + .from("q0") + .on('a').to("q1") + .on('b').to("q2") + .from("q1") + .on('a').to("q0") + .on('b').to("q3") + .from("q2") + .on('a').to("q3") + .on('b').to("q0") + .from("q3") + .on('a').to("q2") + .on('b').to("q1") + .withAccepting("q0") + .create(); + } +} diff --git a/archetypes/complete/src/main/resources/archetype-resources/src/main/resources/automatalib.properties b/archetypes/complete/src/main/resources/archetype-resources/src/main/resources/automatalib.properties new file mode 100644 index 0000000000..8e82d79e33 --- /dev/null +++ b/archetypes/complete/src/main/resources/archetype-resources/src/main/resources/automatalib.properties @@ -0,0 +1,6 @@ +# Sample AutomataLib properties file, controlling Word representation +automatalib.word.delim.left=\u00ab +automatalib.word.delim.right=\u00bb +automatalib.word.symbol.delim.left=' +automatalib.word.symbol.delim.right=' +automatalib.word.symbol.separator=\u2423 diff --git a/archetypes/complete/src/main/resources/archetype-resources/src/main/resources/logback.xml b/archetypes/complete/src/main/resources/archetype-resources/src/main/resources/logback.xml new file mode 100644 index 0000000000..c6e779da9e --- /dev/null +++ b/archetypes/complete/src/main/resources/archetype-resources/src/main/resources/logback.xml @@ -0,0 +1,11 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %30.30(%logger{30}) - %msg%n + + + + + + + \ No newline at end of file diff --git a/archetypes/complete/src/test/resources-template/projects/basic/archetype.properties b/archetypes/complete/src/test/resources-template/projects/complete/archetype.properties similarity index 82% rename from archetypes/complete/src/test/resources-template/projects/basic/archetype.properties rename to archetypes/complete/src/test/resources-template/projects/complete/archetype.properties index a090bf3ed9..acb03c4291 100644 --- a/archetypes/complete/src/test/resources-template/projects/basic/archetype.properties +++ b/archetypes/complete/src/test/resources-template/projects/complete/archetype.properties @@ -1,7 +1,7 @@ package=it.pkg version=0.1-SNAPSHOT groupId=archetype.it -artifactId=basic +artifactId=complete learnlibVersion=${project.version} diff --git a/archetypes/complete/src/test/resources-template/projects/basic/goal.txt b/archetypes/complete/src/test/resources/projects/complete/goal.txt similarity index 100% rename from archetypes/complete/src/test/resources-template/projects/basic/goal.txt rename to archetypes/complete/src/test/resources/projects/complete/goal.txt diff --git a/archetypes/pom.xml b/archetypes/pom.xml index f7f5d93dd5..34de796af3 100644 --- a/archetypes/pom.xml +++ b/archetypes/pom.xml @@ -37,14 +37,14 @@ limitations under the License. complete - + - src/main/resources false @@ -70,6 +70,19 @@ limitations under the License. maven-archetype-plugin ${archetype-plugin.version} + + org.apache.maven.plugins + maven-dependency-plugin + + + + analyze + + true + + + + From 5bd4f07afabcef88140683a529983972b155293f Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 15 Feb 2019 13:04:58 +0100 Subject: [PATCH 122/125] small cleanup --- .../filter/cache/mealy/StateLocalInputMealyTreeCacheTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/StateLocalInputMealyTreeCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/StateLocalInputMealyTreeCacheTest.java index 45be591019..1a240ed051 100644 --- a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/StateLocalInputMealyTreeCacheTest.java +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/StateLocalInputMealyTreeCacheTest.java @@ -37,14 +37,14 @@ public class StateLocalInputMealyTreeCacheTest extends AbstractCacheTest, MealyMachine>, Character, Word>> { - private final StateLocalInputMealySimulatorSUL sul; private final ResetCounterStateLocalInputSUL counter; private final StateLocalInputMealyOracle> oracle; private final Collection initialInputs; public StateLocalInputMealyTreeCacheTest() { - sul = new StateLocalInputMealySimulatorSUL<>(CacheTestUtils.MEALY); + final StateLocalInputMealySimulatorSUL sul = + new StateLocalInputMealySimulatorSUL<>(CacheTestUtils.MEALY); counter = new ResetCounterStateLocalInputSUL<>("counterOracle", sul); oracle = new StateLocalInputSULOracle<>(counter); From 0e2745d569fe5ac0da447da769bf43355ec29d4a Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 18 Feb 2019 12:17:57 +0100 Subject: [PATCH 123/125] migrate goals of reports plugin version 3.0.0 has introduced some incompatible renamings --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 7a78f4412a..b7292a8e8c 100644 --- a/pom.xml +++ b/pom.xml @@ -872,12 +872,12 @@ limitations under the License. index - license - project-team - mailing-list + licenses + team + mailing-lists scm - issue-tracking - cim + issue-management + ci-management dependencies dependency-info modules From f40abbdcf280b62b34dac54e426e457acb50abad Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 18 Feb 2019 12:51:02 +0100 Subject: [PATCH 124/125] switch to AutomataLib release 0.8.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b7292a8e8c..281e2df07e 100644 --- a/pom.xml +++ b/pom.xml @@ -218,7 +218,7 @@ limitations under the License. 1.1.0 - 0.8.0-SNAPSHOT + 0.8.0 0.1 1.9 8.14 From 97afcc0091775f6c73fee700164408c0492f4827 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 18 Feb 2019 14:40:10 +0100 Subject: [PATCH 125/125] [maven-release-plugin] prepare release learnlib-0.14.0 --- algorithms/active/adt/pom.xml | 2 +- algorithms/active/dhc/pom.xml | 2 +- algorithms/active/discrimination-tree-vpda/pom.xml | 2 +- algorithms/active/discrimination-tree/pom.xml | 2 +- algorithms/active/kearns-vazirani/pom.xml | 2 +- algorithms/active/lstar/pom.xml | 2 +- algorithms/active/nlstar/pom.xml | 2 +- algorithms/active/pom.xml | 2 +- algorithms/active/ttt-vpda/pom.xml | 2 +- algorithms/active/ttt/pom.xml | 2 +- algorithms/passive/pom.xml | 2 +- algorithms/passive/rpni-edsm/pom.xml | 2 +- algorithms/passive/rpni-mdl/pom.xml | 2 +- algorithms/passive/rpni/pom.xml | 2 +- algorithms/pom.xml | 2 +- api/pom.xml | 2 +- archetypes/basic/pom.xml | 2 +- archetypes/complete/pom.xml | 2 +- archetypes/pom.xml | 2 +- build-parent/pom.xml | 2 +- build-tools/pom.xml | 2 +- commons/acex/pom.xml | 2 +- commons/counterexamples/pom.xml | 2 +- commons/pom.xml | 2 +- commons/settings/pom.xml | 2 +- commons/util/pom.xml | 2 +- datastructures/discrimination-tree/pom.xml | 2 +- datastructures/list/pom.xml | 2 +- datastructures/observation-table/pom.xml | 2 +- datastructures/pom.xml | 2 +- datastructures/pta/pom.xml | 2 +- distribution/pom.xml | 2 +- drivers/basic/pom.xml | 2 +- drivers/mapper/pom.xml | 2 +- drivers/pom.xml | 2 +- drivers/simulator/pom.xml | 2 +- examples/pom.xml | 4 ++-- oracles/emptiness-oracles/pom.xml | 2 +- oracles/equivalence-oracles/pom.xml | 2 +- oracles/filters/cache/pom.xml | 2 +- oracles/filters/pom.xml | 2 +- oracles/filters/reuse/pom.xml | 2 +- oracles/filters/statistics/pom.xml | 2 +- oracles/membership-oracles/pom.xml | 2 +- oracles/parallelism/pom.xml | 2 +- oracles/pom.xml | 2 +- oracles/property-oracles/pom.xml | 2 +- pom.xml | 4 ++-- test-support/learner-it-support/pom.xml | 2 +- test-support/learning-examples/pom.xml | 2 +- test-support/pom.xml | 2 +- test-support/test-support/pom.xml | 2 +- 52 files changed, 54 insertions(+), 54 deletions(-) diff --git a/algorithms/active/adt/pom.xml b/algorithms/active/adt/pom.xml index 0e10f411d9..92dd4f85dc 100644 --- a/algorithms/active/adt/pom.xml +++ b/algorithms/active/adt/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/active/dhc/pom.xml b/algorithms/active/dhc/pom.xml index 906714dd09..19f3fa5007 100644 --- a/algorithms/active/dhc/pom.xml +++ b/algorithms/active/dhc/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/active/discrimination-tree-vpda/pom.xml b/algorithms/active/discrimination-tree-vpda/pom.xml index 436e200b6d..1f6630e248 100644 --- a/algorithms/active/discrimination-tree-vpda/pom.xml +++ b/algorithms/active/discrimination-tree-vpda/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/active/discrimination-tree/pom.xml b/algorithms/active/discrimination-tree/pom.xml index a94716763e..1ea731b0c8 100644 --- a/algorithms/active/discrimination-tree/pom.xml +++ b/algorithms/active/discrimination-tree/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/active/kearns-vazirani/pom.xml b/algorithms/active/kearns-vazirani/pom.xml index 0a6125f158..160a0850b4 100644 --- a/algorithms/active/kearns-vazirani/pom.xml +++ b/algorithms/active/kearns-vazirani/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/active/lstar/pom.xml b/algorithms/active/lstar/pom.xml index 6514804d87..e227181d19 100644 --- a/algorithms/active/lstar/pom.xml +++ b/algorithms/active/lstar/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/active/nlstar/pom.xml b/algorithms/active/nlstar/pom.xml index 39769a45b2..2352b83960 100644 --- a/algorithms/active/nlstar/pom.xml +++ b/algorithms/active/nlstar/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 learnlib-nlstar diff --git a/algorithms/active/pom.xml b/algorithms/active/pom.xml index 41223349e2..9934ea8215 100644 --- a/algorithms/active/pom.xml +++ b/algorithms/active/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/active/ttt-vpda/pom.xml b/algorithms/active/ttt-vpda/pom.xml index 1371469403..230bd62370 100644 --- a/algorithms/active/ttt-vpda/pom.xml +++ b/algorithms/active/ttt-vpda/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/active/ttt/pom.xml b/algorithms/active/ttt/pom.xml index b6f72079d0..0f4857f423 100644 --- a/algorithms/active/ttt/pom.xml +++ b/algorithms/active/ttt/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-active-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/passive/pom.xml b/algorithms/passive/pom.xml index 3029c9e4db..b65837329f 100644 --- a/algorithms/passive/pom.xml +++ b/algorithms/passive/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/passive/rpni-edsm/pom.xml b/algorithms/passive/rpni-edsm/pom.xml index 2c523d2131..fbdff84638 100644 --- a/algorithms/passive/rpni-edsm/pom.xml +++ b/algorithms/passive/rpni-edsm/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-passive-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/passive/rpni-mdl/pom.xml b/algorithms/passive/rpni-mdl/pom.xml index 751066325c..43d7dee42a 100644 --- a/algorithms/passive/rpni-mdl/pom.xml +++ b/algorithms/passive/rpni-mdl/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-passive-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/passive/rpni/pom.xml b/algorithms/passive/rpni/pom.xml index 1d1baf1ac4..55dbe59974 100644 --- a/algorithms/passive/rpni/pom.xml +++ b/algorithms/passive/rpni/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-algorithms-passive-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/algorithms/pom.xml b/algorithms/pom.xml index ccca0d190e..793b680f54 100644 --- a/algorithms/pom.xml +++ b/algorithms/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/api/pom.xml b/api/pom.xml index e5b31af24f..69de878ce2 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/archetypes/basic/pom.xml b/archetypes/basic/pom.xml index 2f5f9eb4a2..9ed0e82cb3 100644 --- a/archetypes/basic/pom.xml +++ b/archetypes/basic/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib.archetypes learnlib-archetypes-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/archetypes/complete/pom.xml b/archetypes/complete/pom.xml index db29341fc2..3fd24a3c28 100644 --- a/archetypes/complete/pom.xml +++ b/archetypes/complete/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib.archetypes learnlib-archetypes-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/archetypes/pom.xml b/archetypes/pom.xml index 34de796af3..96c999179c 100644 --- a/archetypes/pom.xml +++ b/archetypes/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 62bed6b952..9bfdfabe6f 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/build-tools/pom.xml b/build-tools/pom.xml index 424f832198..b9d4062ba8 100644 --- a/build-tools/pom.xml +++ b/build-tools/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/commons/acex/pom.xml b/commons/acex/pom.xml index e0f206fdfb..0778c7f5ab 100644 --- a/commons/acex/pom.xml +++ b/commons/acex/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-commons-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/commons/counterexamples/pom.xml b/commons/counterexamples/pom.xml index e440c8620c..bf6a83123e 100644 --- a/commons/counterexamples/pom.xml +++ b/commons/counterexamples/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-commons-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/commons/pom.xml b/commons/pom.xml index 53061d4722..9c3bd14f21 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/commons/settings/pom.xml b/commons/settings/pom.xml index e3beb9b8dd..a000e55093 100644 --- a/commons/settings/pom.xml +++ b/commons/settings/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-commons-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/commons/util/pom.xml b/commons/util/pom.xml index bceeda862b..07a3782f6c 100644 --- a/commons/util/pom.xml +++ b/commons/util/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-commons-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/datastructures/discrimination-tree/pom.xml b/datastructures/discrimination-tree/pom.xml index 4681aed534..c72748992f 100644 --- a/datastructures/discrimination-tree/pom.xml +++ b/datastructures/discrimination-tree/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-datastructures-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/datastructures/list/pom.xml b/datastructures/list/pom.xml index 107358ce9a..36ed5f745a 100644 --- a/datastructures/list/pom.xml +++ b/datastructures/list/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-datastructures-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/datastructures/observation-table/pom.xml b/datastructures/observation-table/pom.xml index c2014b9900..dc06e1f26f 100644 --- a/datastructures/observation-table/pom.xml +++ b/datastructures/observation-table/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-datastructures-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/datastructures/pom.xml b/datastructures/pom.xml index 4f39654644..320748f0a4 100644 --- a/datastructures/pom.xml +++ b/datastructures/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/datastructures/pta/pom.xml b/datastructures/pta/pom.xml index 27bb111136..21ce0dd1bc 100644 --- a/datastructures/pta/pom.xml +++ b/datastructures/pta/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-datastructures-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/distribution/pom.xml b/distribution/pom.xml index e98688c7d5..23672b159d 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/drivers/basic/pom.xml b/drivers/basic/pom.xml index fe6f716de2..a73ba5a2aa 100644 --- a/drivers/basic/pom.xml +++ b/drivers/basic/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-drivers-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/drivers/mapper/pom.xml b/drivers/mapper/pom.xml index c99ac1c02e..8266986da6 100644 --- a/drivers/mapper/pom.xml +++ b/drivers/mapper/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-drivers-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/drivers/pom.xml b/drivers/pom.xml index 6ac548b1cb..a20dfbe9ed 100644 --- a/drivers/pom.xml +++ b/drivers/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/drivers/simulator/pom.xml b/drivers/simulator/pom.xml index f8572aaa24..380929c048 100644 --- a/drivers/simulator/pom.xml +++ b/drivers/simulator/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-drivers-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 1f4a370f97..1ef43499f6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml @@ -36,7 +36,7 @@ limitations under the License. - + diff --git a/oracles/emptiness-oracles/pom.xml b/oracles/emptiness-oracles/pom.xml index 2536234062..166e8702c8 100644 --- a/oracles/emptiness-oracles/pom.xml +++ b/oracles/emptiness-oracles/pom.xml @@ -5,7 +5,7 @@ de.learnlib learnlib-oracles-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/oracles/equivalence-oracles/pom.xml b/oracles/equivalence-oracles/pom.xml index 08eb2a975e..b3500699ee 100644 --- a/oracles/equivalence-oracles/pom.xml +++ b/oracles/equivalence-oracles/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-oracles-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/oracles/filters/cache/pom.xml b/oracles/filters/cache/pom.xml index 9a61bf674d..2144d3b219 100644 --- a/oracles/filters/cache/pom.xml +++ b/oracles/filters/cache/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-filters-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/oracles/filters/pom.xml b/oracles/filters/pom.xml index 75e19ff95d..41d5c4195a 100644 --- a/oracles/filters/pom.xml +++ b/oracles/filters/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-oracles-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/oracles/filters/reuse/pom.xml b/oracles/filters/reuse/pom.xml index e15161b449..336b6f53e9 100644 --- a/oracles/filters/reuse/pom.xml +++ b/oracles/filters/reuse/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-filters-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/oracles/filters/statistics/pom.xml b/oracles/filters/statistics/pom.xml index 5a79b14b24..853c0df7f8 100644 --- a/oracles/filters/statistics/pom.xml +++ b/oracles/filters/statistics/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-filters-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/oracles/membership-oracles/pom.xml b/oracles/membership-oracles/pom.xml index 4078facf47..ea80b39025 100644 --- a/oracles/membership-oracles/pom.xml +++ b/oracles/membership-oracles/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-oracles-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/oracles/parallelism/pom.xml b/oracles/parallelism/pom.xml index de9c4d178c..d12262ad47 100644 --- a/oracles/parallelism/pom.xml +++ b/oracles/parallelism/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-oracles-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/oracles/pom.xml b/oracles/pom.xml index 40f20cefdc..26cc92c930 100644 --- a/oracles/pom.xml +++ b/oracles/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/oracles/property-oracles/pom.xml b/oracles/property-oracles/pom.xml index 1f4c6e35ae..18687b4711 100644 --- a/oracles/property-oracles/pom.xml +++ b/oracles/property-oracles/pom.xml @@ -5,7 +5,7 @@ de.learnlib learnlib-oracles-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/pom.xml b/pom.xml index 281e2df07e..fd2370c4ab 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ limitations under the License. --> de.learnlib learnlib-parent - 0.14.0-SNAPSHOT + 0.14.0 pom LearnLib @@ -152,7 +152,7 @@ limitations under the License. scm:git:git@github.com:LearnLib/learnlib.git scm:git:git@github.com:LearnLib/learnlib.git https://github.com/LearnLib/learnlib/tree/develop - HEAD + learnlib-0.14.0 https://github.com/LearnLib/learnlib/issues diff --git a/test-support/learner-it-support/pom.xml b/test-support/learner-it-support/pom.xml index 5dfa2df630..21ea6fd90c 100644 --- a/test-support/learner-it-support/pom.xml +++ b/test-support/learner-it-support/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib.testsupport learnlib-test-support-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/test-support/learning-examples/pom.xml b/test-support/learning-examples/pom.xml index 1018485f6a..1784e70fc3 100644 --- a/test-support/learning-examples/pom.xml +++ b/test-support/learning-examples/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib.testsupport learnlib-test-support-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml diff --git a/test-support/pom.xml b/test-support/pom.xml index d10fbf7351..991c39a6ad 100644 --- a/test-support/pom.xml +++ b/test-support/pom.xml @@ -21,7 +21,7 @@ limitations under the License. de.learnlib learnlib-build-parent - 0.14.0-SNAPSHOT + 0.14.0 ../build-parent/pom.xml diff --git a/test-support/test-support/pom.xml b/test-support/test-support/pom.xml index eea5e4f35f..219a8ae93f 100644 --- a/test-support/test-support/pom.xml +++ b/test-support/test-support/pom.xml @@ -5,7 +5,7 @@ de.learnlib.testsupport learnlib-test-support-parent - 0.14.0-SNAPSHOT + 0.14.0 ../pom.xml

    the property type * @param the output type */ -public class LoggingPropertyOracle implements PropertyOracle { +public class LoggingPropertyOracle, P, D> implements PropertyOracle { private static final LearnLogger LOGGER = LearnLogger.getLogger(LoggingPropertyOracle.class); @@ -81,7 +82,7 @@ public DefaultQuery getCounterExample() { /** * Try to disprove this propertyOracle, and log whenever it is disproved. * - * @see PropertyOracle#disprove(Object, Collection) + * @see PropertyOracle#disprove(Output, Collection) */ @Nullable @Override @@ -102,7 +103,7 @@ public DefaultQuery disprove(A hypothesis, Collection inputs) */ @Nullable @Override - public DefaultQuery findCounterExample(A hypothesis, Collection inputs) throws + public DefaultQuery doFindCounterExample(A hypothesis, Collection inputs) throws ModelCheckingException { final DefaultQuery result = propertyOracle.findCounterExample(hypothesis, inputs); if (result != null) { diff --git a/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java b/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java index d0e6502493..a80e0fe663 100644 --- a/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java @@ -166,7 +166,7 @@ default DefaultQuery findCounterExample(A hypothesis, Collection query = processInput(hypothesis, input); if (query != null) { - ce = isCounterExample(hypothesis, input, query.getOutput()) ? query : null; + ce = isCounterExample(hypothesis, query.getInput(), query.getOutput()) ? query : null; } queries++; } diff --git a/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java b/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java index 678fa7dd04..3c25d3e3e3 100644 --- a/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java @@ -15,7 +15,7 @@ */ package de.learnlib.api.oracle; -import java.util.Collection; +import java.util.List; import javax.annotation.ParametersAreNonnullByDefault; @@ -43,7 +43,7 @@ public interface BlackBoxOracle, I, D> extends InclusionO * * @return the property oracles. */ - Collection> getPropertyOracles(); + List> getPropertyOracles(); interface DFABlackBoxOracle extends BlackBoxOracle, I, Boolean> {} diff --git a/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java index bb8d92ec08..2f3d64cbf7 100644 --- a/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java @@ -45,7 +45,7 @@ @ParametersAreNonnullByDefault public interface EmptinessOracle, I, D> { - default boolean isCounterExample(A hypothesis, Iterable input, @Nullable D output) { + default boolean isCounterExample(Output hypothesis, Iterable input, @Nullable D output) { return Objects.equals(hypothesis.computeOutput(input), output); } diff --git a/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java b/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java index 7b544b2091..16cc739e85 100644 --- a/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java @@ -46,7 +46,7 @@ @ParametersAreNonnullByDefault public interface InclusionOracle, I, D> extends EquivalenceOracle { - default boolean isCounterExample(A hypothesis, Iterable input, @Nullable D output) { + default boolean isCounterExample(Output hypothesis, Iterable input, @Nullable D output) { return !Objects.equals(hypothesis.computeOutput(input), output); } diff --git a/api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java b/api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java index dc2d6e265f..e53422df3e 100644 --- a/api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java @@ -15,11 +15,9 @@ */ package de.learnlib.api.oracle; -import java.util.Objects; - -import javax.annotation.Nullable; - import net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.Lasso.DFALasso; +import net.automatalib.modelchecking.Lasso.MealyLasso; import net.automatalib.words.Word; /** @@ -35,12 +33,19 @@ */ public interface LassoEmptinessOracle, I, D> extends EmptinessOracle { - @Override - default boolean isCounterExample(L hypothesis, Iterable inputs, @Nullable D output) { - return Objects.equals(hypothesis.getAutomaton().computeOutput(inputs), output); + /** + * Return that when a lasso is ultimately periodic, it could serve as a counter example. + * + * @param isUltimatelyPeriodic + * whether the lasso is ultimately periodic + * + * @return true when a lasso is ultimately periodic, false otherwise. + */ + default boolean isOmegaCounterExample(boolean isUltimatelyPeriodic) { + return isUltimatelyPeriodic; } - interface DFALassoEmptinessOracle extends LassoEmptinessOracle, I, Boolean> {} + interface DFALassoEmptinessOracle extends LassoEmptinessOracle, I, Boolean> {} - interface MealyLassoEmptinessOracle extends LassoEmptinessOracle, I, Word> {} + interface MealyLassoEmptinessOracle extends LassoEmptinessOracle, I, Word> {} } diff --git a/api/src/main/java/de/learnlib/api/oracle/LassoOracle.java b/api/src/main/java/de/learnlib/api/oracle/LassoOracle.java index 7d27fc1021..3eb1a96999 100644 --- a/api/src/main/java/de/learnlib/api/oracle/LassoOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/LassoOracle.java @@ -21,7 +21,7 @@ import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.OmegaQuery; -import net.automatalib.automata.DeterministicAutomaton; +import net.automatalib.automata.concepts.Output; import net.automatalib.modelchecking.Lasso; import net.automatalib.modelchecking.Lasso.DFALasso; import net.automatalib.modelchecking.Lasso.MealyLasso; @@ -38,74 +38,66 @@ * * @author Jeroen Meijer */ -public interface LassoOracle, I, D> extends AutomatonOracle { +public interface LassoOracle, I, D> { /** * Processes the given omega query. * - * @param query the omega query to process. + * @param prefix + * the prefix + * @param loop + * the loop + * @param repeat + * the maximum number of times the loop may be repeated * - * @return the processed omega query. + * @return the omega query. */ - OmegaQuery processOmegaQuery(OmegaQuery query); + OmegaQuery processInput(Word prefix, Word loop, int repeat); /** - * Processes the given input word. The default implementation will check if the processed query actually loops. + * Returns whether the given input and output is a counter example for the given hypothesis. * - * @see AutomatonOracle#processInput(DeterministicAutomaton, Word) + * @param hypothesis + * the hypothesis + * @param inputs + * the input sequence + * @param output + * the output corresponding to the input. * - * @param lassoHypothesis - * the hypothesis lasso. - * @param input - * the input to process. + * @return whether the given input and output is a counter example. */ - @Nullable - @Override - default DefaultQuery processInput(L lassoHypothesis, Word input) { - final Word prefix = lassoHypothesis.getPrefix(); - final Word loop = lassoHypothesis.getLoop(); - - assert prefix.isPrefixOf(input); - assert loop.isSuffixOf(input); - - int repeat = (input.length() - prefix.length()) / loop.length(); - - final OmegaQuery omegaQuery = processOmegaQuery(new OmegaQuery<>(prefix, loop, repeat)); - - return omegaQuery.isUltimatelyPeriodic() ? omegaQuery.asDefaultQuery() : null; - } + boolean isCounterExample(Output hypothesis, Iterable inputs, @Nullable D output); /** - * The default implementation accepts an input if it loops at least once and if it makes exactly a loop. - * This behavior is fine for a {@link DFALasso}, because they are assumed to be prefix-closed. + * Returns whether a lasso that is ultimately periodic could serve as a counter example. * - * @see AutomatonOracle#accepts(DeterministicAutomaton, Iterable, int) + * @param isUltimatelyPeriodic + * whether the lasso is ultimately periodic * - * @param hypothesis - * the hypothesis automaton. - * @param input - * the input. - * @param length - * the length of the input. - * - * @return whether the given lasso accepts the given input. + * @return true when lasso that is ultimately periodic could serve as a counter example, false otherwise. */ - @Override - default boolean accepts(L hypothesis, Iterable input, int length) { - return length >= hypothesis.getPrefix().length() + hypothesis.getLoop().length() - && (length - hypothesis.getPrefix().length()) % hypothesis.getLoop().length() == 0; - } + boolean isOmegaCounterExample(boolean isUltimatelyPeriodic); @Nullable - @Override default DefaultQuery findCounterExample(L hypothesis, Collection inputs) { - final int maxQueries = hypothesis.getUnfolds(); + final Word prefix = hypothesis.getPrefix(); + final Word loop = hypothesis.getLoop(); + final int repeat = hypothesis.getUnfolds(); - return findCounterExample(hypothesis, inputs, maxQueries); + final OmegaQuery omegaQuery = processInput(prefix, loop, repeat); + + final DefaultQuery query; + if (isOmegaCounterExample(omegaQuery.isUltimatelyPeriodic())) { + final DefaultQuery ce = omegaQuery.asDefaultQuery(); + query = isCounterExample(hypothesis.getAutomaton(), ce.getInput(), ce.getOutput()) ? ce : null; + } else { + query = null; + } + + return query; } interface DFALassoOracle extends LassoOracle, I, Boolean> {} interface MealyLassoOracle extends LassoOracle, I, Word> {} - } diff --git a/api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java b/api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java index 1af9ef5277..0615fad084 100644 --- a/api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java @@ -21,13 +21,17 @@ import javax.annotation.ParametersAreNonnullByDefault; import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transout.MealyMachine; import net.automatalib.words.Word; /** * A {@link PropertyOracle} can disprove a property, and used to find a counter example to an hypothesis. - * + *

  • the property type - * @param the automaton type * @param the input type + * @param the automaton type + * @param