diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000000..417f1197d7 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,39 @@ +version: '{build}' + +branches: + only: + - master + - develop + - release + +clone_depth: 50 + +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\jdk11 + +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: cd automatalib-checkout + - cmd: mvn install -DskipTests + - cmd: cd %APPVEYOR_BUILD_FOLDER% + +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/.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 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 diff --git a/.travis.yml b/.travis.yml index 0bc7c1ff0c..60f6904163 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,35 +1,94 @@ 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/ + +dist: xenial + +cache: + directories: + - $HOME/.m2 + - $HOME/ltsmin + +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 - release +env: + global: + - LTSMIN_VERSION=v3.1.0 + before_install: + # 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 - # skip several aspects of the build process, because we are only interested in the compiled code - - mvn install -DskipTests -Dmaven.javadoc.skip=true - - popd -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 + - 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 + - cd ${TRAVIS_BUILD_DIR} + +install: + # install LTSmin + - ${TRAVIS_BUILD_DIR}/build-tools/install-ltsmin.sh + - PATH="$PATH:$HOME/ltsmin/$LTSMIN_VERSION/bin" + +script: 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 + script: mvn install -B -Pintegration-tests,code-analysis,bundles + - jdk: openjdk11 + script: mvn install -B -Pintegration-tests,code-analysis,bundles + # Run "integration" tests in other environments + - stage: "Integration Tests" + jdk: openjdk11 + env: MAVEN_OPTS="$MAVEN_OPTS -Dmaven.compiler.source=11 -Dmaven.compiler.target=11" + install: true # Make sure we can build without LTSmin + - os: osx + # Don't explicitly set the jdk version (because the install script doesn't like some (EOL'd) versions) but use the + # default installation of the osx_image (xcode9.3 -> oraclejdk8) + osx_image: xcode9.3 + - os: osx + # Don't explicitly set the jdk version (because the install script doesn't like some (EOL'd) versions) but use the + # default installation of the osx_image (xcode10.1 -> oraclejdk11) + osx_image: xcode10.1 +# - 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 & deploy in default environment + - stage: "Coverage & Deploy" + name: Coverage + jdk: openjdk8 + script: + - mvn install -B -Pintegration-tests,code-coverage + - mvn coveralls:report + - name: Deploy + jdk: openjdk8 + script: skip # skip regular build and define deployment in deploy phase, which is skipped for pull-requests + deploy: + provider: script + script: mvn -B -DskipTests=true deploy + on: + branch: develop # only auto deploy snapshots diff --git a/README.md b/README.md index 9ba64f2238..e79eb40637 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) @@ -30,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. @@ -113,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/ diff --git a/algorithms/active/adt/pom.xml b/algorithms/active/adt/pom.xml index 1020275603..92dd4f85dc 100644 --- a/algorithms/active/adt/pom.xml +++ b/algorithms/active/adt/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-active-parent de.learnlib - 0.13.1 + learnlib-algorithms-active-parent + 0.14.0 ../pom.xml learnlib-adt + LearnLib :: Algorithms :: ADT The ADT Algorithm. Uses adaptive distinguishing trees (a generalization of adaptive distinguishing sequences) to @@ -83,19 +83,16 @@ limitations under the License. org.testng testng - test de.learnlib.testsupport learnlib-learning-examples - test de.learnlib.testsupport learnlib-learner-it-support - test @@ -109,5 +106,4 @@ limitations under the License. test - diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/ads/DefensiveADS.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/ads/DefensiveADS.java index 91b2c3cc89..0c6ad12f2b 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/ads/DefensiveADS.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/ads/DefensiveADS.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,7 +33,7 @@ import de.learnlib.algorithms.adt.api.PartialTransitionAnalyzer; import de.learnlib.algorithms.adt.util.ADTUtil; import net.automatalib.automata.concepts.StateIDs; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; import net.automatalib.util.automata.ads.ADSUtil; import net.automatalib.words.Alphabet; diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADT.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADT.java index 6461bdd4fb..102423bc27 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADT.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTLeafNode.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTLeafNode.java index b319ee715b..08a63513a9 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTLeafNode.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTLeafNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..7f1be4cbc9 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/adt/ADTResetNode.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTResetNode.java index 6f8552aa40..80d8eef6d6 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTResetNode.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTResetNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTSymbolNode.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTSymbolNode.java index 73e9e08abc..530c846b86 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTSymbolNode.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/adt/ADTSymbolNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/ADTExtender.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/ADTExtender.java index afada6338d..9dd2ea06e1 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/ADTExtender.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/ADTExtender.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/LeafSplitter.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/LeafSplitter.java index ca296ae60d..a84e0cdd03 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/LeafSplitter.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/LeafSplitter.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/PartialTransitionAnalyzer.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/PartialTransitionAnalyzer.java index 30518bc71b..ccb46e968f 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/PartialTransitionAnalyzer.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/PartialTransitionAnalyzer.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/SubtreeReplacer.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/SubtreeReplacer.java index a4a75289e0..9c8704e874 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/SubtreeReplacer.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/api/SubtreeReplacer.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ import de.learnlib.algorithms.adt.adt.ADT; import de.learnlib.algorithms.adt.model.ReplacementResult; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; /** diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTHypothesis.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTHypothesis.java index 2a3a77998d..1f499f23ee 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTHypothesis.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTHypothesis.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ import de.learnlib.algorithms.adt.adt.ADTNode; import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.base.fast.AbstractFastMutableDet; -import net.automatalib.automata.transout.MutableMealyMachine; +import net.automatalib.automata.transducers.MutableMealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; 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..7a9115278b 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/automaton/ADTTransition.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTTransition.java index 911e1c7247..925c081cf2 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTTransition.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/automaton/ADTTransition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/ADTExtenders.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/ADTExtenders.java index 72044962ea..c93a29358e 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/ADTExtenders.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/ADTExtenders.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/LeafSplitters.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/LeafSplitters.java index 353554773d..beb2a17087 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/LeafSplitters.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/LeafSplitters.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/SubtreeReplacers.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/SubtreeReplacers.java index dcf66c61fa..3c685c00ac 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/SubtreeReplacers.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/SubtreeReplacers.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,7 @@ import de.learnlib.algorithms.adt.config.model.replacer.LevelOrderReplacer; import de.learnlib.algorithms.adt.config.model.replacer.SingleReplacer; import de.learnlib.algorithms.adt.model.ReplacementResult; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; /** diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/ADSCalculator.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/ADSCalculator.java index 56a725cc9f..ebead5855b 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/ADSCalculator.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/ADSCalculator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import de.learnlib.algorithms.adt.adt.ADTNode; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; /** diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/DefensiveADSCalculator.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/DefensiveADSCalculator.java index 894d80e264..5be441b90e 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/DefensiveADSCalculator.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/DefensiveADSCalculator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ import de.learnlib.algorithms.adt.adt.ADTNode; import de.learnlib.algorithms.adt.api.PartialTransitionAnalyzer; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; /** diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/AbstractCalculator.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/AbstractCalculator.java index 5b951a1028..efbae9ac57 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/AbstractCalculator.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/AbstractCalculator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import de.learnlib.algorithms.adt.adt.ADTNode; import de.learnlib.algorithms.adt.config.model.ADSCalculator; import de.learnlib.algorithms.adt.util.ADTUtil; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.graphs.ads.ADSNode; import net.automatalib.words.Alphabet; diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/BestEffortCalculator.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/BestEffortCalculator.java index 5a0dd364e4..a2ef5400a2 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/BestEffortCalculator.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/BestEffortCalculator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import javax.annotation.ParametersAreNonnullByDefault; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.graphs.ads.ADSNode; import net.automatalib.util.automata.ads.ADS; import net.automatalib.words.Alphabet; diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/BestEffortDefensiveCalculator.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/BestEffortDefensiveCalculator.java index c75cc23430..38731ff2c3 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/BestEffortDefensiveCalculator.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/BestEffortDefensiveCalculator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ import de.learnlib.algorithms.adt.adt.ADTNode; import de.learnlib.algorithms.adt.api.PartialTransitionAnalyzer; import de.learnlib.algorithms.adt.config.model.DefensiveADSCalculator; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; /** diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/MinLengthCalculator.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/MinLengthCalculator.java index 1bf69ad411..72fd80e4a5 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/MinLengthCalculator.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/MinLengthCalculator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import javax.annotation.ParametersAreNonnullByDefault; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.graphs.ads.ADSNode; import net.automatalib.util.automata.ads.BacktrackingSearch; import net.automatalib.words.Alphabet; diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/MinSizeCalculator.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/MinSizeCalculator.java index af48b3959a..e4afc66fd4 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/MinSizeCalculator.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/calculator/MinSizeCalculator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import javax.annotation.ParametersAreNonnullByDefault; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.graphs.ads.ADSNode; import net.automatalib.util.automata.ads.BacktrackingSearch; import net.automatalib.words.Alphabet; diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/extender/DefaultExtender.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/extender/DefaultExtender.java index 67eded866b..eb2350d649 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/extender/DefaultExtender.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/extender/DefaultExtender.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/ExhaustiveReplacer.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/ExhaustiveReplacer.java index 08dd223335..4d6cdc419e 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/ExhaustiveReplacer.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/ExhaustiveReplacer.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,7 +34,7 @@ import de.learnlib.algorithms.adt.config.model.ADSCalculator; import de.learnlib.algorithms.adt.model.ReplacementResult; import de.learnlib.algorithms.adt.util.ADTUtil; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; /** @@ -79,7 +79,7 @@ public Set> computeReplacements(final Mealy .toSet()))); final List> sortedCandidates = new ArrayList<>(candidates); - Collections.sort(sortedCandidates, Comparator.comparingInt(n -> subtreesToFinalNodes.get(n).size())); + sortedCandidates.sort(Comparator.comparingInt(n -> subtreesToFinalNodes.get(n).size())); for (final ADTNode node : sortedCandidates) { diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/LevelOrderReplacer.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/LevelOrderReplacer.java index 26614ce8be..c3338b6bd5 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/LevelOrderReplacer.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/LevelOrderReplacer.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ import de.learnlib.algorithms.adt.config.model.ADSCalculator; import de.learnlib.algorithms.adt.model.ReplacementResult; import de.learnlib.algorithms.adt.util.ADTUtil; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; /** diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/SingleReplacer.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/SingleReplacer.java index ba75c5d321..9f8d1c63cf 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/SingleReplacer.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/config/model/replacer/SingleReplacer.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,7 +35,7 @@ import de.learnlib.algorithms.adt.config.model.ADSCalculator; import de.learnlib.algorithms.adt.model.ReplacementResult; import de.learnlib.algorithms.adt.util.ADTUtil; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -67,7 +67,7 @@ public Set> computeReplacements(final Mealy })); final List> sortedCandidates = new ArrayList<>(candidates); - Collections.sort(sortedCandidates, Comparator.comparingDouble(candidatesScore::get)); + sortedCandidates.sort(Comparator.comparingDouble(candidatesScore::get)); for (final ADTNode node : sortedCandidates) { final Set targetStates = 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..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -52,20 +52,20 @@ 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.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.automata.transout.MealyMachine; +import net.automatalib.SupportsGrowingAlphabet; +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. @@ -81,9 +81,9 @@ public class ADTLearner implements LearningAlgorithm.MealyLearner, PartialTransitionAnalyzer, I>, SupportsGrowingAlphabet, - ResumableLearner, I, O>> { + Resumable, I, O>> { - private Alphabet alphabet; + private final Alphabet alphabet; private final SQOOTBridge oracle; private final LeafSplitter leafSplitter; private final ADTExtender adtExtender; @@ -95,16 +95,25 @@ public class ADTLearner implements LearningAlgorithm.MealyLearner, private ADTHypothesis hypothesis; private ADT, I, O> adt; - @GenerateBuilder(defaults = BuilderDefaults.class) public ADTLearner(final Alphabet alphabet, final SymbolQueryOracle oracle, final LeafSplitter leafSplitter, final ADTExtender adtExtender, final SubtreeReplacer subtreeReplacer) { + this(alphabet, oracle, leafSplitter, adtExtender, subtreeReplacer, true); + } - this.alphabet = SymbolHidingAlphabet.wrapIfMutable(alphabet); + @GenerateBuilder(defaults = BuilderDefaults.class) + public ADTLearner(final Alphabet alphabet, + final SymbolQueryOracle oracle, + final LeafSplitter leafSplitter, + final ADTExtender adtExtender, + final SubtreeReplacer subtreeReplacer, + final boolean useObservationTree) { + + this.alphabet = alphabet; this.observationTree = new ObservationTree<>(this.alphabet); - this.oracle = new SQOOTBridge<>(this.observationTree, oracle, true); + this.oracle = new SQOOTBridge<>(this.observationTree, oracle, useObservationTree); this.leafSplitter = leafSplitter; this.adtExtender = adtExtender; @@ -212,6 +221,7 @@ public boolean refineHypothesisInternal(DefaultQuery> ceQuery) { final ADTNode, I, O> newNode; + // directly insert into observation tree, because we use it for finding a splitter this.observationTree.addState(newState, newState.getAccessSequence(), oldTrans.getOutput()); this.observationTree.addTrace(newState, nodeToSplit); @@ -225,6 +235,7 @@ public boolean refineHypothesisInternal(DefaultQuery> ceQuery) { newNode = this.adt.extendLeaf(nodeToSplit, completeSplitter, oldOutput, newOutput); } else { + // directly insert into observation tree, because we use it for finding a splitter this.observationTree.addTrace(uaState, v, this.oracle.answerQuery(uaAccessSequence, v)); this.observationTree.addTrace(newState, v, this.oracle.answerQuery(uAccessSequenceWithA, v)); @@ -365,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 @@ -809,7 +816,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; @@ -822,5 +833,9 @@ public static ADTExtender adtExtender() { public static SubtreeReplacer subtreeReplacer() { return SubtreeReplacers.LEVELED_BEST_EFFORT; } + + public static boolean useObservationTree() { + return true; + } } } diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearnerState.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearnerState.java index 7441212109..5359cf2c23 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearnerState.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/learner/ADTLearnerState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ExtensionResult.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ExtensionResult.java index defc5b2171..815fba6da0 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ExtensionResult.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ExtensionResult.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..d915b7098b 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,8 +26,8 @@ import de.learnlib.algorithms.adt.adt.ADTNode; import de.learnlib.algorithms.adt.util.ADTUtil; -import net.automatalib.automata.transout.impl.FastMealy; -import net.automatalib.automata.transout.impl.FastMealyState; +import net.automatalib.automata.transducers.impl.FastMealy; +import net.automatalib.automata.transducers.impl.FastMealyState; import net.automatalib.commons.util.Pair; import net.automatalib.util.automata.equivalence.NearLinearEquivalenceTest; import net.automatalib.words.Alphabet; @@ -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 { diff --git a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ReplacementResult.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ReplacementResult.java index 6994d538fc..346a95359e 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ReplacementResult.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/model/ReplacementResult.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..d6f7d9babe 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import de.learnlib.algorithms.adt.adt.ADTLeafNode; import de.learnlib.algorithms.adt.adt.ADTNode; import de.learnlib.algorithms.adt.adt.ADTSymbolNode; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; import net.automatalib.graphs.ads.ADSNode; import net.automatalib.words.Word; @@ -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/active/adt/src/main/java/de/learnlib/algorithms/adt/util/SQOOTBridge.java b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/util/SQOOTBridge.java index 81599e236c..d25d2b4f39 100644 --- a/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/util/SQOOTBridge.java +++ b/algorithms/active/adt/src/main/java/de/learnlib/algorithms/adt/util/SQOOTBridge.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,8 +22,8 @@ import de.learnlib.algorithms.adt.model.ObservationTree; import de.learnlib.api.oracle.SymbolQueryOracle; -import net.automatalib.automata.transout.impl.FastMealy; -import net.automatalib.automata.transout.impl.FastMealyState; +import net.automatalib.automata.transducers.impl.FastMealy; +import net.automatalib.automata.transducers.impl.FastMealyState; /** * A utility class that links an observation tree with a symbol query oracle, meaning that all queries to the symbol @@ -58,7 +58,7 @@ public SQOOTBridge(final ObservationTree observationTree, this.observationTree = observationTree.getObservationTree(); this.delegate = delegate; this.enableCache = enableCache; - this.currentTrace = new ArrayList<>(); + this.currentTrace = enableCache ? new ArrayList<>() : null; } public void initialize() { @@ -94,8 +94,11 @@ public O query(I i) { if (succ == null) { final FastMealyState newState = this.observationTree.addState(); - this.observationTree.addTransition(this.currentState, i, newState, output); nextState = newState; + + if (this.enableCache) { + this.observationTree.addTransition(this.currentState, i, newState, output); + } } else { assert this.observationTree.getOutput(this.currentState, i).equals(output) : "Inconsistent observations"; nextState = succ; diff --git a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/automaton/ADTHypothesisTest.java b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/automaton/ADTHypothesisTest.java index 614578812e..7c8e0440b0 100644 --- a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/automaton/ADTHypothesisTest.java +++ b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/automaton/ADTHypothesisTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/it/ADTIT.java b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/it/ADTIT.java index 0758973909..13237a610c 100644 --- a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/it/ADTIT.java +++ b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/it/ADTIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,6 +17,7 @@ import java.util.Arrays; import java.util.List; +import java.util.Random; import de.learnlib.algorithms.adt.api.ADTExtender; import de.learnlib.algorithms.adt.api.LeafSplitter; @@ -54,6 +55,8 @@ protected void addLearnerVariants(Alphabet alphabet, SubtreeReplacers.LEVELED_MIN_SIZE, SubtreeReplacers.SINGLE_BEST_EFFORT); + final Random useCacheGenerator = new Random(42); + for (int i = 0; i < leafSplitters.size(); i++) { final LeafSplitter leafSplitter = leafSplitters.get(i); builder.setLeafSplitter(leafSplitter); @@ -65,6 +68,7 @@ protected void addLearnerVariants(Alphabet alphabet, for (int k = 0; k < subtreeReplacers.size(); k++) { final SubtreeReplacer subtreeReplacer = subtreeReplacers.get(k); builder.setSubtreeReplacer(subtreeReplacer); + builder.setUseObservationTree(useCacheGenerator.nextBoolean()); variants.addLearnerVariant(i + "," + j + "," + k, builder.create()); } diff --git a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/it/MQ2SQWrapper.java b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/it/MQ2SQWrapper.java index 17d1d3872d..3e574ed85c 100644 --- a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/it/MQ2SQWrapper.java +++ b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/it/MQ2SQWrapper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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 7646d4fc9e..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -25,7 +27,7 @@ import de.learnlib.driver.util.MealySimulatorSUL; import de.learnlib.oracle.membership.SULSymbolQueryOracle; import de.learnlib.testsupport.AbstractGrowingAlphabetTest; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -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/adt/src/test/java/de/learnlib/algorithms/adt/learner/ADTResumableLearnerTest.java b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/learner/ADTResumableLearnerTest.java index f62c35d2c7..c039d6c7a6 100644 --- a/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/learner/ADTResumableLearnerTest.java +++ b/algorithms/active/adt/src/test/java/de/learnlib/algorithms/adt/learner/ADTResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,14 @@ import java.util.Random; import de.learnlib.algorithms.adt.automaton.ADTState; +import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; import de.learnlib.api.oracle.SymbolQueryOracle; +import de.learnlib.api.query.DefaultQuery; import de.learnlib.driver.util.MealySimulatorSUL; import de.learnlib.oracle.membership.SULSymbolQueryOracle; import de.learnlib.testsupport.AbstractResumableLearnerTest; -import net.automatalib.automata.transout.MealyMachine; +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; @@ -49,6 +52,17 @@ protected SymbolQueryOracle getOracle(MealyMachine(new MealySimulatorSUL<>(target)); } + @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)); + }; + } + @Override protected ADTLearner getLearner(SymbolQueryOracle oracle, Alphabet alphabet) { diff --git a/algorithms/active/dhc/pom.xml b/algorithms/active/dhc/pom.xml index 7211179719..19f3fa5007 100644 --- a/algorithms/active/dhc/pom.xml +++ b/algorithms/active/dhc/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-active-parent de.learnlib - 0.13.1 + learnlib-algorithms-active-parent + 0.14.0 ../pom.xml learnlib-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/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..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,17 +32,18 @@ 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.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.automata.transout.impl.compact.CompactMealy; +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; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -56,11 +57,11 @@ public class MealyDHC implements MealyLearner, AccessSequenceTransformer, GlobalSuffixLearnerMealy, SupportsGrowingAlphabet, - ResumableLearner> { + Resumable> { 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,32 @@ 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 @@ -301,7 +304,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/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHCState.java b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHCState.java index 2edbf1a718..ef1f6112c5 100644 --- a/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHCState.java +++ b/algorithms/active/dhc/src/main/java/de/learnlib/algorithms/dhc/mealy/MealyDHCState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import java.util.Map; import com.google.common.collect.Maps; -import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; import net.automatalib.commons.util.mappings.MutableMapping; import net.automatalib.words.Word; diff --git a/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCGrowingAlphabetTest.java b/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCGrowingAlphabetTest.java index 17803d3676..ff8319c973 100644 --- a/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCGrowingAlphabetTest.java +++ b/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCResumableLearnerTest.java b/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCResumableLearnerTest.java index a6b6a46687..c8d4caa80f 100644 --- a/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCResumableLearnerTest.java +++ b/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCTest.java b/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCTest.java index d2f72d6ab2..00e96c0ebc 100644 --- a/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCTest.java +++ b/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/MealyDHCTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,8 +26,8 @@ import de.learnlib.oracle.equivalence.SimulatorEQOracle; import de.learnlib.oracle.membership.SimulatorOracle; import de.learnlib.oracle.membership.SimulatorOracle.MealySimulatorOracle; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.automata.transducers.MealyMachine; +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; diff --git a/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/it/MealyDHCIT.java b/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/it/MealyDHCIT.java index 32c33d6309..f8fc59253f 100644 --- a/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/it/MealyDHCIT.java +++ b/algorithms/active/dhc/src/test/java/de/learnlib/algorithms/dhc/mealy/it/MealyDHCIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree-vpda/pom.xml b/algorithms/active/discrimination-tree-vpda/pom.xml index cbb42296a5..1f6630e248 100644 --- a/algorithms/active/discrimination-tree-vpda/pom.xml +++ b/algorithms/active/discrimination-tree-vpda/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-active-parent de.learnlib - 0.13.1 + learnlib-algorithms-active-parent + 0.14.0 ../pom.xml learnlib-discrimination-tree-vpda + LearnLib :: Algorithms :: Discrimination Tree [VPDA] A learning algorithm, which distinguishes hypothesis states using a discrimination tree (visibly push-down @@ -63,10 +63,6 @@ limitations under the License. net.automatalib automata-commons-smartcollections - - net.automatalib - automata-commons-util - @@ -85,12 +81,10 @@ limitations under the License. org.testng testng - test de.learnlib.testsupport learnlib-learner-it-support - test 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..2de214fd4c 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/BlockList.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/BlockList.java index d46d8e064d..999941a109 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/BlockList.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/BlockList.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/ContextPair.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/ContextPair.java index 11be5e0bb2..b2264510c9 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/ContextPair.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/ContextPair.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree-vpda/src/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..a0f1f6903a 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/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..8991b60937 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/HypIntTrans.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypIntTrans.java index f583a7f160..1e6842664e 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypIntTrans.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypIntTrans.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree-vpda/src/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..9098979036 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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.smartcollections.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)); @@ -85,6 +82,7 @@ public boolean isRoot() { return treeIncoming == null; } + @Override public Word getAccessSequence() { return aseq; } diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypRetTrans.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypRetTrans.java index 3d1d99842c..884f39feea 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypRetTrans.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/HypRetTrans.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/OneSEVPAHypothesis.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/OneSEVPAHypothesis.java index 89e728c134..e6a2d732fc 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/OneSEVPAHypothesis.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/vpda/OneSEVPAHypothesis.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree-vpda/src/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..d504a44c9d 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..98540061bb 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/DTLearnerVPDA.java b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/DTLearnerVPDA.java index 89d8d85249..b8254c1ed3 100644 --- a/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/DTLearnerVPDA.java +++ b/algorithms/active/discrimination-tree-vpda/src/main/java/de/learnlib/algorithms/discriminationtree/vpda/DTLearnerVPDA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree-vpda/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java b/algorithms/active/discrimination-tree-vpda/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java index aa66e43a55..d5dc388f62 100644 --- a/algorithms/active/discrimination-tree-vpda/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java +++ b/algorithms/active/discrimination-tree-vpda/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerVPDAIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/pom.xml b/algorithms/active/discrimination-tree/pom.xml index 874407f2d5..1ea731b0c8 100644 --- a/algorithms/active/discrimination-tree/pom.xml +++ b/algorithms/active/discrimination-tree/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-active-parent de.learnlib - 0.13.1 + learnlib-algorithms-active-parent + 0.14.0 ../pom.xml learnlib-discrimination-tree + LearnLib :: Algorithms :: Discrimination Tree A learning algorithm, which distinguishes hypothesis states using a discrimination tree. @@ -58,7 +58,7 @@ limitations under the License. net.automatalib - automata-commons-util + automata-commons-smartcollections @@ -71,12 +71,10 @@ limitations under the License. org.testng testng - test de.learnlib.testsupport learnlib-learner-it-support - test de.learnlib diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java index 3a37bc0ceb..e59e5c018b 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/AbstractDTLearner.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,9 +23,8 @@ import de.learnlib.algorithms.discriminationtree.hypothesis.DTLearnerHypothesis; import de.learnlib.algorithms.discriminationtree.hypothesis.HState; import de.learnlib.algorithms.discriminationtree.hypothesis.HTransition; +import de.learnlib.api.Resumable; import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.algorithm.feature.ResumableLearner; -import de.learnlib.api.algorithm.feature.SupportsGrowingAlphabet; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.api.query.Query; @@ -34,17 +33,17 @@ import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree; import de.learnlib.util.MQUtil; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; public abstract class AbstractDTLearner, I, D, SP, TP> - implements LearningAlgorithm, - SupportsGrowingAlphabet, - ResumableLearner> { + implements LearningAlgorithm, SupportsGrowingAlphabet, Resumable> { - protected Alphabet alphabet; + protected final Alphabet alphabet; private final MembershipOracle oracle; private final LocalSuffixFinder suffixFinder; private final boolean repeatedCounterexampleEvaluation; @@ -69,7 +68,7 @@ protected AbstractDTLearner(Alphabet alphabet, @Override public void startLearning() { - HState init = hypothesis.getInitialState(); + HState init = hypothesis.createInitialState(); AbstractWordBasedDTNode> initDt = dtree.sift(init.getAccessSequence()); if (initDt.getData() != null) { throw new IllegalStateException("Decision tree already contains data"); @@ -149,9 +148,8 @@ protected void initializeState(HState newState) { } protected void updateHypothesis() { - HTransition current; - while ((current = openTransitions.poll()) != null) { - updateTransition(current); + while (!openTransitions.isEmpty()) { + updateTransitions(); } List> queries = new ArrayList<>(); @@ -174,22 +172,37 @@ protected void updateHypothesis() { oracle.processQueries(queries); } - protected void updateTransition(HTransition trans) { - if (trans.isTree()) { - return; + protected void updateTransitions() { + final List> transitionsToSift = new ArrayList<>(openTransitions.size()); + final List>> nodes = new ArrayList<>(openTransitions.size()); + final List> prefixes = new ArrayList<>(openTransitions.size()); + + for (HTransition t : openTransitions) { + if (!t.isTree()) { + transitionsToSift.add(t); + nodes.add(t.getDT()); + prefixes.add(t.getAccessSequence()); + } } - AbstractWordBasedDTNode> currDt = trans.getDT(); - currDt = dtree.sift(currDt, trans.getAccessSequence()); - trans.setDT(currDt); - - HState state = currDt.getData(); - if (state == null) { - state = createState(trans); - currDt.setData(state); - state.setDTLeaf(currDt); - } else { - state.addNonTreeIncoming(trans); + openTransitions.clear(); + + final List>> results = dtree.sift(nodes, prefixes); + + for (int i = 0; i < transitionsToSift.size(); i++) { + final HTransition trans = transitionsToSift.get(i); + final AbstractWordBasedDTNode> currDt = results.get(i); + + trans.setDT(currDt); + + HState state = currDt.getData(); + if (state == null) { + state = createState(trans); + currDt.setData(state); + state.setDTLeaf(currDt); + } else { + state.addNonTreeIncoming(trans); + } } } @@ -214,30 +227,29 @@ public DTLearnerHypothesis getHypothesisDS() { } @Override - public void addAlphabetSymbol(I symbol) { + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { - if (this.alphabet.containsSymbol(symbol)) { - return; + if (!this.alphabet.containsSymbol(symbol)) { + Alphabets.toGrowingAlphabetOrThrowException(this.alphabet).addSymbol(symbol); } - final int newSymbolIdx = this.alphabet.size(); - this.hypothesis.addAlphabetSymbol(symbol); - // since we share the alphabet instance with our hypothesis, our alphabet might have already been updated (if it - // was already a GrowableAlphabet) - if (!this.alphabet.containsSymbol(symbol)) { - this.alphabet = Alphabets.withNewSymbol(this.alphabet, symbol); - } + // check if we already have information about the symbol (then the transition is defined) so we don't post + // redundant queries + if (this.hypothesis.getInitialState() != null && + this.hypothesis.getSuccessor(this.hypothesis.getInitialState(), symbol) == null) { + final int newSymbolIdx = this.alphabet.getSymbolIndex(symbol); + + for (final HState s : this.hypothesis.getStates()) { + final HTransition newTrans = new HTransition<>(s, symbol, dtree.getRoot()); + s.setTransition(newSymbolIdx, newTrans); + newTransitions.add(newTrans); + openTransitions.add(newTrans); + } - for (final HState s : this.hypothesis.getStates()) { - final HTransition newTrans = new HTransition<>(s, symbol, dtree.getRoot()); - s.setTransition(newSymbolIdx, newTrans); - newTransitions.add(newTrans); - openTransitions.add(newTrans); + this.updateHypothesis(); } - - this.updateHypothesis(); } @Override @@ -252,7 +264,11 @@ public void resume(DTLearnerState state) { this.dtree.setOracle(oracle); } - public static class BuilderDefaults { + public static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } public static LocalSuffixFinder suffixFinder() { return LocalSuffixFinders.RIVEST_SCHAPIRE; diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/DTLearnerState.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/DTLearnerState.java index 707448b107..af05e84580 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/DTLearnerState.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/DTLearnerState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/DTLearnerDFA.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/DTLearnerDFA.java index 18175b75d6..7b1b74ae28 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/DTLearnerDFA.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/DTLearnerDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -95,7 +95,11 @@ public void resume(DTLearnerState state) { this.hypWrapper = new HypothesisWrapperDFA<>(this.hypothesis); } - public static class BuilderDefaults { + public static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } public static boolean epsilonRoot() { return true; diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java index 06602fd2f7..bfbd31c907 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/dfa/HypothesisWrapperDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/DTLearnerHypothesis.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/DTLearnerHypothesis.java index d43ece67ee..a7d2ebcedd 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/DTLearnerHypothesis.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/DTLearnerHypothesis.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import java.util.Map; import de.learnlib.api.AccessSequenceTransformer; -import net.automatalib.automata.GrowableAlphabetAutomaton; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.StateIDs; import net.automatalib.graphs.Graph; @@ -52,21 +52,27 @@ public class DTLearnerHypothesis implements UniversalDeterministicAutomaton, I, HTransition, SP, TP>, AccessSequenceTransformer, StateIDs>, - GrowableAlphabetAutomaton, + SupportsGrowingAlphabet, Serializable { - private Alphabet alphabet; - private final HState root; + private final Alphabet alphabet; + private int alphabetSize; + private HState root; private final List> nodes = new ArrayList<>(); public DTLearnerHypothesis(Alphabet alphabet) { this.alphabet = alphabet; - this.root = new HState<>(alphabet.size()); + this.alphabetSize = this.alphabet.size(); + } + + public HState createInitialState() { + this.root = new HState<>(alphabetSize); this.nodes.add(root); + return this.root; } public HState createState(HTransition treeIncoming) { - HState state = new HState<>(alphabet.size(), nodes.size(), treeIncoming); + HState state = new HState<>(alphabetSize, nodes.size(), treeIncoming); nodes.add(state); treeIncoming.makeTree(state); return state; @@ -131,15 +137,18 @@ public HState getSuccessor(HTransition trans) { @Override public void addAlphabetSymbol(I symbol) { - if (this.alphabet.containsSymbol(symbol)) { - return; + if (!this.alphabet.containsSymbol(symbol)) { + Alphabets.toGrowingAlphabetOrThrowException(this.alphabet).addSymbol(symbol); } - this.alphabet = Alphabets.withNewSymbol(this.alphabet, symbol); - final int alphabetSize = this.alphabet.size(); + final int newAlphabetSize = this.alphabet.size(); + + if (alphabetSize < newAlphabetSize) { + for (final HState s : this.getStates()) { + s.ensureInputCapacity(newAlphabetSize); + } - for (final HState s : this.getStates()) { - s.ensureInputCapacity(alphabetSize); + this.alphabetSize = newAlphabetSize; } } diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HState.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HState.java index 1b76e6491b..777c91f25a 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HState.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import java.util.List; import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; -import net.automatalib.commons.util.array.ResizingObjectArray; +import net.automatalib.commons.smartcollections.ResizingArrayStorage; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; @@ -32,7 +32,7 @@ public class HState implements Serializable { private final HTransition treeIncoming; private final int id; private final int depth; - private final ResizingObjectArray transitions; + private final ResizingArrayStorage> 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/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HTransition.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HTransition.java index a9272dadfe..f13c2a1151 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HTransition.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/hypothesis/HTransition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/mealy/DTLearnerMealy.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/mealy/DTLearnerMealy.java index ab34e37ea7..687e844754 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/mealy/DTLearnerMealy.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/mealy/DTLearnerMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,7 @@ import de.learnlib.api.query.Query; import de.learnlib.counterexamples.LocalSuffixFinder; import de.learnlib.datastructure.discriminationtree.MultiDTree; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/mealy/HypothesisWrapperMealy.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/mealy/HypothesisWrapperMealy.java index cca4eb28b2..cc064aa07d 100644 --- a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/mealy/HypothesisWrapperMealy.java +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/mealy/HypothesisWrapperMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import de.learnlib.algorithms.discriminationtree.hypothesis.DTLearnerHypothesis; import de.learnlib.algorithms.discriminationtree.hypothesis.HState; import de.learnlib.algorithms.discriminationtree.hypothesis.HTransition; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; final class HypothesisWrapperMealy diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAGrowingAlphabetTest.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAGrowingAlphabetTest.java index f98cc5e5e7..4fc8bdeb6d 100644 --- a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAGrowingAlphabetTest.java +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAIT.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAIT.java index 7a6512b216..0d6b3150e5 100644 --- a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAIT.java +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAResumableLearnerTest.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAResumableLearnerTest.java index e3153c6291..0e5e42e2a0 100644 --- a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAResumableLearnerTest.java +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerDFAResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyGrowingAlphabetTest.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyGrowingAlphabetTest.java index 1f86813408..335d8a8642 100644 --- a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyGrowingAlphabetTest.java +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyIT.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyIT.java index a1e4af1c48..abea8d6e3d 100644 --- a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyIT.java +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyResumableLearnerTest.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyResumableLearnerTest.java index 34dd836f00..01fe098952 100644 --- a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyResumableLearnerTest.java +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMealyResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/kearns-vazirani/pom.xml b/algorithms/active/kearns-vazirani/pom.xml index 5a2b08875c..160a0850b4 100644 --- a/algorithms/active/kearns-vazirani/pom.xml +++ b/algorithms/active/kearns-vazirani/pom.xml @@ -1,6 +1,6 @@ 4.0.0 + de.learnlib learnlib-algorithms-active-parent - 0.13.1 + 0.14.0 ../pom.xml + learnlib-kearns-vazirani + LearnLib :: Algorithms :: Kearns/Vazirani The automata learning algorithm described by Kearns & Vazirani @@ -40,6 +43,10 @@ limitations under the License. net.automatalib automata-core + + net.automatalib + automata-commons-smartcollections + de.learnlib @@ -57,16 +64,14 @@ limitations under the License. org.testng testng - test de.learnlib.testsupport learnlib-learner-it-support - test com.github.misberner.buildergen buildergen - \ No newline at end of file + diff --git a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/StateInfo.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/StateInfo.java index d2a476b940..75f92ffc3d 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/StateInfo.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/StateInfo.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -25,16 +27,18 @@ 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.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; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -49,9 +53,9 @@ * @author Malte Isberner */ public class KearnsVaziraniDFA - implements DFALearner, SupportsGrowingAlphabet, ResumableLearner> { + implements DFALearner, SupportsGrowingAlphabet, Resumable> { - private Alphabet alphabet; + private final Alphabet alphabet; private final MembershipOracle oracle; private final boolean repeatedCounterexampleEvaluation; private final AcexAnalyzer ceAnalyzer; @@ -110,6 +114,10 @@ public DFA getHypothesisModel() { return hypothesis; } + public BinaryDTree> getDiscriminationTree() { + return discriminationTree; + } + private boolean refineHypothesisSingle(Word input, boolean output) { int inputLen = input.length(); @@ -168,6 +176,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); @@ -177,8 +188,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)); } } @@ -199,7 +220,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); @@ -221,13 +242,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)); } } @@ -236,53 +261,69 @@ 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) { + + final List>> leaves = + discriminationTree.sift(starts, prefixes); + final ArrayStorage> result = new ArrayStorage<>(leaves.size()); - 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; + for (int i = 0; i < leaves.size(); i++) { + final AbstractWordBasedDTNode> leaf = leaves.get(i); - initState(succStateInfo); + 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 - 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 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); - } + // 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()); + for (final StateInfo si : this.stateInfos) { + transAs.add(si.accessSequence.append(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> succs = sift(transAs); - final StateInfo succ = sift(transAs); - setTransition(state, inputIdx, succ); + final Iterator> stateIter = this.stateInfos.iterator(); + final Iterator> leafsIter = succs.iterator(); + final int inputIdx = this.alphabet.getSymbolIndex(symbol); + + while (stateIter.hasNext() && leafsIter.hasNext()) { + setTransition(stateIter.next().id, inputIdx, leafsIter.next()); + } + + assert !stateIter.hasNext(); + assert !leafsIter.hasNext(); } } @@ -299,7 +340,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/dfa/KearnsVaziraniDFAState.java b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAState.java index 5ec0a18220..2b2369d482 100644 --- a/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAState.java +++ b/algorithms/active/kearns-vazirani/src/main/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -26,18 +28,18 @@ 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.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.AbstractWordBasedDiscriminationTree; import de.learnlib.datastructure.discriminationtree.model.LCAInfo; import de.learnlib.util.mealy.MealyUtil; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.SupportsGrowingAlphabet; +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; @@ -53,13 +55,13 @@ * @author Malte Isberner */ public class KearnsVaziraniMealy - implements MealyLearner, SupportsGrowingAlphabet, ResumableLearner> { + implements MealyLearner, SupportsGrowingAlphabet, Resumable> { - private Alphabet alphabet; + private final Alphabet alphabet; 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 +108,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(); @@ -182,6 +188,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); @@ -191,10 +200,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); - O output = hypothesis.getTransition(sourceState, transIdx).getOutput(); - setTransition(sourceState, transIdx, succInfo, output); + 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), + hypothesis.getTransition(sourceState, transIdx).getOutput()); } } @@ -206,7 +226,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; @@ -235,15 +255,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()); } } @@ -252,55 +277,73 @@ 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 - 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 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); - } + // 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))); + } - // 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>> 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 int inputIdx = this.alphabet.getSymbolIndex(symbol); - 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()); + } } } @@ -317,7 +360,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/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..31234bc150 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,8 +19,8 @@ import java.util.List; import de.learnlib.algorithms.kv.StateInfo; -import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree; -import net.automatalib.automata.transout.impl.compact.CompactMealy; +import de.learnlib.datastructure.discriminationtree.MultiDTree; +import net.automatalib.automata.transducers.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; } diff --git a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAGrowingAlphabetTest.java b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAGrowingAlphabetTest.java index f3e61969c2..556d3393e1 100644 --- a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAGrowingAlphabetTest.java +++ b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAIT.java b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAIT.java index 5bba0527c7..e206b4dc5d 100644 --- a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAIT.java +++ b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAResumableLearnerTest.java b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAResumableLearnerTest.java index f7bace6216..aef50c4155 100644 --- a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAResumableLearnerTest.java +++ b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/dfa/KearnsVaziraniDFAResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyGrowingAlphabetTest.java b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyGrowingAlphabetTest.java index 529b8114d0..47e1b55085 100644 --- a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyGrowingAlphabetTest.java +++ b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyIT.java b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyIT.java index 9053c583c1..17a788fc68 100644 --- a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyIT.java +++ b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyResumableLearnerTest.java b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyResumableLearnerTest.java index a93c037a72..17f5c5ada4 100644 --- a/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyResumableLearnerTest.java +++ b/algorithms/active/kearns-vazirani/src/test/java/de/learnlib/algorithms/kv/mealy/KearnsVaziraniMealyResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/pom.xml b/algorithms/active/lstar/pom.xml index ab86d1644b..e227181d19 100644 --- a/algorithms/active/lstar/pom.xml +++ b/algorithms/active/lstar/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-active-parent de.learnlib - 0.13.1 + learnlib-algorithms-active-parent + 0.14.0 ../pom.xml learnlib-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 @@ -37,6 +37,10 @@ limitations under the License. + + org.slf4j + slf4j-api + @@ -109,6 +113,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 d68b6043fb..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,18 +17,18 @@ import java.io.Serializable; import java.util.ArrayList; +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; import de.learnlib.datastructure.observationtable.Row; -import net.automatalib.automata.GrowableAlphabetAutomaton; +import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.MutableDeterministic; -import net.automatalib.commons.util.collections.CollectionsUtil; +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. @@ -49,8 +49,8 @@ * * @author Malte Isberner */ -public abstract class AbstractAutomatonLStar & GrowableAlphabetAutomaton> - extends AbstractLStar implements ResumableLearner> { +public abstract class AbstractAutomatonLStar & SupportsGrowingAlphabet> + extends AbstractLStar implements Resumable> { protected AI internalHyp; protected List> stateInfos = new ArrayList<>(); @@ -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(); } @@ -77,7 +77,7 @@ public A getHypothesisModel() { protected abstract A exposeInternalHypothesis(); @Override - public final void startLearning() { + public void startLearning() { super.startLearning(); updateInternalHypothesis(); } @@ -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 @@ -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); + } } } } @@ -186,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/AbstractExtensibleAutomatonLStar.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractExtensibleAutomatonLStar.java index 20a91b8f58..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -75,8 +75,12 @@ protected List> selectClosingRows(List>> unclosed) { public static final class BuilderDefaults { + private BuilderDefaults() { + // prevent instantiation + } + 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..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,16 +23,18 @@ 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.AbstractObservationTable; import de.learnlib.datastructure.observationtable.GenericObservationTable; import de.learnlib.datastructure.observationtable.Inconsistency; import de.learnlib.datastructure.observationtable.OTLearner; 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; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -56,9 +58,9 @@ public abstract class AbstractLStar implements OTLearner, GlobalSuffixLearner, SupportsGrowingAlphabet { - protected Alphabet alphabet; + protected final Alphabet alphabet; protected final MembershipOracle oracle; - protected GenericObservationTable table; + protected AbstractObservationTable table; /** * Constructor. @@ -114,7 +116,7 @@ protected List>> incorporateCounterExample(DefaultQuery ce) { } protected List> initialPrefixes() { - return Collections.singletonList(Word.epsilon()); + return Collections.singletonList(Word.epsilon()); } /** @@ -226,20 +228,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/AbstractLStarState.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/AbstractLStarState.java index 7a6b9418af..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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 8ad48478dd..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/ce/ObservationTableCEXHandler.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/ce/ObservationTableCEXHandler.java index a04987437e..78c7d1de27 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/ce/ObservationTableCEXHandler.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/ce/ObservationTableCEXHandler.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/ce/ObservationTableCEXHandlers.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/ce/ObservationTableCEXHandlers.java index e83a29d6fa..5846b8ae82 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/ce/ObservationTableCEXHandlers.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/ce/ObservationTableCEXHandlers.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/CloseRandomStrategy.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/CloseRandomStrategy.java index e97a06693d..2f9d2002ab 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/CloseRandomStrategy.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/CloseRandomStrategy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/ClosingStrategies.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/ClosingStrategies.java index 8b70025c6d..0f9bd6a8fa 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/ClosingStrategies.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/ClosingStrategies.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/ClosingStrategy.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/ClosingStrategy.java index eb4d129d61..a05c829cf0 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/ClosingStrategy.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/closing/ClosingStrategy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/ClassicLStarDFA.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/ClassicLStarDFA.java index a7a335ed68..b3b8b3ea9e 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/ClassicLStarDFA.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/ClassicLStarDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..74cda43349 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/LStarDFAUtil.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/LStarDFAUtil.java index f5131d183a..1624e7ea18 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/LStarDFAUtil.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/dfa/LStarDFAUtil.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/ClassicLStarMealy.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/ClassicLStarMealy.java index 49ab978a7a..32f9a0c73f 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/ClassicLStarMealy.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/ClassicLStarMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,10 +28,10 @@ import de.learnlib.datastructure.observationtable.Row; import de.learnlib.util.mealy.MealyUtil; import net.automatalib.automata.concepts.SuffixOutput; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.MutableMealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.automata.transout.impl.compact.CompactMealyTransition; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MutableMealyMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.automata.transducers.impl.compact.CompactMealyTransition; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/ExtensibleLStarMealy.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/ExtensibleLStarMealy.java index ce3f2e0d49..4e5b097107 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/ExtensibleLStarMealy.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/ExtensibleLStarMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,9 +29,9 @@ import de.learnlib.datastructure.observationtable.ObservationTable; import de.learnlib.datastructure.observationtable.Row; import net.automatalib.automata.concepts.SuffixOutput; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; -import net.automatalib.automata.transout.impl.compact.CompactMealyTransition; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.automata.transducers.impl.compact.CompactMealyTransition; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/LStarMealyUtil.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/LStarMealyUtil.java index 9bbd15af5f..cebf84edc9 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/LStarMealyUtil.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/LStarMealyUtil.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..729001ecb2 --- /dev/null +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/mealy/PartialLStarMealy.java @@ -0,0 +1,210 @@ +/* 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.exception.GrowingAlphabetNotSupportedException; +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) throws GrowingAlphabetNotSupportedException { + 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/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliDFA.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliDFA.java index b44424ff10..1f6bd3f631 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliDFA.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliMealy.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliMealy.java index 369615a836..4f1b60ff87 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliMealy.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireDFA.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireDFA.java index fafbd95db6..92930937cb 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireDFA.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireMealy.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireMealy.java index 0bb6a78d98..8c039fe0c1 100644 --- a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireMealy.java +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarDFAGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarDFAGrowingAlphabetTest.java index 4200010c4e..2daebecb78 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarDFAGrowingAlphabetTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarDFAGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarDFAResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarDFAResumableLearnerTest.java index d1521c0799..9109bbb70b 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarDFAResumableLearnerTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarDFAResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMealyGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMealyGrowingAlphabetTest.java index ea477460af..29ae2fc0b7 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMealyGrowingAlphabetTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMealyGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMealyResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMealyResumableLearnerTest.java index a2b2b847d8..ff8429c7c1 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMealyResumableLearnerTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMealyResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,8 @@ import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealyBuilder; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.testsupport.AbstractResumableLearnerMealyTest; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.automata.transducers.MealyMachine; +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; diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LStarDFATest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LStarDFATest.java index e35f18cc3b..e6dc5330d0 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LStarDFATest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LStarDFATest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LStarMealyTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LStarMealyTest.java index c53c14ee33..1654017f55 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LStarMealyTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LStarMealyTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ import de.learnlib.oracle.membership.SimulatorOracle; import de.learnlib.oracle.membership.SimulatorOracle.MealySimulatorOracle; import de.learnlib.util.mealy.MealyUtil; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import org.testng.annotations.Test; diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LearningTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LearningTest.java index 70c6dc203f..7e1d3a8600 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LearningTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/LearningTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliDFAGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliDFAGrowingAlphabetTest.java index 95086c9ccf..78fa992678 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliDFAGrowingAlphabetTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliDFAGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliDFAResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliDFAResumableLearnerTest.java index da53547c9a..27c9066153 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliDFAResumableLearnerTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliDFAResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMealyGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMealyGrowingAlphabetTest.java index 9c0c72427b..b7a36f31e6 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMealyGrowingAlphabetTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMealyGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMealyResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMealyResumableLearnerTest.java index 7e969ec43c..812f47c080 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMealyResumableLearnerTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMealyResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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/RivestSchapireDFAGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireDFAGrowingAlphabetTest.java index 0aae398ae5..3d58f1a84b 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireDFAGrowingAlphabetTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireDFAGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireDFAResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireDFAResumableLearnerTest.java index e06e4fb38c..5a2d4b44fb 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireDFAResumableLearnerTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireDFAResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMealyGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMealyGrowingAlphabetTest.java index fa114ff574..0f7acfd59e 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMealyGrowingAlphabetTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMealyGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMealyResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMealyResumableLearnerTest.java index 94d8673edd..951f6c0073 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMealyResumableLearnerTest.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMealyResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ClassicLStarMealyIT.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ClassicLStarMealyIT.java index c8a24ebdee..301a159932 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ClassicLStarMealyIT.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ClassicLStarMealyIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarDFAIT.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarDFAIT.java index 3d730fc73c..7978e389e0 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarDFAIT.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarDFAIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarMealyIT.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarMealyIT.java index 30474b4505..c58d52ce83 100644 --- a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarMealyIT.java +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarMealyIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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/algorithms/active/nlstar/pom.xml b/algorithms/active/nlstar/pom.xml index 124978483b..2352b83960 100644 --- a/algorithms/active/nlstar/pom.xml +++ b/algorithms/active/nlstar/pom.xml @@ -1,6 +1,6 @@ 4.0.0 + de.learnlib learnlib-algorithms-active-parent - 0.13.1 + 0.14.0 - LearnLib :: Algorithms :: NL* + learnlib-nlstar + + LearnLib :: Algorithms :: NL* A variant of the L* algorithm for inferring non-deterministic hypothesis automata. @@ -55,12 +58,10 @@ limitations under the License. de.learnlib.testsupport learnlib-learner-it-support - test org.testng testng - test de.learnlib @@ -68,4 +69,4 @@ limitations under the License. test - \ No newline at end of file + diff --git a/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/Inconsistency.java b/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/Inconsistency.java index e9715239d8..099fb8bc1b 100644 --- a/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/Inconsistency.java +++ b/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/Inconsistency.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/NLStarLearner.java b/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/NLStarLearner.java index 077c0ca938..0589f88aab 100644 --- a/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/NLStarLearner.java +++ b/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/NLStarLearner.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/ObservationTable.java b/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/ObservationTable.java index 0caea507c3..615544c8d1 100644 --- a/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/ObservationTable.java +++ b/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/ObservationTable.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -82,8 +82,8 @@ public List>> addSuffix(Word suffixToAdd) { return addSuffixes(Collections.singletonList(suffixToAdd)); } - private List>> makeUpper(Row row) { - return makeUpper(Collections.singletonList(row)); + private void makeUpper(Row row) { + makeUpper(Collections.singletonList(row)); } public List>> makeUpper(List> rows) { diff --git a/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/Row.java b/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/Row.java index c087e47f3c..c3ecd613cf 100644 --- a/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/Row.java +++ b/algorithms/active/nlstar/src/main/java/de/learnlib/algorithms/nlstar/Row.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/nlstar/src/test/java/de/learnlib/algorithms/nlstar/NLStarIT.java b/algorithms/active/nlstar/src/test/java/de/learnlib/algorithms/nlstar/NLStarIT.java index 379878eb83..362c4e07fe 100644 --- a/algorithms/active/nlstar/src/test/java/de/learnlib/algorithms/nlstar/NLStarIT.java +++ b/algorithms/active/nlstar/src/test/java/de/learnlib/algorithms/nlstar/NLStarIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/pom.xml b/algorithms/active/pom.xml index a9653ce25b..9934ea8215 100644 --- a/algorithms/active/pom.xml +++ b/algorithms/active/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-parent de.learnlib - 0.13.1 + learnlib-algorithms-parent + 0.14.0 ../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 cf2daf847c..230bd62370 100644 --- a/algorithms/active/ttt-vpda/pom.xml +++ b/algorithms/active/ttt-vpda/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-active-parent de.learnlib - 0.13.1 + learnlib-algorithms-active-parent + 0.14.0 ../pom.xml learnlib-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-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/ExtractRecord.java b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/ExtractRecord.java index 44d200bd47..beb53ebce4 100644 --- a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/ExtractRecord.java +++ b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/ExtractRecord.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/GlobalSplitter.java b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/GlobalSplitter.java index bdfdaa5040..69a4397b6f 100644 --- a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/GlobalSplitter.java +++ b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/GlobalSplitter.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/NonDetState.java b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/NonDetState.java index 3d73c64ad0..1dd6d8fe2c 100644 --- a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/NonDetState.java +++ b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/NonDetState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/NondetStackContents.java b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/NondetStackContents.java index 23073d033a..48b295bf9b 100644 --- a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/NondetStackContents.java +++ b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/NondetStackContents.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/OutputInconsistency.java b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/OutputInconsistency.java index 773dda3e04..5d2e7671e9 100644 --- a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/OutputInconsistency.java +++ b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/OutputInconsistency.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/Splitter.java b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/Splitter.java index 665dce28a1..8d77eb1494 100644 --- a/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/Splitter.java +++ b/algorithms/active/ttt-vpda/src/main/java/de/learnlib/algorithms/ttt/vpda/Splitter.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..ebbbafc626 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -623,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-vpda/src/test/java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerVPDAIT.java b/algorithms/active/ttt-vpda/src/test/java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerVPDAIT.java index d71a7bef90..aeadc82583 100644 --- a/algorithms/active/ttt-vpda/src/test/java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerVPDAIT.java +++ b/algorithms/active/ttt-vpda/src/test/java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerVPDAIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/pom.xml b/algorithms/active/ttt/pom.xml index 71d3e2e498..0f4857f423 100644 --- a/algorithms/active/ttt/pom.xml +++ b/algorithms/active/ttt/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-active-parent de.learnlib - 0.13.1 + learnlib-algorithms-active-parent + 0.14.0 ../pom.xml learnlib-ttt + LearnLib :: Algorithms :: TTT The TTT Algorithm @@ -74,10 +74,6 @@ limitations under the License. net.automatalib automata-commons-smartcollections - - net.automatalib - automata-commons-util - @@ -112,5 +108,4 @@ limitations under the License. buildergen - 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..45293ecdb7 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -45,6 +44,7 @@ public TTTState anySubtreeState() { return curr.data; } + @Override public AbstractBaseDTNode anyChild() { assert isInner(); return children.values().iterator().next(); @@ -55,7 +55,7 @@ public Iterable> subtreeStates() { } public Iterator> subtreeStatesIterator() { - return new TransformingLeavesIterator<>(this, AbstractBaseDTNode::getData); + return DiscriminationTreeIterators.transformingLeafIterator(this, AbstractBaseDTNode::getData); } public IncomingList getIncoming() { @@ -63,7 +63,7 @@ public IncomingList getIncoming() { } public Iterator> subtreeNodesIterator() { - return new NodesIterator<>(this); + return DiscriminationTreeIterators.nodeIterator(this); } /** 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 a6cd96ecbd..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,14 +22,15 @@ 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; import net.automatalib.visualization.VisualizationHelper; import net.automatalib.words.Alphabet; +import net.automatalib.words.GrowingAlphabet; import net.automatalib.words.impl.Alphabets; /** @@ -43,12 +44,13 @@ public abstract class AbstractTTTHypothesis implements DeterministicAutomaton, I, T>, FiniteAlphabetAutomaton, I, T>, DeterministicAutomaton.FullIntAbstraction, - GrowableAlphabetAutomaton, + SupportsGrowingAlphabet, Serializable { 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 e265e09a38..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,16 +34,17 @@ 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.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; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -57,9 +58,9 @@ * @author Malte Isberner */ public abstract class AbstractTTTLearner - implements LearningAlgorithm, SupportsGrowingAlphabet, ResumableLearner> { + implements LearningAlgorithm, SupportsGrowingAlphabet, Resumable> { - protected Alphabet alphabet; + protected final Alphabet alphabet; protected final MembershipOracle oracle; protected final AcexAnalyzer analyzer; /** @@ -149,7 +150,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); @@ -229,14 +230,8 @@ protected boolean refineHypothesisSingle(DefaultQuery ceQuery) { * the transition * @param tempDiscriminator * the temporary discriminator - * - * @return the discrimination tree node separating the old and the new node, labeled by the specified temporary - * discriminator */ - private AbstractBaseDTNode 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); @@ -259,8 +254,6 @@ private AbstractBaseDTNode splitState(TTTTransition transition, } notifyPostSplit(transition, tempDiscriminator); - - return dtNode; } private void splitState(OutputInconsistency outIncons) { @@ -443,11 +436,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; @@ -765,22 +758,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 +847,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 +864,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. * @@ -941,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); + + 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(); + this.closeTransitions(); + } } protected abstract AbstractBaseDTNode createNewNode(AbstractBaseDTNode parent, D parentOutput); @@ -982,7 +1026,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/base/BaseTTTDiscriminationTree.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BaseTTTDiscriminationTree.java index b84ab9d0f1..05e7237430 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BlockList.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BlockList.java index 178154e77c..12eb7699c3 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BlockList.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BlockList.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/HypothesisChangedException.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/HypothesisChangedException.java index cc364ea661..fa79e1b8d2 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/HypothesisChangedException.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/HypothesisChangedException.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/IncomingList.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/IncomingList.java index aad7449c99..c001b3cc19 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/IncomingList.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/IncomingList.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/OutputInconsistency.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/OutputInconsistency.java index df56f4f858..ec01fd9f03 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/OutputInconsistency.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/OutputInconsistency.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTEventListener.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTEventListener.java index bbf2132bca..6bce441722 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTEventListener.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTEventListener.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java index b370c5cab7..0f86d3fb62 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..d77ad73190 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ import java.io.Serializable; import de.learnlib.api.AccessSequenceProvider; -import net.automatalib.commons.util.array.ResizingObjectArray; +import net.automatalib.commons.smartcollections.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/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTTransition.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTTransition.java index 4de02c33d4..032d64d192 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTTransition.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTTransition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/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..67a13e9174 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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.smartcollections.ArrayStorage; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -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); @@ -176,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/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTDTNodeDFA.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTDTNodeDFA.java index 134489237c..0065b42365 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTDTNodeDFA.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTDTNodeDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java index f1b81e6466..a779aa6599 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTLearnerDFA.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTLearnerDFA.java index d1f624f36f..76f1063058 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTLearnerDFA.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTLearnerDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTStateDFA.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTStateDFA.java index c1382e7321..2bf9906ff3 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTStateDFA.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTStateDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTDTNodeMealy.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTDTNodeMealy.java index b45ec3aba0..d1e95bdd87 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTDTNodeMealy.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTDTNodeMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java index 68f0da6dff..28df55f9c8 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ import de.learnlib.algorithms.ttt.base.TTTState; import de.learnlib.algorithms.ttt.base.TTTTransition; import net.automatalib.automata.UniversalDeterministicAutomaton; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTLearnerMealy.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTLearnerMealy.java index 2bc9e20e9e..7d388bf122 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTLearnerMealy.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTLearnerMealy.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,7 @@ import de.learnlib.counterexamples.acex.MealyOutInconsPrefixTransformAcex; import de.learnlib.counterexamples.acex.OutInconsPrefixTransformAcex; import de.learnlib.util.mealy.MealyUtil; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; 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..0ebf99e888 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,6 +31,7 @@ public O getOutput() { return this.output; } + @Override public Object getProperty() { return output; } diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTDFAGrowingAlphabetTest.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTDFAGrowingAlphabetTest.java index 61a155c054..8a641e0b85 100644 --- a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTDFAGrowingAlphabetTest.java +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTDFAGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerDFAResumableLearnerTest.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerDFAResumableLearnerTest.java index 495dd91518..ba1c597a3e 100644 --- a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerDFAResumableLearnerTest.java +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerDFAResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMealyGrowingAlphabetTest.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMealyGrowingAlphabetTest.java index 87f08fc699..f7db6060ef 100644 --- a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMealyGrowingAlphabetTest.java +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMealyGrowingAlphabetTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMealyResumableLearnerTest.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMealyResumableLearnerTest.java index 18bbb643d8..5426c1fa8c 100644 --- a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMealyResumableLearnerTest.java +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMealyResumableLearnerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/dfa/it/PrefixTTTLearnerDFAIT.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/dfa/it/PrefixTTTLearnerDFAIT.java index 8fdaed183d..94c9a4303a 100644 --- a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/dfa/it/PrefixTTTLearnerDFAIT.java +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/dfa/it/PrefixTTTLearnerDFAIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerDFAIT.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerDFAIT.java index cbcc73e851..49ceaa32a8 100644 --- a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerDFAIT.java +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/dfa/it/TTTLearnerDFAIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/mealy/it/TTTLearnerMealyIT.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/mealy/it/TTTLearnerMealyIT.java index 4de3cea124..a0841c48bd 100644 --- a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/mealy/it/TTTLearnerMealyIT.java +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/mealy/it/TTTLearnerMealyIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/passive/pom.xml b/algorithms/passive/pom.xml index 47f483a8d7..b65837329f 100644 --- a/algorithms/passive/pom.xml +++ b/algorithms/passive/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-parent de.learnlib - 0.13.1 + learnlib-algorithms-parent + 0.14.0 ../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 c81b986d6e..fbdff84638 100644 --- a/algorithms/passive/rpni-edsm/pom.xml +++ b/algorithms/passive/rpni-edsm/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-passive-parent de.learnlib - 0.13.1 + learnlib-algorithms-passive-parent + 0.14.0 ../pom.xml learnlib-rpni-edsm + LearnLib :: Algorithms :: EDSM The EDSM passive learning algorithm @@ -70,10 +70,6 @@ limitations under the License. - - de.learnlib.testsupport - learnlib-learning-examples - de.learnlib.testsupport learnlib-learner-it-support @@ -93,5 +89,4 @@ limitations under the License. test - 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..6db297bdc0 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-edsm/src/main/java/de/learnlib/algorithms/rpni/EDSMUtil.java b/algorithms/passive/rpni-edsm/src/main/java/de/learnlib/algorithms/rpni/EDSMUtil.java index 931ca8a979..4a2d35110f 100644 --- a/algorithms/passive/rpni-edsm/src/main/java/de/learnlib/algorithms/rpni/EDSMUtil.java +++ b/algorithms/passive/rpni-edsm/src/main/java/de/learnlib/algorithms/rpni/EDSMUtil.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/passive/rpni-edsm/src/test/java/de/learnlib/algorithms/rpni/EDSMScoreTest.java b/algorithms/passive/rpni-edsm/src/test/java/de/learnlib/algorithms/rpni/EDSMScoreTest.java index 74d5195936..f121789eed 100644 --- a/algorithms/passive/rpni-edsm/src/test/java/de/learnlib/algorithms/rpni/EDSMScoreTest.java +++ b/algorithms/passive/rpni-edsm/src/test/java/de/learnlib/algorithms/rpni/EDSMScoreTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,7 +44,7 @@ public class EDSMScoreTest { private List negativeSamplesAsIntArray; @BeforeClass - public void setUp() throws Exception { + public void setUp() { alphabet = Alphabets.fromArray('a', 'b'); final Word p1 = Word.fromString("a"); diff --git a/algorithms/passive/rpni-edsm/src/test/java/de/learnlib/algorithms/rpni/it/EdsmDfaIT.java b/algorithms/passive/rpni-edsm/src/test/java/de/learnlib/algorithms/rpni/it/EdsmDfaIT.java index 80b0215d15..700c26def0 100644 --- a/algorithms/passive/rpni-edsm/src/test/java/de/learnlib/algorithms/rpni/it/EdsmDfaIT.java +++ b/algorithms/passive/rpni-edsm/src/test/java/de/learnlib/algorithms/rpni/it/EdsmDfaIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/passive/rpni-mdl/pom.xml b/algorithms/passive/rpni-mdl/pom.xml index 755a51262e..43d7dee42a 100644 --- a/algorithms/passive/rpni-mdl/pom.xml +++ b/algorithms/passive/rpni-mdl/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-passive-parent de.learnlib - 0.13.1 + learnlib-algorithms-passive-parent + 0.14.0 ../pom.xml learnlib-rpni-mdl + LearnLib :: Algorithms :: MDL The MDL passive learning algorithm @@ -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 @@ -87,5 +83,4 @@ limitations under the License. test - diff --git a/algorithms/passive/rpni-mdl/src/main/java/de/learnlib/algorithms/rpni/BlueFringeMDLDFA.java b/algorithms/passive/rpni-mdl/src/main/java/de/learnlib/algorithms/rpni/BlueFringeMDLDFA.java index b8d5fddc68..d71c6ee9a7 100644 --- a/algorithms/passive/rpni-mdl/src/main/java/de/learnlib/algorithms/rpni/BlueFringeMDLDFA.java +++ b/algorithms/passive/rpni-mdl/src/main/java/de/learnlib/algorithms/rpni/BlueFringeMDLDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/passive/rpni-mdl/src/main/java/de/learnlib/algorithms/rpni/MDLUtil.java b/algorithms/passive/rpni-mdl/src/main/java/de/learnlib/algorithms/rpni/MDLUtil.java index 4c8de4e19d..266c472666 100644 --- a/algorithms/passive/rpni-mdl/src/main/java/de/learnlib/algorithms/rpni/MDLUtil.java +++ b/algorithms/passive/rpni-mdl/src/main/java/de/learnlib/algorithms/rpni/MDLUtil.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/passive/rpni-mdl/src/test/java/de/learnlib/algorithms/rpni/MDLScoreTest.java b/algorithms/passive/rpni-mdl/src/test/java/de/learnlib/algorithms/rpni/MDLScoreTest.java index 36d8a52ccf..de0cfb93f1 100644 --- a/algorithms/passive/rpni-mdl/src/test/java/de/learnlib/algorithms/rpni/MDLScoreTest.java +++ b/algorithms/passive/rpni-mdl/src/test/java/de/learnlib/algorithms/rpni/MDLScoreTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -42,7 +42,7 @@ public class MDLScoreTest { private List positiveSamplesAsIntArray; @BeforeClass - public void setUp() throws Exception { + public void setUp() { alphabet = Alphabets.fromArray('a', 'b'); alphabetAsInt = Alphabets.fromArray(0, 1); 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..3ebcbff06e 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/algorithms/passive/rpni/pom.xml b/algorithms/passive/rpni/pom.xml index 2068feca23..55dbe59974 100644 --- a/algorithms/passive/rpni/pom.xml +++ b/algorithms/passive/rpni/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-algorithms-passive-parent de.learnlib - 0.13.1 + learnlib-algorithms-passive-parent + 0.14.0 ../pom.xml learnlib-rpni + LearnLib :: Algorithms :: RPNI The RPNI passive learning algorithm @@ -70,10 +70,6 @@ limitations under the License. - - de.learnlib.testsupport - learnlib-learning-examples - de.learnlib.testsupport learnlib-learner-it-support @@ -92,5 +88,4 @@ limitations under the License. buildergen - diff --git a/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/AbstractBlueFringeRPNI.java b/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/AbstractBlueFringeRPNI.java index 2b716e54df..fdb77eb8a2 100644 --- a/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/AbstractBlueFringeRPNI.java +++ b/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/AbstractBlueFringeRPNI.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/BlueFringeRPNIDFA.java b/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/BlueFringeRPNIDFA.java index c4d15cded5..bcd434fc33 100644 --- a/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/BlueFringeRPNIDFA.java +++ b/algorithms/passive/rpni/src/main/java/de/learnlib/algorithms/rpni/BlueFringeRPNIDFA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/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..0aa9d3102f 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,8 +22,8 @@ import de.learnlib.api.algorithm.PassiveLearningAlgorithm; import de.learnlib.api.query.DefaultQuery; import de.learnlib.datastructure.pta.pta.BlueFringePTA; -import net.automatalib.automata.transout.MealyMachine; -import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; import net.automatalib.commons.util.Pair; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -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/algorithms/passive/rpni/src/test/java/de/learnlib/algorithms/rpni/it/RpniDfaIT.java b/algorithms/passive/rpni/src/test/java/de/learnlib/algorithms/rpni/it/RpniDfaIT.java index 3490008390..e0ad2961af 100644 --- a/algorithms/passive/rpni/src/test/java/de/learnlib/algorithms/rpni/it/RpniDfaIT.java +++ b/algorithms/passive/rpni/src/test/java/de/learnlib/algorithms/rpni/it/RpniDfaIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/algorithms/passive/rpni/src/test/java/de/learnlib/algorithms/rpni/it/RpniMealyIT.java b/algorithms/passive/rpni/src/test/java/de/learnlib/algorithms/rpni/it/RpniMealyIT.java index f1e2062804..1e2333a597 100644 --- a/algorithms/passive/rpni/src/test/java/de/learnlib/algorithms/rpni/it/RpniMealyIT.java +++ b/algorithms/passive/rpni/src/test/java/de/learnlib/algorithms/rpni/it/RpniMealyIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ import de.learnlib.algorithms.rpni.BlueFringeRPNIMealy; import de.learnlib.testsupport.it.learner.AbstractMealyPassiveLearnerIT; import de.learnlib.testsupport.it.learner.PassiveLearnerVariantList; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; diff --git a/algorithms/pom.xml b/algorithms/pom.xml index 686a169ccf..793b680f54 100644 --- a/algorithms/pom.xml +++ b/algorithms/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-build-parent de.learnlib - 0.13.1 + learnlib-build-parent + 0.14.0 ../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 ebf60c1e05..69de878ce2 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,6 +1,6 @@ @@ -81,6 +82,10 @@ limitations under the License. logback-classic test + + org.mockito + mockito-core + test + - diff --git a/api/src/main/java/de/learnlib/api/AccessSequenceProvider.java b/api/src/main/java/de/learnlib/api/AccessSequenceProvider.java index d7dc8e3c53..6986914933 100644 --- a/api/src/main/java/de/learnlib/api/AccessSequenceProvider.java +++ b/api/src/main/java/de/learnlib/api/AccessSequenceProvider.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/AccessSequenceTransformer.java b/api/src/main/java/de/learnlib/api/AccessSequenceTransformer.java index b7b885c3d3..658126b15f 100644 --- a/api/src/main/java/de/learnlib/api/AccessSequenceTransformer.java +++ b/api/src/main/java/de/learnlib/api/AccessSequenceTransformer.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/Mapper.java b/api/src/main/java/de/learnlib/api/Mapper.java index 37feefd7aa..f4321f65de 100644 --- a/api/src/main/java/de/learnlib/api/Mapper.java +++ b/api/src/main/java/de/learnlib/api/Mapper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/ObservableSUL.java b/api/src/main/java/de/learnlib/api/ObservableSUL.java new file mode 100644 index 0000000000..2e0ba58bf6 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/ObservableSUL.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.api; + +import javax.annotation.Nonnull; + +/** + * A System Under Learning (SUL) where at any point in time the internal state can be observed. + * + * The main purpose of this interface is to check whether infinite words are accepted by the SUL. + * + * @param the state type + * @param the input type + * @param the output type + * + * @author Jeroen Meijer + */ +public interface ObservableSUL extends SUL { + + @Nonnull + @Override + default ObservableSUL fork() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /** + * Returns the current state of the system. + * + * Implementation note: it is important that the returned Object has a well-defined {@link Object#equals(Object)} + * method, and a good {@link Object#hashCode()} function. + * + * @return the current state of the system. + */ + @Nonnull + S getState(); + + /** + * Returns whether each state retrieved with {@link #getState()} is a deep copy. + * + * A state is a deep copy if calls to either {@link #step(Object)}, {@link #pre()}, or {@link #post()} do not modify + * any state previously obtained with {@link #getState()}. + * + * More formally (assuming a perfect hash function): the result must be false if there is a case where in the + * following statements the assertion does not hold: + * {@code Object o = getState(); int hc = o.hashCode(); [step(...)|pre()|post()]; assert o.hashCode() == hc;} + * + * Furthermore, if states can be retrieved, but each state is not a deep copy, then this SUL must be + * forkable, i.e. if !{@link #deepCopies()} then {@link #canFork()} must hold. + * + * @return whether each state is a deep copy. + */ + default boolean deepCopies() { + return false; + } +} 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 53% 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 6729e0184a..505778e271 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/feature/ResumableLearner.java +++ b/api/src/main/java/de/learnlib/api/Resumable.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/api/src/main/java/de/learnlib/api/SUL.java b/api/src/main/java/de/learnlib/api/SUL.java index 9b8a2cf283..d0a0438c65 100644 --- a/api/src/main/java/de/learnlib/api/SUL.java +++ b/api/src/main/java/de/learnlib/api/SUL.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -87,4 +87,5 @@ default boolean canFork() { default SUL fork() throws UnsupportedOperationException { throw new UnsupportedOperationException(); } + } 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/algorithm/LearningAlgorithm.java b/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java index 8c2dbffa9c..0af262e33e 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java +++ b/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; /** @@ -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/algorithm/NFALearner.java b/api/src/main/java/de/learnlib/api/algorithm/NFALearner.java index 53322b89b1..f0ed72fdb4 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/NFALearner.java +++ b/api/src/main/java/de/learnlib/api/algorithm/NFALearner.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/algorithm/PassiveLearningAlgorithm.java b/api/src/main/java/de/learnlib/api/algorithm/PassiveLearningAlgorithm.java index a756a10090..badcc38215 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/PassiveLearningAlgorithm.java +++ b/api/src/main/java/de/learnlib/api/algorithm/PassiveLearningAlgorithm.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,7 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.fsa.FiniteStateAcceptor; import net.automatalib.automata.fsa.NFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; public interface PassiveLearningAlgorithm { diff --git a/api/src/main/java/de/learnlib/api/algorithm/feature/GlobalSuffixFeature.java b/api/src/main/java/de/learnlib/api/algorithm/feature/GlobalSuffixFeature.java index b1aef7d11a..78247f79b4 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/feature/GlobalSuffixFeature.java +++ b/api/src/main/java/de/learnlib/api/algorithm/feature/GlobalSuffixFeature.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/algorithm/feature/GlobalSuffixLearner.java b/api/src/main/java/de/learnlib/api/algorithm/feature/GlobalSuffixLearner.java index c7edbbac08..bfc35faadc 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/feature/GlobalSuffixLearner.java +++ b/api/src/main/java/de/learnlib/api/algorithm/feature/GlobalSuffixLearner.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; /** diff --git a/api/src/main/java/de/learnlib/api/exception/SULException.java b/api/src/main/java/de/learnlib/api/exception/SULException.java index 95dc21dfa9..9f85755704 100644 --- a/api/src/main/java/de/learnlib/api/exception/SULException.java +++ b/api/src/main/java/de/learnlib/api/exception/SULException.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/logging/Category.java b/api/src/main/java/de/learnlib/api/logging/Category.java index 5a72c6518e..6e5e00314f 100644 --- a/api/src/main/java/de/learnlib/api/logging/Category.java +++ b/api/src/main/java/de/learnlib/api/logging/Category.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/logging/LearnLogger.java b/api/src/main/java/de/learnlib/api/logging/LearnLogger.java index e06daac954..69210b7281 100644 --- a/api/src/main/java/de/learnlib/api/logging/LearnLogger.java +++ b/api/src/main/java/de/learnlib/api/logging/LearnLogger.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java b/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java new file mode 100644 index 0000000000..f079119309 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/logging/LoggingPropertyOracle.java @@ -0,0 +1,137 @@ +/* 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.logging; + +import java.util.Collection; + +import javax.annotation.Nullable; + +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.transducers.MealyMachine; +import net.automatalib.exception.ModelCheckingException; +import net.automatalib.words.Word; + +/** + * A PropertyOracle that performs logging. + * + * 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 input type + * @param the automaton type + * @param

the property type + * @param the output type + */ +public class LoggingPropertyOracle, P, D> implements PropertyOracle { + + private static final LearnLogger LOGGER = LearnLogger.getLogger(LoggingPropertyOracle.class); + + /** + * The wrapped {@link PropertyOracle}. + */ + private final PropertyOracle propertyOracle; + + /** + * Constructs a new LoggingPropertyOracle. + * + * @param propertyOracle the {@link PropertyOracle} to wrap around. + */ + public LoggingPropertyOracle(PropertyOracle propertyOracle) { + this.propertyOracle = propertyOracle; + } + + @Override + public boolean isDisproved() { + return propertyOracle.isDisproved(); + } + + @Override + public void setProperty(P property) { + this.propertyOracle.setProperty(property); + } + + @Override + public P getProperty() { + return propertyOracle.getProperty(); + } + + @Nullable + @Override + public DefaultQuery getCounterExample() { + return propertyOracle.getCounterExample(); + } + + /** + * Try to disprove this propertyOracle, and log whenever it is disproved. + * + * @see PropertyOracle#disprove(Output, Collection) + */ + @Nullable + @Override + public DefaultQuery disprove(A hypothesis, Collection inputs) throws ModelCheckingException { + final DefaultQuery result = propertyOracle.disprove(hypothesis, inputs); + if (result != null) { + LOGGER.logEvent("Property violated: '" + toString() + "'"); + LOGGER.logQuery("Counter example for property: " + getCounterExample()); + } + + return result; + } + + /** + * Try to find a counterexample to the given hypothesis, and log whenever such a spurious counterexample is found. + * + * @see PropertyOracle#findCounterExample(Object, Collection) + */ + @Nullable + @Override + public DefaultQuery doFindCounterExample(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); + } + return result; + } + + @Override + public String toString() { + return propertyOracle.getProperty().toString(); + } + + public static class DFALoggingPropertyOracle extends LoggingPropertyOracle, P, Boolean> + implements DFAPropertyOracle { + + public DFALoggingPropertyOracle(DFAPropertyOracle property) { + super(property); + } + } + + public static class MealyLoggingPropertyOracle + extends LoggingPropertyOracle, P, Word> + implements MealyPropertyOracle { + + public MealyLoggingPropertyOracle(MealyPropertyOracle property) { + super(property); + } + } +} 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..03cc5b626c 100644 --- a/api/src/main/java/de/learnlib/api/logging/Slf4jDelegator.java +++ b/api/src/main/java/de/learnlib/api/logging/Slf4jDelegator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; - } } diff --git a/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java b/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.java new file mode 100644 index 0000000000..c7b894d0b9 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/AutomatonOracle.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.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 net.automatalib.automata.DeterministicAutomaton; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.words.Word; + +/** + * 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 + * + * @author Jeroen Meijer + */ +@ParametersAreNonnullByDefault +public interface AutomatonOracle, I, D> { + + /** + * Returns whether the given input and output is a counter example for the given hypothesis. + * + * @param hypothesis + * the hypothesis + * @param inputs + * the input sequence + * @param output + * the output corresponding to the input. + * + * @return whether the given input and output is a counter example. + */ + boolean isCounterExample(A hypothesis, Iterable inputs, @Nullable D output); + + /** + * 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 the next input word, or {@code null} if t here is no next input. + */ + @Nullable + Word nextInput(); + + /** + * Add a new input word. + *

+ * Implementations could add words to e.g. a {@link Stack}, or {@link Queue}. + * + * @param input + * the input word to add. + */ + void addWord(Word input); + + /** + * Setup method which is called immediately before + * {@link #findCounterExample(DeterministicAutomaton, Collection, int)} is called. + */ + void pre(); + + /** + * 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 multiplier + */ + double getMultiplier(); + + /** + * @see #getMultiplier() + * @param multiplier + * the multiplier + */ + void setMultiplier(double multiplier); + + /** + * Processes the given input. Implementations could use membership oracles to process the query. + * + * @param hypothesis + * the hypothesis. + * @param input + * the input to process. + * + * @return the processed query. + */ + DefaultQuery processInput(A hypothesis, Word input); + + /** + * 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 i : inputs) { + final Word word = prefix.append(i); + + // skip undefined inputs + if (!hypothesis.getStates(word).isEmpty()) { + addWord(word); + } + } + } + + /** + * Returns whether the given input is accepted by the given hypothesis. + * + * @param hypothesis + * the hypothesis automaton. + * @param input + * the input. + * @param length + * the length of the input. + * + * @return whether the given input is accepted. + */ + boolean accepts(A hypothesis, Iterable input, int length); + + /** + * Find a counterexample for a given {@code hypothesis}. + * + * @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 counter example does not exist. + */ + @Nullable + default DefaultQuery findCounterExample(A hypothesis, Collection inputs, int maxQueries) { + pre(); + DefaultQuery ce = null; + + 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, query.getInput(), query.getOutput()) ? query : null; + } + queries++; + } + } + + return ce; + } + + /** + * Finds a counter example to the given hypothesis. By default the maximum number of queries performed are + * {@code hypothesis.size() * getMultiplier()}. + * + * @param hypothesis + * the hypothesis automaton. + * @param inputs + * the input alphabet. + * + * @return the counter example, or {@code null} if a counter example does not exist + */ + @Nullable + default DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + return findCounterExample(hypothesis, inputs, (int) (hypothesis.size() * getMultiplier())); + } + + interface DFAOracle extends AutomatonOracle, I, Boolean> { + + @Override + default boolean accepts(DFA hypothesis, Iterable input, int length) { + return hypothesis.accepts(input); + } + } + + interface MealyOracle extends AutomatonOracle, I, Word> { + + @Override + default boolean accepts(MealyMachine hypothesis, Iterable input, int length) { + return hypothesis.computeOutput(input) != null; + } + } +} diff --git a/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java b/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java new file mode 100644 index 0000000000..b80b66f9dc --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/BlackBoxOracle.java @@ -0,0 +1,51 @@ +/* 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.List; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.words.Word; + +/** + * 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 + */ +@ParametersAreNonnullByDefault +public interface BlackBoxOracle, I, D> extends InclusionOracle { + + /** + * Returns the property oracles that this black-box oracle uses to evaluate properties. + * + * @return the property oracles. + */ + List> getPropertyOracles(); + + interface DFABlackBoxOracle extends BlackBoxOracle, I, Boolean> {} + + 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 new file mode 100644 index 0000000000..b65e87a04b --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/EmptinessOracle.java @@ -0,0 +1,58 @@ +/* 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.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 net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transducers.MealyMachine; +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 + * 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 + * @param + * the input type + * @param + * the output type + * + * @author Jeroen Meijer + */ +@ParametersAreNonnullByDefault +public interface EmptinessOracle, I, D> { + + default boolean isCounterExample(Output hypothesis, Iterable input, @Nullable D output) { + return Objects.equals(hypothesis.computeOutput(input), output); + } + + @Nullable + DefaultQuery findCounterExample(A hypothesis, Collection inputs); + + interface DFAEmptinessOracle extends EmptinessOracle, I, Boolean> {} + + interface MealyEmptinessOracle extends EmptinessOracle, I, Word> {} +} 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..2cb7c2b0dd 100644 --- a/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; /** @@ -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/api/src/main/java/de/learnlib/api/oracle/Filter.java b/api/src/main/java/de/learnlib/api/oracle/Filter.java index cee8febbe4..53c3e2cf31 100644 --- a/api/src/main/java/de/learnlib/api/oracle/Filter.java +++ b/api/src/main/java/de/learnlib/api/oracle/Filter.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java b/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.java new file mode 100644 index 0000000000..16df4bad03 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/InclusionOracle.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.api.oracle; + +import java.util.Objects; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.SUL; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.words.Word; + +/** + * 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. + * + * 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 + * + * @author Jeroen Meijer + */ +@ParametersAreNonnullByDefault +public interface InclusionOracle, I, D> extends EquivalenceOracle { + + default boolean isCounterExample(Output hypothesis, Iterable input, @Nullable D output) { + return !Objects.equals(hypothesis.computeOutput(input), output); + } + + interface DFAInclusionOracle extends InclusionOracle, I, Boolean>, DFAEquivalenceOracle {} + + 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..cd27a0e6ff --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/LassoEmptinessOracle.java @@ -0,0 +1,51 @@ +/* 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 net.automatalib.modelchecking.Lasso; +import net.automatalib.modelchecking.Lasso.DFALasso; +import net.automatalib.modelchecking.Lasso.MealyLasso; +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 { + + /** + * 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 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..3faab0bb7a --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/LassoOracle.java @@ -0,0 +1,103 @@ +/* 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.Collection; + +import javax.annotation.Nullable; + +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +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; + +/** + * 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> { + + /** + * Processes the given omega query. + * + * @param prefix + * the prefix + * @param loop + * the loop + * @param repeat + * the maximum number of times the loop may be repeated + * + * @return the omega query. + */ + OmegaQuery processInput(Word prefix, Word loop, int repeat); + + /** + * Returns whether the given input and output is a counter example for the given hypothesis. + * + * @param hypothesis + * the hypothesis + * @param inputs + * the input sequence + * @param output + * the output corresponding to the input. + * + * @return whether the given input and output is a counter example. + */ + boolean isCounterExample(Output hypothesis, Iterable inputs, @Nullable D output); + + /** + * Returns whether a lasso that is ultimately periodic could serve as a counter example. + * + * @param isUltimatelyPeriodic + * whether the lasso is ultimately periodic + * + * @return true when lasso that is ultimately periodic could serve as a counter example, false otherwise. + */ + boolean isOmegaCounterExample(boolean isUltimatelyPeriodic); + + @Nullable + default DefaultQuery findCounterExample(L hypothesis, Collection inputs) { + final Word prefix = hypothesis.getPrefix(); + final Word loop = hypothesis.getLoop(); + final int repeat = hypothesis.getUnfolds(); + + 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/MembershipOracle.java b/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java index eb6424166b..001785f9bb 100644 --- a/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/OmegaMembershipOracle.java b/api/src/main/java/de/learnlib/api/oracle/OmegaMembershipOracle.java new file mode 100644 index 0000000000..3bd25dd2c8 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/OmegaMembershipOracle.java @@ -0,0 +1,94 @@ +/* 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.Collection; +import java.util.Collections; + +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.ObservableSUL; +import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.query.OmegaQuery; +import net.automatalib.commons.util.Pair; +import net.automatalib.words.Word; + +/** + * Answers {@link OmegaQuery}s, similar to a {@link MembershipOracle}. Additionally, one can ask whether two states + * are equal to each other. + * + * @author Jeroen Meijer + * + * @param the state type + * @param the input type + * @param the output type + */ +@ParametersAreNonnullByDefault +public interface OmegaMembershipOracle extends OmegaQueryAnswerer { + + @Override + default Pair answerQuery(Word prefix, Word loop, int repeat) { + final OmegaQuery query = new OmegaQuery<>(prefix, loop, repeat); + processQuery(query); + return Pair.of(query.getOutput(), query.getPeriodicity()); + } + + default void processQuery(OmegaQuery query) { + processQueries(Collections.singleton(query)); + } + + 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. + * + * @see ObservableSUL#getState() + * + * @param w1 the first access sequence. + * @param s1 the first state. + * @param w2 the second access sequence. + * @param s2 the second state. + * + * @return whether both states, or states via the given access sequences are equal. + */ + boolean isSameState(Word w1, S s1, Word w2, S s2); + + interface DFAOmegaMembershipOracle extends OmegaMembershipOracle { + + @Override + DFAMembershipOracle getMembershipOracle(); + } + + interface MealyOmegaMembershipOracle extends OmegaMembershipOracle> { + + @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 new file mode 100644 index 0000000000..a6342453a3 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/OmegaQueryAnswerer.java @@ -0,0 +1,38 @@ +/* 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 javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.automatalib.commons.util.Pair; +import net.automatalib.words.Word; + +/** + * Answers {@link de.learnlib.api.query.OmegaQuery}s. + * + * @author Jeroen Meijer + * @see OmegaMembershipOracle + * @see QueryAnswerer + */ +public interface OmegaQueryAnswerer { + + @Nullable + 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..2457794398 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/PropertyOracle.java @@ -0,0 +1,122 @@ +/* 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.Collection; + +import javax.annotation.Nullable; +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.transducers.MealyMachine; +import net.automatalib.words.Word; + +/** + * A {@link PropertyOracle} can disprove a property, and used to find a counter example to an hypothesis. + *

+ * 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 + * @param the automaton type + * @param

the property type + * @param the output type + * + * @author Jeroen Meijer + */ +@ParametersAreNonnullByDefault +public interface PropertyOracle, P, D> extends InclusionOracle { + + /** + * 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(Output, 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} 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 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 doFindCounterExample(A hypothesis, Collection inputs); + + interface DFAPropertyOracle extends PropertyOracle, P, Boolean>, DFAInclusionOracle {} + + interface MealyPropertyOracle + extends PropertyOracle, P, Word>, MealyInclusionOracle {} +} + diff --git a/api/src/main/java/de/learnlib/api/oracle/QueryAnswerer.java b/api/src/main/java/de/learnlib/api/oracle/QueryAnswerer.java index 36fc68094b..1f6ce5f421 100644 --- a/api/src/main/java/de/learnlib/api/oracle/QueryAnswerer.java +++ b/api/src/main/java/de/learnlib/api/oracle/QueryAnswerer.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java b/api/src/main/java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java new file mode 100644 index 0000000000..f931b851a1 --- /dev/null +++ b/api/src/main/java/de/learnlib/api/oracle/SingleQueryOmegaOracle.java @@ -0,0 +1,48 @@ +/* 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.Collection; + +import de.learnlib.api.query.OmegaQuery; +import net.automatalib.commons.util.Pair; +import net.automatalib.words.Word; + +/** + * An {@link OmegaMembershipOracle} that answers single queries. + * + * @author Jeroen Meijer + * + * @see OmegaMembershipOracle + * @see SingleQueryOracle + */ +public interface SingleQueryOmegaOracle extends OmegaMembershipOracle { + + @Override + 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) { + queries.forEach(this::processQuery); + } + + interface SingleQueryOmegaOracleDFA extends SingleQueryOmegaOracle, DFAOmegaMembershipOracle {} + + interface SingleQueryOmegaOracleMealy extends SingleQueryOmegaOracle>, MealyOmegaMembershipOracle {} +} diff --git a/api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java b/api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java index 59677a5e3b..71668afea1 100644 --- a/api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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/api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java b/api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java index c8314fd78b..1335d87c03 100644 --- a/api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/SymbolQueryOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/AbstractQuery.java b/api/src/main/java/de/learnlib/api/query/AbstractQuery.java index f9f7a298ef..297351f528 100644 --- a/api/src/main/java/de/learnlib/api/query/AbstractQuery.java +++ b/api/src/main/java/de/learnlib/api/query/AbstractQuery.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/query/DefaultQuery.java b/api/src/main/java/de/learnlib/api/query/DefaultQuery.java index f8297a6885..c99f1db48f 100644 --- a/api/src/main/java/de/learnlib/api/query/DefaultQuery.java +++ b/api/src/main/java/de/learnlib/api/query/DefaultQuery.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/query/OmegaQuery.java b/api/src/main/java/de/learnlib/api/query/OmegaQuery.java new file mode 100644 index 0000000000..2def1dc42f --- /dev/null +++ b/api/src/main/java/de/learnlib/api/query/OmegaQuery.java @@ -0,0 +1,131 @@ +/* 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.query; + +import java.util.Objects; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import de.learnlib.api.ObservableSUL; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; + +/** + * 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. + * + * @param + * the input type + * @param + * the output type + * + * @see DefaultQuery + * @see Query + * @see ObservableSUL#getState() + */ +@ParametersAreNonnullByDefault +public class OmegaQuery { + + private final Word prefix; + private final Word loop; + private final int repeat; + + private D output; + private int periodicity; + + public OmegaQuery(Word prefix, Word loop, int repeat) { + this.prefix = prefix; + this.loop = loop; + this.repeat = repeat; + } + + public void answer(D output, int periodicity) { + this.output = output; + this.periodicity = periodicity; + } + + public Word getPrefix() { + return prefix; + } + + public Word getLoop() { + return loop; + } + + public int getRepeat() { + return repeat; + } + + @Nullable + public D getOutput() { + return output; + } + + public int getPeriodicity() { + return periodicity; + } + + public boolean isUltimatelyPeriodic() { + return periodicity > 0; + } + + 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); + } + + @Override + public String toString() { + return "OmegaQuery{" + "prefix=" + prefix + ", loop=" + loop + ", repeat=" + repeat + ", output=" + output + + ", periodicity=" + periodicity + '}'; + } + + @Override + public final boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof OmegaQuery)) { + return false; + } + + 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 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 0c9cc80f97..520bfeec77 100644 --- a/api/src/main/java/de/learnlib/api/query/Query.java +++ b/api/src/main/java/de/learnlib/api/query/Query.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,13 +15,15 @@ */ package de.learnlib.api.query; +import java.util.Objects; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.oracle.MembershipOracle; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; /** @@ -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/api/src/main/java/de/learnlib/api/setting/LearnLibSettingsSource.java b/api/src/main/java/de/learnlib/api/setting/LearnLibSettingsSource.java index 162316fd99..7721ec196d 100644 --- a/api/src/main/java/de/learnlib/api/setting/LearnLibSettingsSource.java +++ b/api/src/main/java/de/learnlib/api/setting/LearnLibSettingsSource.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/main/java/de/learnlib/api/statistic/StatisticData.java b/api/src/main/java/de/learnlib/api/statistic/StatisticData.java index 92c26dc4ee..0f3494472e 100644 --- a/api/src/main/java/de/learnlib/api/statistic/StatisticData.java +++ b/api/src/main/java/de/learnlib/api/statistic/StatisticData.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..137f82e49d --- /dev/null +++ b/api/src/main/java/de/learnlib/api/statistic/StatisticLearner.java @@ -0,0 +1,45 @@ +/* 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.statistic; + +import javax.annotation.Nonnull; + +import de.learnlib.api.algorithm.LearningAlgorithm; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transducers.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..87ed4d46c3 100644 --- a/api/src/main/java/de/learnlib/api/statistic/StatisticOracle.java +++ b/api/src/main/java/de/learnlib/api/statistic/StatisticOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/api/src/main/java/de/learnlib/api/statistic/StatisticSUL.java b/api/src/main/java/de/learnlib/api/statistic/StatisticSUL.java index cc9c058cb1..a5c191908d 100644 --- a/api/src/main/java/de/learnlib/api/statistic/StatisticSUL.java +++ b/api/src/main/java/de/learnlib/api/statistic/StatisticSUL.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/api/src/test/java/de/learnlib/api/logging/LearnLoggerTest.java b/api/src/test/java/de/learnlib/api/logging/LearnLoggerTest.java index 0dfd164e4b..385dca90ac 100644 --- a/api/src/test/java/de/learnlib/api/logging/LearnLoggerTest.java +++ b/api/src/test/java/de/learnlib/api/logging/LearnLoggerTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/archetypes/basic/pom.xml b/archetypes/basic/pom.xml index cd4c43efad..9ed0e82cb3 100644 --- a/archetypes/basic/pom.xml +++ b/archetypes/basic/pom.xml @@ -1,6 +1,6 @@ @@ -41,6 +41,4 @@ limitations under the License. test - - diff --git a/archetypes/basic/src/main/resources-template/META-INF/maven/archetype-metadata.xml b/archetypes/basic/src/main/resources-template/META-INF/maven/archetype-metadata.xml index 4ae49c64b5..a8c86d0c9b 100644 --- a/archetypes/basic/src/main/resources-template/META-INF/maven/archetype-metadata.xml +++ b/archetypes/basic/src/main/resources-template/META-INF/maven/archetype-metadata.xml @@ -1,6 +1,6 @@ 4.0.0 @@ -27,7 +11,7 @@ limitations under the License. UTF-8 - + 1.8 1.8 @@ -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/pom.xml b/archetypes/complete/pom.xml index cbed117de2..3fd24a3c28 100644 --- a/archetypes/complete/pom.xml +++ b/archetypes/complete/pom.xml @@ -1,6 +1,6 @@ @@ -42,4 +42,3 @@ limitations under the License. - 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 a5cc3f9cbe..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 @@ -1,6 +1,6 @@ 4.0.0 @@ -27,7 +11,7 @@ limitations under the License. UTF-8 - + 1.8 1.8 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 3d64afea06..96c999179c 100644 --- a/archetypes/pom.xml +++ b/archetypes/pom.xml @@ -1,6 +1,6 @@ @@ -73,15 +64,33 @@ limitations under the License. true - maven-archetype-plugin ${archetype-plugin.version} + + org.apache.maven.plugins + maven-dependency-plugin + + + + analyze + + true + + + + + + + org.apache.maven.archetype + archetype-packaging + ${archetype-plugin.version} + + - diff --git a/build-parent/pom.xml b/build-parent/pom.xml index b496ab0083..9bfdfabe6f 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -1,6 +1,6 @@ + + org.jacoco + jacoco-maven-plugin + + + + **/ADTLearnerBuilder.class + **/MealyDHCBuilder.class + **/DTLearner*Builder.class + **/DTLearnerVPDABuilder.class + **/KearnsVazirani*Builder.class + **/ClassicLStar*Builder.class + **/ExtensibleLStar*Builder.class + **/PartialLStarMealyBuilder.class + **/MalerPnueli*Builder.class + **/RivestSchapire*Builder.class + **/NLStarLearnerBuilder.class + **/TTTLearner*Builder.class + **/TTTLearnerVPDABuilder.class + + + + + + @@ -44,21 +74,68 @@ limitations under the License. + + + + com.github.spotbugs + spotbugs-maven-plugin + + /learnlib-spotbugs-exclusions.xml + Max + + + + de.learnlib + learnlib-build-tools + ${project.version} + + + + + org.apache.maven.plugins + maven-pmd-plugin + + + /learnlib-pmd-ruleset.xml + + + + + de.learnlib + learnlib-build-tools + ${project.version} + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + /automatalib-learnlib-checkstyle.xml + /license-header-java.txt + /learnlib-checkstyle-suppressions.xml + true + false + + + + com.puppycrawl.tools + checkstyle + ${checkstyle.version} + + + de.learnlib + learnlib-build-tools + ${project.version} + + + + + - org.codehaus.mojo - findbugs-maven-plugin - - /learnlib-findbugs-exclusions.xml - Max - - - - de.learnlib - learnlib-build-tools - ${project.version} - - + com.github.spotbugs + spotbugs-maven-plugin verify @@ -102,18 +179,6 @@ limitations under the License. org.apache.maven.plugins maven-pmd-plugin - - - /learnlib-pmd-ruleset.xml - - - - - de.learnlib - learnlib-build-tools - ${project.version} - - pmd @@ -133,25 +198,6 @@ limitations under the License. org.apache.maven.plugins maven-checkstyle-plugin - - /automatalib-learnlib-checkstyle.xml - /license-header-java.txt - /learnlib-checkstyle-suppressions.xml - true - false - - - - com.puppycrawl.tools - checkstyle - ${checkstyle.version} - - - de.learnlib - learnlib-build-tools - ${project.version} - - verify @@ -165,33 +211,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 - - - - - - diff --git a/build-tools/deploy-site.sh b/build-tools/deploy-site.sh index 63aa44b23b..9a9fdf836e 100755 --- a/build-tools/deploy-site.sh +++ b/build-tools/deploy-site.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (C) 2013-2018 TU Dortmund +# Copyright (C) 2013-2019 TU Dortmund # This file is part of LearnLib, http://www.learnlib.de/. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/build-tools/fix-license.sh b/build-tools/fix-license.sh index 52cefc67cc..553b97a3dd 100755 --- a/build-tools/fix-license.sh +++ b/build-tools/fix-license.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (C) 2013-2018 TU Dortmund +# Copyright (C) 2013-2019 TU Dortmund # This file is part of LearnLib, http://www.learnlib.de/. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/build-tools/generate-module-overview.py b/build-tools/generate-module-overview.py new file mode 100755 index 0000000000..dfd192207b --- /dev/null +++ b/build-tools/generate-module-overview.py @@ -0,0 +1,52 @@ +#!/usr/bin/python3 + +import os +import sys +import xml.etree.ElementTree as ET + +XPATH_ARTIFACT_ID = "./mvn:artifactId" +XPATH_DESCRIPTION = "./mvn:description" +XPATH_SUBMODULES = "./mvn:modules/mvn:module" +MAVEN_NAMESPACE = {'mvn': 'http://maven.apache.org/POM/4.0.0'} + + +def main(): + if len(sys.argv) < 2: + raise Exception("You need to specify a Maven project folder") + + project_dir = parse_target_directory(sys.argv[1]) + generate_entry(0, project_dir) + + +def parse_target_directory(path): + if os.path.isabs(path): + if not os.path.isdir(path): + raise Exception("%s is not a valid directory", path) + return path + else: + result = os.path.join(os.getcwd(), path) + if not os.path.isdir(result): + raise Exception("%s is not a valid directory", result) + return result + + +def generate_entry(indent, project_folder): + pom_path = os.path.join(project_folder, "pom.xml") + pom = ET.parse(pom_path) + + if indent == 0: + padding = '' + else: + padding = ('{:' + str(indent * 2) + '}').format(' ') + + artifact = pom.find(XPATH_ARTIFACT_ID, namespaces=MAVEN_NAMESPACE) + description = pom.find(XPATH_DESCRIPTION, namespaces=MAVEN_NAMESPACE) + + print('{}* **{}**: {}'.format(padding, artifact.text, description.text)) + + for module in pom.findall(XPATH_SUBMODULES, namespaces=MAVEN_NAMESPACE): + generate_entry(indent + 1, os.path.join(project_folder, module.text)) + + +if __name__ == '__main__': + main() diff --git a/build-tools/howto-release.txt b/build-tools/howto-release.txt deleted file mode 100644 index 9a41fef2d4..0000000000 --- a/build-tools/howto-release.txt +++ /dev/null @@ -1,12 +0,0 @@ - -1) Release to sonatype repository - -... - -2) Build binary release - -$ mvn -Pbinary-release clean compile javadoc:aggregate-jar package - -3) Deploy - -copy target/learnlib-${project.version}.zip to ... \ No newline at end of file diff --git a/build-tools/install-ltsmin.sh b/build-tools/install-ltsmin.sh new file mode 100755 index 0000000000..4b46141409 --- /dev/null +++ b/build-tools/install-ltsmin.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +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${FILE_SUFFIX}" -a -f "$HOME/ltsmin/${LTSMIN_VERSION}/bin/etf2lts-mc${FILE_SUFFIX}" && exit 0 + +# 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 "$HOME/ltsmin-download" + +# the files to extract +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 "$HOME/ltsmin-download/$LTSMIN_NAME" -C "$HOME/ltsmin" --files-from=$HOME/ltsmin-download/files diff --git a/build-tools/license-header.txt b/build-tools/license-header.txt index c49deb7560..20f53abbb1 100644 --- a/build-tools/license-header.txt +++ b/build-tools/license-header.txt @@ -1,4 +1,4 @@ -Copyright (C) 2013-2018 TU Dortmund +Copyright (C) 2013-2019 TU Dortmund This file is part of LearnLib, http://www.learnlib.de/. Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/build-tools/pom.xml b/build-tools/pom.xml index 13a407b42a..b9d4062ba8 100644 --- a/build-tools/pom.xml +++ b/build-tools/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-parent de.learnlib - 0.13.1 + learnlib-parent + 0.14.0 ../pom.xml learnlib-build-tools + LearnLib :: Build Tools Tools and resources required for building LearnLib - diff --git a/build-tools/src/main/resources/automatalib-learnlib-checkstyle.xml b/build-tools/src/main/resources/automatalib-learnlib-checkstyle.xml index 20f9016c05..fc5dae3e95 100644 --- a/build-tools/src/main/resources/automatalib-learnlib-checkstyle.xml +++ b/build-tools/src/main/resources/automatalib-learnlib-checkstyle.xml @@ -1,6 +1,6 @@ - - - - - - - - - - - - - - + LearnLib PMD ruleset + + + + + + + + + + + + + - + + + - - - - - + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + - - - + + + + + + - - + + + - + + + \ No newline at end of file diff --git a/build-tools/src/main/resources/learnlib-findbugs-exclusions.xml b/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml similarity index 77% rename from build-tools/src/main/resources/learnlib-findbugs-exclusions.xml rename to build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml index 99909a9837..8a9b394311 100644 --- a/build-tools/src/main/resources/learnlib-findbugs-exclusions.xml +++ b/build-tools/src/main/resources/learnlib-spotbugs-exclusions.xml @@ -1,6 +1,6 @@ - - - - - - @@ -40,4 +34,12 @@ limitations under the License. --> + + + + + + + + \ No newline at end of file diff --git a/build-tools/src/main/resources/license-header-java.txt b/build-tools/src/main/resources/license-header-java.txt index 3383533f91..30ca2f37f3 100644 --- a/build-tools/src/main/resources/license-header-java.txt +++ b/build-tools/src/main/resources/license-header-java.txt @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/build-tools/src/main/resources/license-header-xml.txt b/build-tools/src/main/resources/license-header-xml.txt index 276797a777..5abe96f2cb 100644 --- a/build-tools/src/main/resources/license-header-xml.txt +++ b/build-tools/src/main/resources/license-header-xml.txt @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-commons-parent de.learnlib - 0.13.1 + learnlib-commons-parent + 0.14.0 ../pom.xml learnlib-acex + LearnLib :: Commons :: Abstract Counterexamples An abstract counterexample analysis framework net.automatalib - automata-commons-util + automata-commons-smartcollections - 4.0.0 - learnlib-commons-parent de.learnlib - 0.13.1 + learnlib-commons-parent + 0.14.0 ../pom.xml learnlib-counterexamples + LearnLib :: Commons :: Counterexamples A collection of standard algorithms for handling counterexamples in automata learning diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/AcexLocalSuffixFinder.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/AcexLocalSuffixFinder.java index 5c38f5a81b..b111fe9535 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/AcexLocalSuffixFinder.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/AcexLocalSuffixFinder.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinder.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinder.java index d9bca93036..18738a051e 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinder.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinder.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..df556d129d 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinders.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/GlobalSuffixFinders.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..ee7511c381 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinder.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinder.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..15e28eb07b 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinders.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/LocalSuffixFinders.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/ClassicPrefixTransformAcex.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/ClassicPrefixTransformAcex.java index a6ba5c6f24..c718079f5b 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/ClassicPrefixTransformAcex.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/ClassicPrefixTransformAcex.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/MealyOutInconsPrefixTransformAcex.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/MealyOutInconsPrefixTransformAcex.java index c63514c975..a8ec77f190 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/MealyOutInconsPrefixTransformAcex.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/MealyOutInconsPrefixTransformAcex.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/OutInconsPrefixTransformAcex.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/OutInconsPrefixTransformAcex.java index 55edbdc816..cbecfb098a 100644 --- a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/OutInconsPrefixTransformAcex.java +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/OutInconsPrefixTransformAcex.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/commons/pom.xml b/commons/pom.xml index 19a7ae9788..9c3bd14f21 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-build-parent de.learnlib - 0.13.1 + learnlib-build-parent + 0.14.0 ../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 9d50ceb028..a000e55093 100644 --- a/commons/settings/pom.xml +++ b/commons/settings/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-commons-parent de.learnlib - 0.13.1 + learnlib-commons-parent + 0.14.0 ../pom.xml learnlib-settings + LearnLib :: Commons :: Settings A collection of utility methods to parse LearnLib specific settings @@ -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..ca6be2d44f --- /dev/null +++ b/commons/settings/src/main/java/de/learnlib/setting/LearnLibProperty.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.setting; + +/** + * An enum of all the system properties currently used by LearnLib. + * + * @author frohme + */ +public enum LearnLibProperty { + + /** + * {@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..d66ef9b759 100644 --- a/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java +++ b/commons/settings/src/main/java/de/learnlib/setting/LearnLibSettings.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -37,66 +39,56 @@ 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); - if (prop == null) { - return null; - } - + public > E getEnumValue(LearnLibProperty property, Class enumClazz) { // 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(String propName, boolean defaultValue) { - Boolean b = getBoolean(propName); - if (b != null) { - return b; - } - return defaultValue; + public boolean getBool(LearnLibProperty property, boolean defaultValue) { + return WrapperUtil.booleanValue(getBoolean(property), defaultValue); } - public Boolean getBoolean(String propName) { - String prop = getProperty(propName); - if (prop != null) { - return Boolean.parseBoolean(prop); - } - return null; + public Boolean getBoolean(LearnLibProperty property) { + return getTypedValue(property, Boolean::parseBoolean); } - public int getInt(String propName, int defaultValue) { - Integer prop = getInteger(propName); - if (prop != null) { - return prop; - } - return defaultValue; + public int getInt(LearnLibProperty property, int defaultValue) { + return WrapperUtil.intValue(getInteger(property), defaultValue); } - public Integer getInteger(String propName) { - String prop = getProperty(propName); - if (prop != null) { - try { - return Integer.parseInt(prop); - } catch (NumberFormatException ex) { - LOG.warn("Could not parse LearnLib integer property '" + propName + "'.", ex); - } + public Integer getInteger(LearnLibProperty property) { + return getTypedValue(property, Integer::parseInt); + } + + private T getTypedValue(LearnLibProperty property, Function valueExtractor) { + String prop = getProperty(property); + + 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/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..8d519aff4b 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..86028d71df 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..12ef7c3c36 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..ced91074e2 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..089bcd68df 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..e2db29d2a3 --- /dev/null +++ b/commons/settings/src/test/java/de/learnlib/setting/LearnLibSettingsTest.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.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()); + } + + @Test + public void testProperties() { + LearnLibSettings settings = LearnLibSettings.getInstance(); + + for (LearnLibProperty p : LearnLibProperty.values()) { + switch (p) { + 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..cf8c485426 --- /dev/null +++ b/commons/settings/src/test/resources/learnlib.properties @@ -0,0 +1,5 @@ +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/pom.xml b/commons/util/pom.xml index 4dcef41ff5..07a3782f6c 100644 --- a/commons/util/pom.xml +++ b/commons/util/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-commons-parent de.learnlib - 0.13.1 + learnlib-commons-parent + 0.14.0 ../pom.xml learnlib-util + LearnLib :: Commons :: Util A collection of utility methods for learning setups (oracle wrappers, etc.) @@ -58,6 +58,10 @@ limitations under the License. net.automatalib automata-core + + net.automatalib + automata-commons-util + net.automatalib automata-util @@ -68,11 +72,6 @@ limitations under the License. jsr305 - - - org.testng testng 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..67dec02eb4 --- /dev/null +++ b/commons/util/src/main/java/de/learnlib/util/AbstractBFOracle.java @@ -0,0 +1,111 @@ +/* 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.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/Experiment.java b/commons/util/src/main/java/de/learnlib/util/Experiment.java index 38f2e4590f..3cf10a7015 100644 --- a/commons/util/src/main/java/de/learnlib/util/Experiment.java +++ b/commons/util/src/main/java/de/learnlib/util/Experiment.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,25 +25,28 @@ import de.learnlib.filter.statistic.Counter; import de.learnlib.util.statistics.SimpleProfiler; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; /** * runs a learning experiment. * - * @param + * @param the automaton type * * @author falkhowar */ @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 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, @@ -52,11 +55,12 @@ public Experiment(LearningAlgorithm learningAlgorithm, this.impl = new ExperimentImpl<>(learningAlgorithm, equivalenceAlgorithm, inputs); } - /** - * - */ @Nonnull public A run() { + if (this.finalHypothesis != null) { + throw new IllegalStateException("Experiment has already been run"); + } + finalHypothesis = impl.run(); return finalHypothesis; } @@ -66,6 +70,7 @@ public A getFinalHypothesis() { if (finalHypothesis == null) { throw new IllegalStateException("Experiment has not yet been run"); } + return finalHypothesis; } @@ -83,7 +88,7 @@ private void profileStop(String taskname) { /** * @param logModels - * the logModels to set + * flag whether models should be logged */ public void setLogModels(boolean logModels) { this.logModels = logModels; @@ -91,7 +96,7 @@ public void setLogModels(boolean logModels) { /** * @param profile - * the profile to set + * flag whether learning process should be profiled */ public void setProfile(boolean profile) { this.profile = profile; @@ -105,25 +110,6 @@ public Counter getRounds() { return rounds; } - 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> { - - public MealyExperiment(LearningAlgorithm, I, Word> learningAlgorithm, - EquivalenceOracle, I, Word> equivalenceAlgorithm, - Alphabet inputs) { - super(learningAlgorithm, equivalenceAlgorithm, inputs); - } - - } - private final class ExperimentImpl { private final LearningAlgorithm learningAlgorithm; @@ -142,25 +128,26 @@ public A run() { rounds.increment(); LOGGER.logPhase("Starting round " + rounds.getCount()); LOGGER.logPhase("Learning"); - profileStart("Learning"); + + profileStart(LEARNING_PROFILE_KEY); learningAlgorithm.startLearning(); - profileStop("Learning"); + profileStop(LEARNING_PROFILE_KEY); + + while (true) { + final A hyp = learningAlgorithm.getHypothesisModel(); - 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"); + + profileStart(COUNTEREXAMPLE_PROFILE_KEY); DefaultQuery ce = equivalenceAlgorithm.findCounterExample(hyp, inputs); - profileStop("Searching for counterexample"); + profileStop(COUNTEREXAMPLE_PROFILE_KEY); + if (ce == null) { - done = true; - continue; + return hyp; } LOGGER.logCounterexample(ce.getInput().toString()); @@ -169,12 +156,32 @@ public A run() { rounds.increment(); LOGGER.logPhase("Starting round " + rounds.getCount()); LOGGER.logPhase("Learning"); - profileStart("Learning"); - learningAlgorithm.refineHypothesis(ce); - profileStop("Learning"); + + profileStart(LEARNING_PROFILE_KEY); + final boolean refined = learningAlgorithm.refineHypothesis(ce); + profileStop(LEARNING_PROFILE_KEY); + + assert refined; } + } + } + + 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> { - return hyp; + public MealyExperiment(LearningAlgorithm, I, Word> learningAlgorithm, + EquivalenceOracle, I, Word> 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..53c4d4f95e 100644 --- a/commons/util/src/main/java/de/learnlib/util/MQUtil.java +++ b/commons/util/src/main/java/de/learnlib/util/MQUtil.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,11 +23,15 @@ 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.LearnLibProperty; import de.learnlib.setting.LearnLibSettings; import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.commons.util.Pair; import net.automatalib.words.Word; @ParametersAreNonnullByDefault @@ -37,7 +41,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() { @@ -84,6 +88,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 +106,17 @@ public static void answerQueries(QueryAnswerer answerer, Collection } } + public static void answerOmegaQueries(OmegaQueryAnswerer answerer, + 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()); + } + } + public static void answerQueriesParallel(QueryAnswerer answerer, Collection> queries) { queries.parallelStream().forEach(q -> { @@ -103,6 +127,17 @@ public static void answerQueriesParallel(QueryAnswerer answerer, }); } + public static void answerOmegaQueriesParallel(OmegaQueryAnswerer answerer, + Collection> queries) { + queries.parallelStream().forEach(q -> { + 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()); + }); + } + public static boolean isCounterexample(DefaultQuery query, SuffixOutput hyp) { D qryOut = query.getOutput(); D hypOut = hyp.computeSuffixOutput(query.getPrefix(), query.getSuffix()); diff --git a/commons/util/src/main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java b/commons/util/src/main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java index 4e08e2dcae..ff85971a60 100644 --- a/commons/util/src/main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java +++ b/commons/util/src/main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; @ParametersAreNonnullByDefault diff --git a/commons/util/src/main/java/de/learnlib/util/mealy/MealyUtil.java b/commons/util/src/main/java/de/learnlib/util/mealy/MealyUtil.java index b2691e8e13..6c95e59de7 100644 --- a/commons/util/src/main/java/de/learnlib/util/mealy/MealyUtil.java +++ b/commons/util/src/main/java/de/learnlib/util/mealy/MealyUtil.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; /** diff --git a/commons/util/src/main/java/de/learnlib/util/mealy/SymbolOracleWrapper.java b/commons/util/src/main/java/de/learnlib/util/mealy/SymbolOracleWrapper.java index 2e709772a9..ade003ac9a 100644 --- a/commons/util/src/main/java/de/learnlib/util/mealy/SymbolOracleWrapper.java +++ b/commons/util/src/main/java/de/learnlib/util/mealy/SymbolOracleWrapper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/commons/util/src/main/java/de/learnlib/util/nfa/NFALearnerWrapper.java b/commons/util/src/main/java/de/learnlib/util/nfa/NFALearnerWrapper.java index c7dc81dabd..d48ef16585 100644 --- a/commons/util/src/main/java/de/learnlib/util/nfa/NFALearnerWrapper.java +++ b/commons/util/src/main/java/de/learnlib/util/nfa/NFALearnerWrapper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/commons/util/src/main/java/de/learnlib/util/statistics/SimpleProfiler.java b/commons/util/src/main/java/de/learnlib/util/statistics/SimpleProfiler.java index 1b914671d6..1175381a4e 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..5e9bb35bc3 --- /dev/null +++ b/commons/util/src/test/java/de/learnlib/util/ExperimentTest.java @@ -0,0 +1,132 @@ +/* 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.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.assertSame(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.assertSame(hypothesis, intermediateTarget); + + counterexamples++; + return new DefaultQuery<>(Word.epsilon(), true); + } + return null; + } + } + +} diff --git a/datastructures/discrimination-tree/pom.xml b/datastructures/discrimination-tree/pom.xml index e6297ad84b..c72748992f 100644 --- a/datastructures/discrimination-tree/pom.xml +++ b/datastructures/discrimination-tree/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-datastructures-parent de.learnlib - 0.13.1 + learnlib-datastructures-parent + 0.14.0 ../pom.xml learnlib-datastructure-dt + LearnLib :: Datastructures :: Discrimination Tree Data- and utility classes for Discrimination Trees @@ -44,6 +44,18 @@ limitations under the License. net.automatalib automata-api + + net.automatalib + automata-core + + + net.automatalib + automata-commons-util + + + net.automatalib + automata-commons-smartcollections + net.automatalib automata-util @@ -53,5 +65,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/BinaryDTNode.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/BinaryDTNode.java index cefef47392..f1a8ae6225 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/BinaryDTNode.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/BinaryDTNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/BinaryDTree.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/BinaryDTree.java index 3e0975a891..6fa8448d45 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/BinaryDTree.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/BinaryDTree.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/MultiDTNode.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/MultiDTNode.java index 2aeac9c27c..ec3ab66307 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/MultiDTNode.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/MultiDTNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/MultiDTree.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/MultiDTree.java index 5f811ac7f1..666d9ef72c 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/MultiDTree.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/MultiDTree.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/SplitData.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/SplitData.java index deb67300d4..8046d57e00 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/SplitData.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/SplitData.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..3e03ee6c7d --- /dev/null +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/iterators/DiscriminationTreeIterators.java @@ -0,0 +1,86 @@ +/* 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.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 89% 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..a7690cda83 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/AbstractDTNode.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDTNode.java index cc75285884..e53c9973b4 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDTNode.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDTNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..7ad0965586 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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.smartcollections.ArrayStorage; +import net.automatalib.commons.util.BitSetIterator; 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; @@ -91,6 +172,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; @@ -131,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/AbstractTemporaryIntrusiveDTNode.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractTemporaryIntrusiveDTNode.java index 56642f64f8..c61c3cddbc 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractTemporaryIntrusiveDTNode.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractTemporaryIntrusiveDTNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDTNode.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDTNode.java index 95579a05a1..539752a242 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDTNode.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractWordBasedDTNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..f9c6cfb4e7 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; /** @@ -37,14 +38,8 @@ public AbstractWordBasedDiscriminationTree(AbstractWordBasedDTNode root super(root, oracle); } - 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; + @Override + protected DefaultQuery buildQuery(AbstractWordBasedDTNode node, Word prefix) { + return new DefaultQuery<>(prefix, node.getDiscriminator()); } } 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..58cce923ac 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/LCAInfo.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/LCAInfo.java index 8223cc49f5..31b74269c0 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/LCAInfo.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/LCAInfo.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..16ab0cc4a6 --- /dev/null +++ b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/DummyDT.java @@ -0,0 +1,63 @@ +/* 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.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..431b3c4a36 --- /dev/null +++ b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/IteratorsTest.java @@ -0,0 +1,70 @@ +/* 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.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..52f2769707 --- /dev/null +++ b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/LCATest.java @@ -0,0 +1,51 @@ +/* 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.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..e86217819d --- /dev/null +++ b/datastructures/discrimination-tree/src/test/java/de/learnlib/datastructure/discriminationtree/VisualizationTest.java @@ -0,0 +1,55 @@ +/* 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.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)); + } +} diff --git a/datastructures/list/pom.xml b/datastructures/list/pom.xml index dabdccf9c2..36ed5f745a 100644 --- a/datastructures/list/pom.xml +++ b/datastructures/list/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-datastructures-parent de.learnlib - 0.13.1 + learnlib-datastructures-parent + 0.14.0 ../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/list/src/main/java/de/learnlib/datastructure/list/IntrusiveList.java b/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveList.java index ba1dac26f3..0773cba935 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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); diff --git a/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveListElem.java b/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveListElem.java index 2a90b307c3..673254ff85 100644 --- a/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveListElem.java +++ b/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveListElem.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveListElemImpl.java b/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveListElemImpl.java index baf42dfe19..28ff4a119f 100644 --- a/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveListElemImpl.java +++ b/datastructures/list/src/main/java/de/learnlib/datastructure/list/IntrusiveListElemImpl.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/observation-table/pom.xml b/datastructures/observation-table/pom.xml index 1ed5fcd8dd..dc06e1f26f 100644 --- a/datastructures/observation-table/pom.xml +++ b/datastructures/observation-table/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-datastructures-parent de.learnlib - 0.13.1 + learnlib-datastructures-parent + 0.14.0 ../pom.xml learnlib-datastructure-ot + LearnLib :: Datastructures :: Observationtable Data- and utility classes for Observation Tables @@ -34,6 +34,18 @@ limitations under the License. + + org.slf4j + slf4j-api + + + com.google.guava + guava + + + com.google.code.findbugs + jsr305 + @@ -54,14 +66,9 @@ limitations under the License. net.automatalib automata-commons-util - - com.google.guava - guava - - - com.google.code.findbugs - jsr305 + net.automatalib + automata-commons-smartcollections - 4.0.0 - learnlib-build-parent de.learnlib - 0.13.1 + learnlib-build-parent + 0.14.0 ../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 a55afa3ff8..21ce0dd1bc 100644 --- a/datastructures/pta/pom.xml +++ b/datastructures/pta/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-datastructures-parent de.learnlib - 0.13.1 + learnlib-datastructures-parent + 0.14.0 ../pom.xml learnlib-datastructure-pta + LearnLib :: Datastructures :: PTA Data- and utility classes for Prefix-Tree-Acceptors @@ -46,6 +46,10 @@ limitations under the License. net.automatalib automata-commons-util + + net.automatalib + automata-commons-smartcollections + net.automatalib automata-util @@ -70,5 +74,4 @@ limitations under the License. testng - diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/bluefringe/DefaultProcessingOrders.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/bluefringe/DefaultProcessingOrders.java index 81bfe85206..49d340c176 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/bluefringe/DefaultProcessingOrders.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/bluefringe/DefaultProcessingOrders.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/bluefringe/ProcessingOrder.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/bluefringe/ProcessingOrder.java index 022f94d2a4..6ad4db68cf 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/bluefringe/ProcessingOrder.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/bluefringe/ProcessingOrder.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..cf36b597c2 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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.smartcollections.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/AbstractBlueFringePTA.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBlueFringePTA.java index 98f2a9c947..61e366a00c 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBlueFringePTA.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBlueFringePTA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBlueFringePTAState.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBlueFringePTAState.java index 640b09b7eb..f1b4fd5eb2 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBlueFringePTAState.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/AbstractBlueFringePTAState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..2d0de5a7de 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/BlueFringePTA.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BlueFringePTA.java index a97b232dca..93c43d9b92 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BlueFringePTA.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BlueFringePTA.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BlueFringePTAState.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BlueFringePTAState.java index 49cf2a3897..454513834a 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BlueFringePTAState.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/BlueFringePTAState.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/PTATransition.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/PTATransition.java index 8b32252d43..a330d0944f 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/PTATransition.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/PTATransition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/PropertyConflictException.java b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/PropertyConflictException.java index 4f6ead14a1..48d3ec447f 100644 --- a/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/PropertyConflictException.java +++ b/datastructures/pta/src/main/java/de/learnlib/datastructure/pta/pta/PropertyConflictException.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..b0c4f8a5c1 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,21 +27,20 @@ import com.google.common.collect.Sets; import net.automatalib.automata.UniversalDeterministicAutomaton; +import net.automatalib.commons.smartcollections.ArrayStorage; import net.automatalib.commons.util.Pair; -import net.automatalib.commons.util.array.RichArray; 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); @@ -466,7 +465,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 diff --git a/datastructures/pta/src/test/java/de/learnlib/datastructure/pta/MergedAutomatonTest.java b/datastructures/pta/src/test/java/de/learnlib/datastructure/pta/MergedAutomatonTest.java index 3bd9abeff8..5d09c802c4 100644 --- a/datastructures/pta/src/test/java/de/learnlib/datastructure/pta/MergedAutomatonTest.java +++ b/datastructures/pta/src/test/java/de/learnlib/datastructure/pta/MergedAutomatonTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/distribution/pom.xml b/distribution/pom.xml index efd3dfb1a3..23672b159d 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -1,6 +1,6 @@ 4.0.0 + de.learnlib learnlib-build-parent - 0.13.1 + 0.14.0 ../build-parent/pom.xml 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. - + + de.learnlib + learnlib-emptiness-oracles + + de.learnlib learnlib-equivalence-oracles @@ -202,6 +207,11 @@ limitations under the License. learnlib-parallelism + + de.learnlib + learnlib-property-oracles + + net.automatalib.distribution @@ -230,6 +240,16 @@ limitations under the License. + + + + de.learnlib + learnlib-examples + ${project.version} + test + true + + bundles @@ -419,6 +439,13 @@ limitations under the License. + + de.learnlib + learnlib-emptiness-oracles + ${project.version} + sources + + de.learnlib learnlib-equivalence-oracles @@ -460,6 +487,13 @@ limitations under the License. ${project.version} sources + + + de.learnlib + learnlib-property-oracles + ${project.version} + sources + @@ -523,6 +557,18 @@ limitations under the License. de.learnlib:* + + + com.github.misberner.buildergen + buildergen + ${buildergen.version} + + + org.kohsuke.metainf-services + metainf-services + ${metainf-services.version} + + - 4.0.0 - learnlib-drivers-parent de.learnlib - 0.13.1 + learnlib-drivers-parent + 0.14.0 ../pom.xml learnlib-drivers-basic + LearnLib :: Drivers :: Basic Basic Test Driver Generation Support @@ -65,10 +65,6 @@ limitations under the License. - - de.learnlib.testsupport - learnlib-learning-examples - de.learnlib learnlib-membership-oracles @@ -79,5 +75,4 @@ limitations under the License. learnlib-mapper - diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/api/TestDriver.java b/drivers/basic/src/main/java/de/learnlib/drivers/api/TestDriver.java index 59e9eb543c..9a1f1e8501 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/api/TestDriver.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/api/TestDriver.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ConcreteMethodInput.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ConcreteMethodInput.java index db47b5b4c4..beada0cc6f 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ConcreteMethodInput.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/ConcreteMethodInput.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..3cc2750b96 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ * * @author falkhowar */ -public class Error extends AbstractMethodOutput { +public class Error extends MethodOutput { private final Throwable cause; @@ -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/MethodInput.java b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/MethodInput.java index ae291a8aa7..04e8881f24 100644 --- a/drivers/basic/src/main/java/de/learnlib/drivers/reflect/MethodInput.java +++ b/drivers/basic/src/main/java/de/learnlib/drivers/reflect/MethodInput.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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 83% 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..38b5c12fa9 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..b799dde09b 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ * * @author falkhowar */ -public class ReturnValue extends AbstractMethodOutput { +public class ReturnValue extends MethodOutput { private final Object ret; @@ -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); } 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..e651091e55 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..43c3c0a8c5 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..a1a54eac44 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..59b5a0246d 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/drivers/basic/src/test/java/de/learnlib/drivers/reflect/StackWithException.java b/drivers/basic/src/test/java/de/learnlib/drivers/reflect/StackWithException.java index 043150b9ad..c8e15c1bdf 100644 --- a/drivers/basic/src/test/java/de/learnlib/drivers/reflect/StackWithException.java +++ b/drivers/basic/src/test/java/de/learnlib/drivers/reflect/StackWithException.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/basic/src/test/java/de/learnlib/drivers/reflect/StackWithNull.java b/drivers/basic/src/test/java/de/learnlib/drivers/reflect/StackWithNull.java index ce7a63fbba..b490ba7a9e 100644 --- a/drivers/basic/src/test/java/de/learnlib/drivers/reflect/StackWithNull.java +++ b/drivers/basic/src/test/java/de/learnlib/drivers/reflect/StackWithNull.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/pom.xml b/drivers/mapper/pom.xml index 1f22d446f9..8266986da6 100644 --- a/drivers/mapper/pom.xml +++ b/drivers/mapper/pom.xml @@ -1,6 +1,6 @@ 4.0.0 + de.learnlib learnlib-drivers-parent - 0.13.1 + 0.14.0 ../pom.xml @@ -49,5 +50,9 @@ limitations under the License. jsr305 + + org.testng + testng + diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/AbstractContextExecutableInputSUL.java b/drivers/mapper/src/main/java/de/learnlib/mapper/AbstractContextExecutableInputSUL.java index 9ace02628d..f86519576e 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/AbstractContextExecutableInputSUL.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/AbstractContextExecutableInputSUL.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/ContextExecutableInputSUL.java b/drivers/mapper/src/main/java/de/learnlib/mapper/ContextExecutableInputSUL.java index 41bb71dcd1..b5e84c1ca3 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/ContextExecutableInputSUL.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/ContextExecutableInputSUL.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/ExecutableInputSUL.java b/drivers/mapper/src/main/java/de/learnlib/mapper/ExecutableInputSUL.java index 0642499451..bda70fbc1c 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/ExecutableInputSUL.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/ExecutableInputSUL.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/MappedSUL.java b/drivers/mapper/src/main/java/de/learnlib/mapper/MappedSUL.java index 008e18db3d..1eae3fbb08 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/MappedSUL.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/MappedSUL.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/MapperComposition.java b/drivers/mapper/src/main/java/de/learnlib/mapper/MapperComposition.java index d24a6b64ea..3a12ee16ef 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/MapperComposition.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/MapperComposition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/Mappers.java b/drivers/mapper/src/main/java/de/learnlib/mapper/Mappers.java index d476401a51..0db99c940e 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/Mappers.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/Mappers.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/SULMapperComposition.java b/drivers/mapper/src/main/java/de/learnlib/mapper/SULMapperComposition.java index 839de29971..34bd1feaed 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/SULMapperComposition.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/SULMapperComposition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/SULMappers.java b/drivers/mapper/src/main/java/de/learnlib/mapper/SULMappers.java index db36c87653..1aa0431738 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/SULMappers.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/SULMappers.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/StringMapper.java b/drivers/mapper/src/main/java/de/learnlib/mapper/StringMapper.java index 51dcf1740b..c1bfce300f 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/StringMapper.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/StringMapper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/api/ContextExecutableInput.java b/drivers/mapper/src/main/java/de/learnlib/mapper/api/ContextExecutableInput.java index 7a40376e25..eef733a089 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/api/ContextExecutableInput.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/api/ContextExecutableInput.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/api/ExecutableInput.java b/drivers/mapper/src/main/java/de/learnlib/mapper/api/ExecutableInput.java index 23805ff013..ae9975bdb0 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/api/ExecutableInput.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/api/ExecutableInput.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java b/drivers/mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java index cb690d40bd..e2ffa7fabe 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..0812eedc4d --- /dev/null +++ b/drivers/mapper/src/test/java/de/learnlib/mapper/MapperCompositionTest.java @@ -0,0 +1,106 @@ +/* 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.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 Mapper mapper; + + @BeforeClass + public void setUp() { + toUpperCaseMapper = new ToUpperCaseMapper(); + StringMapper 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..f3d70d8c95 --- /dev/null +++ b/drivers/mapper/src/test/java/de/learnlib/mapper/SULMapperCompositionTest.java @@ -0,0 +1,253 @@ +/* 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.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); + } + } +} diff --git a/drivers/pom.xml b/drivers/pom.xml index bf4bc7d9e9..a20dfbe9ed 100644 --- a/drivers/pom.xml +++ b/drivers/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-build-parent de.learnlib - 0.13.1 + learnlib-build-parent + 0.14.0 ../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 c3a70769e0..380929c048 100644 --- a/drivers/simulator/pom.xml +++ b/drivers/simulator/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-drivers-parent de.learnlib - 0.13.1 + learnlib-drivers-parent + 0.14.0 ../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/drivers/simulator/src/main/java/de/learnlib/driver/util/MealySimulatorSUL.java b/drivers/simulator/src/main/java/de/learnlib/driver/util/MealySimulatorSUL.java index 711d9a77fe..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ import de.learnlib.api.SUL; import de.learnlib.api.exception.SULException; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; /** * A {@link SUL} that implements steps by stepping through a {@link MealyMachine}. @@ -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 e64a8bc930..1ef43499f6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-build-parent de.learnlib - 0.13.1 + learnlib-build-parent + 0.14.0 ../build-parent/pom.xml learnlib-examples + LearnLib :: Examples A collection of various small example applications that illustrate several use cases of LearnLib. @@ -34,27 +34,10 @@ limitations under the License. deployed for this module. - - - - - org.jacoco - jacoco-maven-plugin - - true - - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - - + + + + + + de.learnlib + learnlib-acex + de.learnlib learnlib-api @@ -74,10 +61,18 @@ limitations under the License. de.learnlib learnlib-drivers-basic + + de.learnlib + learnlib-drivers-simulator + de.learnlib learnlib-lstar + + de.learnlib + learnlib-ttt + de.learnlib learnlib-equivalence-oracles @@ -102,6 +97,12 @@ limitations under the License. de.learnlib learnlib-util + + de.learnlib.testsupport + learnlib-learning-examples + compile + + @@ -112,6 +113,10 @@ limitations under the License. net.automatalib automata-core + + net.automatalib + automata-commons-util + net.automatalib automata-util @@ -120,6 +125,10 @@ limitations under the License. net.automatalib automata-serialization-dot + + net.automatalib + automata-modelchecking-ltsmin + net.automatalib @@ -131,5 +140,68 @@ limitations under the License. logback-classic runtime + + de.learnlib + learnlib-emptiness-oracles + + + de.learnlib + learnlib-property-oracles + + + + + org.testng + testng + + + net.java.openjdk.cacio + cacio-tta + + + org.jmockit + jmockit + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-surefire-plugin + + + 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/main/java/de/learnlib/examples/example1/Example.java b/examples/src/main/java/de/learnlib/examples/Example1.java similarity index 97% 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..38476c16b1 100644 --- a/examples/src/main/java/de/learnlib/examples/example1/Example.java +++ b/examples/src/main/java/de/learnlib/examples/Example1.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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 85% rename from examples/src/main/java/de/learnlib/examples/example2/Example.java rename to examples/src/main/java/de/learnlib/examples/Example2.java index 511af226ba..a7402ff0e4 100644 --- a/examples/src/main/java/de/learnlib/examples/example2/Example.java +++ b/examples/src/main/java/de/learnlib/examples/Example2.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -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; @@ -37,7 +37,7 @@ import de.learnlib.oracle.membership.SULOracle; import de.learnlib.util.Experiment.MealyExperiment; import de.learnlib.util.statistics.SimpleProfiler; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.serialization.dot.GraphDOT; import net.automatalib.visualization.Visualization; import net.automatalib.words.Word; @@ -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 } @@ -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/examples/src/main/java/de/learnlib/examples/example3/Example.java b/examples/src/main/java/de/learnlib/examples/Example3.java similarity index 96% 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..563149b892 100644 --- a/examples/src/main/java/de/learnlib/examples/example3/Example.java +++ b/examples/src/main/java/de/learnlib/examples/Example3.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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,12 +23,12 @@ 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; import de.learnlib.filter.reuse.tree.SystemStateHandler; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.Automata; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -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.java b/examples/src/main/java/de/learnlib/examples/bbc/Example1.java new file mode 100644 index 0000000000..1568893543 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example1.java @@ -0,0 +1,113 @@ +/* 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.bbc; + +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.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.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.DFALassoPropertyOracle; +import de.learnlib.util.Experiment; +import net.automatalib.automata.fsa.DFA; +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; + +/** + * Runs a black-box checking experiment for a DFA. + * + * @author Jeroen Meijer + */ +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 Example1() {} + + 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 + DFAModelCheckerLasso modelChecker = + new LTSminLTLDFABuilder().withString2Input(EDGE_PARSER).create(); + + // create an emptiness oracle, that is used to disprove properties + LassoEmptinessOracle.DFALassoEmptinessOracle + emptinessOracle = new DFALassoEmptinessOracleImpl<>(omqOracle); + + // 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 + PropertyOracle.DFAPropertyOracle ltl = new LoggingPropertyOracle.DFALoggingPropertyOracle<>( + new DFALassoPropertyOracle<>("letter==\"b\"", inclusionOracle, emptinessOracle, modelChecker)); + + // 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)); + + // 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/examples/src/main/java/de/learnlib/examples/bbc/Example2.java b/examples/src/main/java/de/learnlib/examples/bbc/Example2.java new file mode 100644 index 0000000000..f363ce279e --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example2.java @@ -0,0 +1,118 @@ +/* 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.bbc; + +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.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.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.membership.SimulatorOmegaOracle.MealySimulatorOmegaOracle; +import de.learnlib.oracle.property.MealyLassoPropertyOracle; +import de.learnlib.util.Experiment; +import net.automatalib.automata.transducers.MealyMachine; +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; + +/** + * Run a black-box checking experiment with Mealy machines and straightforward edge semantics. + * + * The main difference with {@link Example3} is how the LTL formula is written. + * + * @see Example3 + * + * @author Jeroen Meijer + */ +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 Example2() { } + + 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.getMembershipOracle(); + + // 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 + LassoEmptinessOracle.MealyLassoEmptinessOracle + emptinessOracle = new MealyLassoEmptinessOracleImpl<>(omqOracle); + + // create an inclusion oracle, that is used to find counterexamples to hypotheses + MealyInclusionOracle inclusionOracle = new MealyBFInclusionOracle<>(mqOracle, 1.0); + + // create an LTL property oracle, that also logs stuff + PropertyOracle.MealyPropertyOracle ltl = new LoggingPropertyOracle.MealyLoggingPropertyOracle<>( + new MealyLassoPropertyOracle<>("X output==\"2\"", inclusionOracle, emptinessOracle, modelChecker)); + + // 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)); + + // 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/examples/src/main/java/de/learnlib/examples/bbc/Example3.java b/examples/src/main/java/de/learnlib/examples/bbc/Example3.java new file mode 100644 index 0000000000..c6225a2693 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example3.java @@ -0,0 +1,116 @@ +/* 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.bbc; + +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.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.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.membership.SimulatorOmegaOracle.MealySimulatorOmegaOracle; +import de.learnlib.oracle.property.MealyLassoPropertyOracle; +import de.learnlib.util.Experiment; +import net.automatalib.automata.transducers.MealyMachine; +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; + +/** + * Run a black-box checking experiment with a Mealy machine and alternating edge semantics. + * + * The main difference with {@link Example2} is how the LTL formula is written. + * + * @see Example2 + * + * @author Jeroen Meijer + */ +public final class Example3 { + + public static final Function EDGE_PARSER = s -> s.charAt(0); + + private Example3() { } + + 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.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(); + + // create an emptiness oracle, that is used to disprove properties + LassoEmptinessOracle.MealyLassoEmptinessOracle + emptinessOracle = new MealyLassoEmptinessOracleImpl<>(omqOracle); + + // create an inclusion oracle, that is used to find counterexamples to hypotheses + MealyInclusionOracle inclusionOracle = new MealyBFInclusionOracle<>(mqOracle, 1.0); + + // 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)); + + // 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)); + + // 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/examples/src/main/java/de/learnlib/examples/bbc/Example4.java b/examples/src/main/java/de/learnlib/examples/bbc/Example4.java new file mode 100644 index 0000000000..4f6d0759d6 --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/bbc/Example4.java @@ -0,0 +1,141 @@ +/* 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.bbc; + +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 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 List> propertyOracles; + + public CExFirstOracle() { + this(Collections.emptySet()); + } + + public CExFirstOracle(PropertyOracle propertyOracle) { + this(Collections.singleton(propertyOracle)); + } + + public CExFirstOracle(Collection> propertyOracles) { + this.propertyOracles = new ArrayList<>(propertyOracles); + } + + @Override + public List> getPropertyOracles() { + return propertyOracles; + } + + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + for (PropertyOracle propertyOracle : propertyOracles) { + 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/CompleteExplorationEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java index bcf776b402..54422ea7d9 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ import de.learnlib.api.oracle.MembershipOracle; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.collections.CollectionsUtil; import net.automatalib.words.Word; @@ -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/DFABFInclusionOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DFABFInclusionOracle.java new file mode 100644 index 0000000000..c52a375ced --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DFABFInclusionOracle.java @@ -0,0 +1,29 @@ +/* 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; + +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/DelegateEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DelegateEQOracle.java index fa0e3364c5..95b20a31f2 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DelegateEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DelegateEQOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..7fe34a66c4 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/DisproveFirstOracle.java @@ -0,0 +1,123 @@ +/* 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; + +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; +import net.automatalib.automata.concepts.Output; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transducers.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 List> propertyOracles; + + public DisproveFirstOracle() { + this(Collections.emptyList()); + } + + public DisproveFirstOracle(PropertyOracle propertyOracle) { + this(Lists.newArrayList(propertyOracle)); + } + + public DisproveFirstOracle(Collection> propertyOracles) { + this.propertyOracles = new ArrayList<>(propertyOracles); + } + + @Override + public List> getPropertyOracles() { + return propertyOracles; + } + + @Nullable + @Override + public DefaultQuery findCounterExample(A hypothesis, Collection inputs) { + for (PropertyOracle po : propertyOracles) { + if (!po.isDisproved()) { + po.disprove(hypothesis, inputs); + } + } + + for (PropertyOracle po : propertyOracles) { + if (!po.isDisproved()) { + final DefaultQuery ce = po.doFindCounterExample(hypothesis, inputs); + if (ce != null) { + assert isCounterExample(hypothesis, ce.getInput(), ce.getOutput()); + return ce; + } + } + } + + return null; + } + + 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..f7c4b83a00 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; public class EQOracleChain implements EquivalenceOracle { @@ -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/EquivalenceQueries.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EquivalenceQueries.java index 1ea7e203c5..a3d0e74332 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/IncrementalWMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java index 036c4086b7..32ffa519ba 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.conformance.IncrementalWMethodTestsIterator; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; 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..6c7552ba49 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracle.java @@ -0,0 +1,30 @@ +/* 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; + +import de.learnlib.api.oracle.AutomatonOracle; +import de.learnlib.api.oracle.InclusionOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.transducers.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/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java index 4b38bf5e83..28f3790634 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.cover.Covers; import net.automatalib.words.Word; @@ -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/RandomWordsEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java index fc27a8fb72..b006f025da 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -24,7 +23,8 @@ import de.learnlib.api.oracle.MembershipOracle; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.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/RandomWpMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java index 213a31bca3..c85603c348 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.mappings.MutableMapping; import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.cover.Covers; @@ -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/SampleSetEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SampleSetEQOracle.java index 6cf08215a9..420b9297af 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SampleSetEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SampleSetEQOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimpleEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimpleEQOracle.java index c32d831557..463c129b20 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimpleEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimpleEQOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java index 582367257f..eacd8b4e3f 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.Automata; import net.automatalib.words.Word; diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java index 1841035a4c..39f4ca5b95 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.conformance.WMethodTestsIterator; import net.automatalib.words.Word; 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..ef7b76e189 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.conformance.WpMethodTestsIterator; import net.automatalib.words.Word; @@ -51,7 +51,7 @@ public class WpMethodEQOracle sulOracle, int maxDepth) { this(sulOracle, maxDepth, 1); @@ -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/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..18c0fb608b 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,12 +17,13 @@ import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Random; import de.learnlib.api.SUL; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.collections.CollectionsUtil; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; @@ -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/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/main/java/de/learnlib/oracle/equivalence/mealy/SymbolEQOracleWrapper.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/SymbolEQOracleWrapper.java index b5beddc91f..68fc5139fc 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/SymbolEQOracleWrapper.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/mealy/SymbolEQOracleWrapper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..9e7fd3b205 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/main/java/de/learnlib/oracle/equivalence/vpda/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/vpda/SimulatorEQOracle.java index b40066c827..7a12b7ac9a 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/vpda/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/vpda/SimulatorEQOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..a129474364 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracleTest.java @@ -0,0 +1,73 @@ +/* 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; + +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.testsupport.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() { + Assert.assertTrue(bfio.isCounterExample(automaton, query.getInput(), query.getOutput())); + } + + @Test + public void testFindCounterExample() { + 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/AbstractEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractEQOracleTest.java new file mode 100644 index 0000000000..87e12391b4 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/AbstractEQOracleTest.java @@ -0,0 +1,94 @@ +/* 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; + +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/CExFirstOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java new file mode 100644 index 0000000000..72a63ec163 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/CExFirstOracleTest.java @@ -0,0 +1,88 @@ +/* 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; + +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)).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 + public void testGetPropertyOracles() { + Assert.assertEquals(oracle.getPropertyOracles().size(), 2); + } + + /** + * Tests: + * 1. whether the correct counterexample is given by the {@link CExFirstOracle}, and + * 2. whether {@link PropertyOracle#disprove(Output, Collection)} is called only on {@link #po2}. + */ + @Test + public void testFindCounterExample() { + 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..911391af6d --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DFABFInclusionOracleTest.java @@ -0,0 +1,64 @@ +/* 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; + +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..a3d4011b12 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/DisproveFirstOracleTest.java @@ -0,0 +1,88 @@ +/* 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; + +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)).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 + public void testGetPropertyOracles() { + Assert.assertEquals(oracle.getPropertyOracles().size(), 2); + } + + /** + * Tests: + * 1. whether the correct counterexample is given by the {@link DisproveFirstOracle}, and + * 2. whether {@link PropertyOracle#disprove(Output, Collection)} is called only on {@link #po2}. + */ + @Test + public void testFindCounterExample() { + final DefaultQuery ce = oracle.findCounterExample(automaton, inputs); + + Assert.assertEquals(ce, query); + + Mockito.verify(po1, Mockito.times(1)).disprove(automaton, inputs); + Mockito.verify(po2).disprove(automaton, inputs); + Mockito.verify(po2, Mockito.never()).doFindCounterExample(automaton, inputs); + } +} \ No newline at end of file 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 8b9620971c..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,7 @@ import net.automatalib.automata.concepts.DetSuffixOutputAutomaton; import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.impl.compact.CompactDFA; -import net.automatalib.automata.transout.impl.compact.CompactMealy; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; import net.automatalib.exception.UndefinedPropertyAccessException; import net.automatalib.words.Alphabet; import org.testng.Assert; @@ -36,18 +36,18 @@ public class EmptyAutomatonOracleTest { @Test - public void testEmptyDFA() throws Exception { + public void testEmptyDFA() { testEmptyAutomaton(ExamplePaulAndMary.createExample(), new CompactDFA.Creator<>()); } @Test - public void testEmptyMealy() throws Exception { + public void testEmptyMealy() { Assert.assertThrows(UndefinedPropertyAccessException.class, () -> testEmptyAutomaton(ExampleStack.createExample(), new CompactMealy.Creator<>())); } private & UniversalDeterministicAutomaton> void testEmptyAutomaton( - LearningExample example, + LearningExample example, AutomatonCreator emptyCreator) { final A automaton = example.getReferenceAutomaton(); 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..4f2a313eef --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/MealyBFInclusionOracleTest.java @@ -0,0 +1,65 @@ +/* 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; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.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/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..483316f82f --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracleTest.java @@ -0,0 +1,91 @@ +/* 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; + +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.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.Symbol; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class RandomWMethodEQOracleTest 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> transitionCover; + 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.transitionCover = new HashSet<>(Automata.transitionCover(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++; + + 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, Symbol, Boolean> getOracle(MembershipOracle mOracle) { + return new DFARandomWMethodEQOracle<>(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/RandomWordsEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWordsEQOracleTest.java new file mode 100644 index 0000000000..055caeab72 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWordsEQOracleTest.java @@ -0,0 +1,84 @@ +/* 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; + +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/RandomWpMethodEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracleTest.java new file mode 100644 index 0000000000..f0ca15b5e0 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracleTest.java @@ -0,0 +1,90 @@ +/* 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; + +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/SampleSetEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/SampleSetEQOracleTest.java new file mode 100644 index 0000000000..a758d29523 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/SampleSetEQOracleTest.java @@ -0,0 +1,96 @@ +/* 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; + +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/TestWordEQOracleBatchTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/TestWordEQOracleBatchTest.java new file mode 100644 index 0000000000..a485f732e2 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/TestWordEQOracleBatchTest.java @@ -0,0 +1,107 @@ +/* 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; + +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); + } + } + +} 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..5121e1f090 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/mealy/RandomWalkEQOracleTest.java @@ -0,0 +1,113 @@ +/* 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.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.transducers.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)); + } + } + +} 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..50383d5578 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/vpda/RandomWellMatchedWordsEQOracleTest.java @@ -0,0 +1,113 @@ +/* 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.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; + } +} diff --git a/oracles/filters/cache/pom.xml b/oracles/filters/cache/pom.xml index a993738db4..2144d3b219 100644 --- a/oracles/filters/cache/pom.xml +++ b/oracles/filters/cache/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-filters-parent de.learnlib - 0.13.1 + learnlib-filters-parent + 0.14.0 ../pom.xml learnlib-cache + LearnLib :: Filters :: Cache Caches to avoid posing duplicate membership queries @@ -40,6 +40,10 @@ limitations under the License. de.learnlib learnlib-api + + de.learnlib + learnlib-membership-oracles + @@ -58,6 +62,10 @@ limitations under the License. net.automatalib automata-incremental + + net.automatalib + automata-util + @@ -65,6 +73,11 @@ limitations under the License. jsr305 + + + org.slf4j + slf4j-api + - - de.learnlib.testsupport - learnlib-learning-examples - 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/LearningCache.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/LearningCache.java index 65e3650eab..ab684d6695 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/LearningCache.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/LearningCache.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; /** diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/LearningCacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/LearningCacheOracle.java index 2960028bae..f40db45b02 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/LearningCacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/LearningCacheOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ import de.learnlib.api.oracle.MembershipOracle; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; /** diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheConsistencyTest.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheConsistencyTest.java index 11e5030165..66445fd413 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheConsistencyTest.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFACacheConsistencyTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..4f69b21795 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +15,7 @@ */ package de.learnlib.filter.cache.dfa; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -23,9 +24,13 @@ import javax.annotation.ParametersAreNonnullByDefault; +import de.learnlib.api.Resumable; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.filter.cache.LearningCacheOracle.DFALearningCacheOracle; +import de.learnlib.filter.cache.dfa.DFACacheOracle.DFACacheOracleState; +import net.automatalib.SupportsGrowingAlphabet; +import net.automatalib.exception.GrowingAlphabetNotSupportedException; import net.automatalib.incremental.dfa.Acceptance; import net.automatalib.incremental.dfa.IncrementalDFABuilder; import net.automatalib.incremental.dfa.dag.IncrementalDFADAGBuilder; @@ -33,6 +38,8 @@ import net.automatalib.incremental.dfa.tree.IncrementalDFATreeBuilder; import net.automatalib.incremental.dfa.tree.IncrementalPCDFATreeBuilder; import net.automatalib.words.Alphabet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * DFA cache. This cache is implemented as a membership oracle: upon construction, it is provided with a delegate @@ -46,52 +53,96 @@ * @author Malte Isberner */ @ParametersAreNonnullByDefault -public class DFACacheOracle implements DFALearningCacheOracle { +public class DFACacheOracle + implements DFALearningCacheOracle, SupportsGrowingAlphabet, Resumable> { - private final IncrementalDFABuilder incDfa; + private static final Logger LOGGER = LoggerFactory.getLogger(DFACacheOracle.class); + + private IncrementalDFABuilder incDfa; 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; } + /** + * 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); @@ -139,4 +190,41 @@ public void processQueries(Collection> queries) { } } + @Override + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + incDfa.addAlphabetSymbol(symbol); + } + + @Override + public DFACacheOracleState suspend() { + return new DFACacheOracleState<>(incDfa); + } + + @Override + public void resume(DFACacheOracleState state) { + final Class thisClass = this.incDfa.getClass(); + final Class stateClass = state.getBuilder().getClass(); + + if (!thisClass.equals(stateClass)) { + LOGGER.warn( + "You currently plan to use a '{}', but the state contained a '{}'. This may yield unexpected behavior.", + thisClass, + stateClass); + } + + this.incDfa = state.getBuilder(); + } + + public static class DFACacheOracleState implements Serializable { + + private final IncrementalDFABuilder builder; + + DFACacheOracleState(IncrementalDFABuilder builder) { + this.builder = builder; + } + + IncrementalDFABuilder getBuilder() { + return builder; + } + } } 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..ba5cd0eb7f 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,8 +18,11 @@ import javax.annotation.ParametersAreNonnullByDefault; 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,19 +32,61 @@ 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); } - public static DFALearningCacheOracle createHashCache(MembershipOracle mqOracle) { + public static DFAHashCacheOracle createHashCache(MembershipOracle mqOracle) { return new DFAHashCacheOracle<>(mqOracle); } @@ -66,11 +111,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); diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFAHashCacheConsistencyTest.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFAHashCacheConsistencyTest.java index 5d88971dc9..990b881b58 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFAHashCacheConsistencyTest.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFAHashCacheConsistencyTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFAHashCacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFAHashCacheOracle.java index 2705cbff1e..ae7fc3a866 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFAHashCacheOracle.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/DFAHashCacheOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +15,7 @@ */ package de.learnlib.filter.cache.dfa; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -23,17 +24,19 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import de.learnlib.api.Resumable; import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.filter.cache.LearningCacheOracle.DFALearningCacheOracle; +import de.learnlib.filter.cache.dfa.DFAHashCacheOracle.DFAHashCacheOracleState; import net.automatalib.automata.fsa.DFA; import net.automatalib.words.Word; -public class DFAHashCacheOracle implements DFALearningCacheOracle { +public class DFAHashCacheOracle implements DFALearningCacheOracle, Resumable> { private final MembershipOracle delegate; - private final Map, Boolean> cache; + private Map, Boolean> cache; private final Lock cacheLock; public DFAHashCacheOracle(MembershipOracle delegate) { @@ -78,4 +81,27 @@ public void processQueries(Collection> queries) { } } + @Override + public DFAHashCacheOracleState suspend() { + return new DFAHashCacheOracleState<>(cache); + } + + @Override + public void resume(DFAHashCacheOracleState state) { + this.cache = state.getCache(); + } + + public static class DFAHashCacheOracleState implements Serializable { + + private final Map, Boolean> cache; + + public DFAHashCacheOracleState(Map, Boolean> cache) { + this.cache = cache; + } + + public Map, Boolean> getCache() { + return cache; + } + } + } diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/ProxyQuery.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/ProxyQuery.java index 2bc3da7352..ebb931f6a2 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/ProxyQuery.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/dfa/ProxyQuery.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/InternalMealyCacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/InternalMealyCacheOracle.java new file mode 100644 index 0000000000..357ede6452 --- /dev/null +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/InternalMealyCacheOracle.java @@ -0,0 +1,232 @@ +/* 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.cache.mealy; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +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; +import net.automatalib.incremental.mealy.IncrementalMealyBuilder; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; +import net.automatalib.words.impl.SimpleAlphabet; + +/** + * Mealy cache. This cache is implemented as a membership oracle: upon construction, it is provided with a delegate + * oracle. Queries that can be answered from the cache are answered directly, others are forwarded to the delegate + * oracle. When the delegate oracle has finished processing these remaining queries, the results are incorporated into + * the cache. + *

    + * This oracle additionally enables the user to define a Mealy-style prefix-closure filter: a {@link Mapping} from + * output symbols to output symbols may be provided, with the following semantics: If in an output word a symbol for + * which the given mapping has a non-null value is encountered, all symbols after this symbol are replaced by the + * respective value. The rationale behind this is that the concrete error message (key in the mapping) is still + * reflected in the learned model, it is forced to result in a sink state with only a single repeating output symbol + * (value in the mapping). + * + * @param + * input symbol class + * @param + * output symbol class + * + * @author Malte Isberner + */ +class InternalMealyCacheOracle implements MealyLearningCacheOracle, SupportsGrowingAlphabet { + + private final MembershipOracle> delegate; + protected IncrementalMealyBuilder incMealy; + protected final Lock incMealyLock; + private final Comparator> queryCmp; + private final Mapping errorSyms; + + InternalMealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, + Mapping errorSyms, + MembershipOracle> delegate) { + this(incrementalBuilder, errorSyms, delegate, new DynamicSymbolComparator<>()); + } + + InternalMealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, + Mapping errorSyms, + MembershipOracle> delegate, + Comparator comparator) { + this.incMealy = incrementalBuilder; + this.incMealyLock = new ReentrantLock(); + this.queryCmp = new ReverseLexCmp<>(comparator); + this.errorSyms = errorSyms; + this.delegate = delegate; + } + + public int getCacheSize() { + return incMealy.asGraph().size(); + } + + @Override + public MealyCacheConsistencyTest createCacheConsistencyTest() { + return new MealyCacheConsistencyTest<>(incMealy, incMealyLock); + } + + @Override + public void processQueries(Collection>> queries) { + if (queries.isEmpty()) { + return; + } + + List>> qrys = new ArrayList<>(queries); + qrys.sort(queryCmp); + + List> masterQueries = new ArrayList<>(); + + Iterator>> it = qrys.iterator(); + Query> q = it.next(); + Word ref = q.getInput(); + + incMealyLock.lock(); + try { + MasterQuery master = createMasterQuery(ref); + if (!master.isAnswered()) { + masterQueries.add(master); + } + master.addSlave(q); + + while (it.hasNext()) { + q = it.next(); + Word curr = q.getInput(); + if (!curr.isPrefixOf(ref)) { + master = createMasterQuery(curr); + if (!master.isAnswered()) { + masterQueries.add(master); + } + } + + master.addSlave(q); + // Update ref to increase the effectiveness of the length check in + // isPrefixOf + ref = curr; + } + } finally { + incMealyLock.unlock(); + } + + delegate.processQueries(masterQueries); + + incMealyLock.lock(); + try { + for (MasterQuery m : masterQueries) { + postProcess(m); + } + } finally { + incMealyLock.unlock(); + } + } + + private MasterQuery createMasterQuery(Word word) { + WordBuilder wb = new WordBuilder<>(word.size()); + if (incMealy.lookup(word, wb)) { + return new MasterQuery<>(word, wb.toWord()); + } + + if (errorSyms == null) { + return new MasterQuery<>(word); + } + + int wbSize = wb.size(); + + if (wbSize == 0) { + return new MasterQuery<>(word, errorSyms); + } + + O repSym = errorSyms.get(wb.getSymbol(wbSize - 1)); + if (repSym == null) { + return new MasterQuery<>(word, errorSyms); + } + + wb.repeatAppend(word.length() - wbSize, repSym); + return new MasterQuery<>(word, wb.toWord()); + } + + private void postProcess(MasterQuery master) { + Word word = master.getSuffix(); + Word answer = master.getAnswer(); + + if (errorSyms == null) { + incMealy.insert(word, answer); + return; + } + + int answLen = answer.length(); + int i = 0; + while (i < answLen) { + O sym = answer.getSymbol(i++); + if (errorSyms.get(sym) != null) { + break; + } + } + + if (i == answLen) { + incMealy.insert(word, answer); + } else { + incMealy.insert(word.prefix(i), answer.prefix(i)); + } + } + + @Override + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + incMealy.addAlphabetSymbol(symbol); + } + + private static final class ReverseLexCmp implements Comparator>, Serializable { + + private final Comparator comparator; + + ReverseLexCmp(Comparator comparator) { + this.comparator = comparator; + } + + @Override + public int compare(Query o1, Query o2) { + return -CmpUtil.lexCompare(o1.getInput(), o2.getInput(), comparator); + } + } + + private static final class DynamicSymbolComparator implements Comparator, Serializable { + + private final SimpleAlphabet alphabet; + + DynamicSymbolComparator() { + this.alphabet = new SimpleAlphabet<>(); + } + + @Override + public int compare(I i1, I i2) { + alphabet.addSymbol(i1); + alphabet.addSymbol(i2); + return alphabet.compare(i1, i2); + } + } + +} diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MasterQuery.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MasterQuery.java index 7446277e5c..16fc7bf7fc 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MasterQuery.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MasterQuery.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheConsistencyTest.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheConsistencyTest.java index f15a9350a2..62db7b5aed 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheConsistencyTest.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCacheConsistencyTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.incremental.mealy.IncrementalMealyBuilder; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; 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..c660db1bd3 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,106 +16,40 @@ package de.learnlib.filter.cache.mealy; import java.io.Serializable; -import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import de.learnlib.api.Resumable; 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 de.learnlib.filter.cache.mealy.MealyCacheOracle.MealyCacheOracleState; +import net.automatalib.automata.transducers.OutputAndLocalInputs; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.incremental.mealy.IncrementalMealyBuilder; import net.automatalib.incremental.mealy.dag.IncrementalMealyDAGBuilder; import net.automatalib.incremental.mealy.tree.IncrementalMealyTreeBuilder; +import net.automatalib.incremental.mealy.tree.dynamic.DynamicIncrementalMealyTreeBuilder; +import net.automatalib.incremental.mealy.tree.dynamic.StateLocalInputIncrementalMealyTreeBuilder; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -import net.automatalib.words.WordBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -/** - * Mealy cache. This cache is implemented as a membership oracle: upon construction, it is provided with a delegate - * oracle. Queries that can be answered from the cache are answered directly, others are forwarded to the delegate - * oracle. When the delegate oracle has finished processing these remaining queries, the results are incorporated into - * the cache. - *

    - * This oracle additionally enables the user to define a Mealy-style prefix-closure filter: a {@link Mapping} from - * output symbols to output symbols may be provided, with the following semantics: If in an output word a symbol for - * which the given mapping has a non-null value is encountered, all symbols after this symbol are replaced by the - * respective value. The rationale behind this is that the concrete error message (key in the mapping) is still - * reflected in the learned model, it is forced to result in a sink state with only a single repeating output symbol - * (value in the mapping). - * - * @param - * input symbol class - * @param - * output symbol class - * - * @author Malte Isberner - */ -public class MealyCacheOracle implements MealyLearningCacheOracle { - - private final MembershipOracle> delegate; - private final IncrementalMealyBuilder incMealy; - private final Lock incMealyLock; - 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); - } +public class MealyCacheOracle extends InternalMealyCacheOracle + implements Resumable> { - /** - * 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); - } + private static final Logger LOGGER = LoggerFactory.getLogger(MealyCacheOracle.class); - public MealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, - Mapping errorSyms, - MembershipOracle> delegate) { - this(incrementalBuilder, new ReentrantLock(), errorSyms, delegate); + MealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, + Mapping errorSyms, + MembershipOracle> delegate) { + super(incrementalBuilder, errorSyms, delegate); } - public MealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, - Lock lock, - Mapping errorSyms, - MembershipOracle> delegate) { - this.incMealy = incrementalBuilder; - this.incMealyLock = lock; - this.queryCmp = new ReverseLexCmp<>(incrementalBuilder.getInputAlphabet()); - this.errorSyms = errorSyms; - this.delegate = delegate; + MealyCacheOracle(IncrementalMealyBuilder incrementalBuilder, + Mapping errorSyms, + MembershipOracle> delegate, + Comparator comparator) { + super(incrementalBuilder, errorSyms, delegate, comparator); } public static MealyCacheOracle createDAGCacheOracle(Alphabet inputAlphabet, @@ -127,7 +61,7 @@ public static MealyCacheOracle createDAGCacheOracle(Alphabet inp Mapping errorSyms, MembershipOracle> delegate) { IncrementalMealyBuilder incrementalBuilder = new IncrementalMealyDAGBuilder<>(inputAlphabet); - return new MealyCacheOracle<>(incrementalBuilder, errorSyms, delegate); + return new MealyCacheOracle<>(incrementalBuilder, errorSyms, delegate, inputAlphabet); } public static MealyCacheOracle createTreeCacheOracle(Alphabet inputAlphabet, @@ -139,134 +73,62 @@ public static MealyCacheOracle createTreeCacheOracle(Alphabet in Mapping errorSyms, MembershipOracle> delegate) { IncrementalMealyBuilder incrementalBuilder = new IncrementalMealyTreeBuilder<>(inputAlphabet); - return new MealyCacheOracle<>(incrementalBuilder, errorSyms, delegate); + return new MealyCacheOracle<>(incrementalBuilder, errorSyms, delegate, inputAlphabet); } - public int getCacheSize() { - return incMealy.asGraph().size(); + public static MealyCacheOracle createDynamicTreeCacheOracle(MembershipOracle> delegate) { + return createDynamicTreeCacheOracle(null, delegate); } - @Override - public MealyCacheConsistencyTest createCacheConsistencyTest() { - return new MealyCacheConsistencyTest<>(incMealy, incMealyLock); + public static MealyCacheOracle createDynamicTreeCacheOracle(Mapping errorSyms, + MembershipOracle> delegate) { + IncrementalMealyBuilder incrementalBuilder = new DynamicIncrementalMealyTreeBuilder<>(); + return new MealyCacheOracle<>(incrementalBuilder, errorSyms, delegate); } - @Override - public void processQueries(Collection>> queries) { - if (queries.isEmpty()) { - return; - } - - RichArray>> qrys = new RichArray<>(queries); - qrys.parallelSort(queryCmp); - - List> masterQueries = new ArrayList<>(); - - Iterator>> it = qrys.iterator(); - Query> q = it.next(); - Word ref = q.getInput(); - - incMealyLock.lock(); - try { - MasterQuery master = createMasterQuery(ref); - if (!master.isAnswered()) { - masterQueries.add(master); - } - master.addSlave(q); - - while (it.hasNext()) { - q = it.next(); - Word curr = q.getInput(); - if (!curr.isPrefixOf(ref)) { - master = createMasterQuery(curr); - if (!master.isAnswered()) { - masterQueries.add(master); - } - } - - master.addSlave(q); - // Update ref to increase the effectiveness of the length check in - // isPrefixOf - ref = curr; - } - } finally { - incMealyLock.unlock(); - } - - delegate.processQueries(masterQueries); - - incMealyLock.lock(); - try { - for (MasterQuery m : masterQueries) { - postProcess(m); - } - } finally { - incMealyLock.unlock(); - } + public static MealyCacheOracle> createStateLocalInputTreeCacheOracle(Collection initialLocalInputs, + MembershipOracle>> delegate) { + return createStateLocalInputTreeCacheOracle(initialLocalInputs, null, delegate); } - private MasterQuery createMasterQuery(Word word) { - WordBuilder wb = new WordBuilder<>(); - if (incMealy.lookup(word, wb)) { - return new MasterQuery<>(word, wb.toWord()); - } - - if (errorSyms == null) { - return new MasterQuery<>(word); - } - - int wbSize = wb.size(); - - if (wbSize == 0) { - return new MasterQuery<>(word, errorSyms); - } - - O repSym = errorSyms.get(wb.getSymbol(wbSize - 1)); - if (repSym == null) { - return new MasterQuery<>(word, errorSyms); - } - - wb.repeatAppend(word.length() - wbSize, repSym); - return new MasterQuery<>(word, wb.toWord()); + public static MealyCacheOracle> createStateLocalInputTreeCacheOracle(Collection initialLocalInputs, + Mapping, ? extends OutputAndLocalInputs> errorSyms, + MembershipOracle>> delegate) { + IncrementalMealyBuilder> incrementalBuilder = + new StateLocalInputIncrementalMealyTreeBuilder<>(initialLocalInputs); + return new MealyCacheOracle<>(incrementalBuilder, errorSyms, delegate); } - private void postProcess(MasterQuery master) { - Word word = master.getSuffix(); - Word answer = master.getAnswer(); - - if (errorSyms == null) { - incMealy.insert(word, answer); - return; - } + @Override + public MealyCacheOracleState suspend() { + return new MealyCacheOracleState<>(incMealy); + } - int answLen = answer.length(); - int i = 0; - while (i < answLen) { - O sym = answer.getSymbol(i++); - if (errorSyms.get(sym) != null) { - break; - } + @Override + public void resume(MealyCacheOracleState state) { + final Class thisClass = this.incMealy.getClass(); + final Class stateClass = state.getBuilder().getClass(); + + if (!thisClass.equals(stateClass)) { + LOGGER.warn( + "You currently plan to use a '{}', but the state contained a '{}'. This may yield unexpected behavior.", + thisClass, + stateClass); } - if (i == answLen) { - incMealy.insert(word, answer); - } else { - incMealy.insert(word.prefix(i), answer.prefix(i)); - } + this.incMealy = state.getBuilder(); } - private static final class ReverseLexCmp implements Comparator>, Serializable { + public static class MealyCacheOracleState implements Serializable { - private final Alphabet alphabet; + private final IncrementalMealyBuilder builder; - ReverseLexCmp(Alphabet alphabet) { - this.alphabet = alphabet; + MealyCacheOracleState(IncrementalMealyBuilder builder) { + this.builder = builder; } - @Override - public int compare(Query o1, Query o2) { - return -CmpUtil.lexCompare(o1.getInput(), o2.getInput(), alphabet); + IncrementalMealyBuilder getBuilder() { + return builder; } } - } diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCaches.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCaches.java index 4b6bf8ddb6..f0f76ffd01 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCaches.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/MealyCaches.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,11 @@ */ package de.learnlib.filter.cache.mealy; +import java.util.Collection; + import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.oracle.StateLocalInputOracle; +import net.automatalib.automata.transducers.OutputAndLocalInputs; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.incremental.mealy.dag.IncrementalMealyDAGBuilder; import net.automatalib.words.Alphabet; @@ -93,6 +97,115 @@ public static MealyCacheOracle createTreeCache(Alphabet alphabet return MealyCacheOracle.createTreeCacheOracle(alphabet, errorSyms, mqOracle); } + /** + * Creates a cache oracle for a Mealy machine learning setup with a dynamic alphabet storage, using a tree for + * internal cache organization. + *

    + * Note: Due to the dynamic alphabet storage, memory consumption of a dense tree may be higher than normal caches + * with a predefined alphabet. However, for sparse data, the memory consumption may be lower as only memory for the + * actual data of the tree is allocated. + * + * @param mqOracle + * the membership oracle + * + * @return a Mealy learning cache with a tree-based implementation + */ + public static MealyCacheOracle createDynamicTreeCache(MembershipOracle> mqOracle) { + return MealyCacheOracle.createDynamicTreeCacheOracle(mqOracle); + } + + /** + * Creates a cache oracle for a Mealy machine learning setup with a dynamic alphabet storage, using a tree for + * internal cache organization. + *

    + * Note: Due to the dynamic alphabet storage, memory consumption of a dense tree may be higher than normal caches + * with a predefined alphabet. However, for sparse data, the memory consumption may be lower as only memory for the + * actual data of the tree is allocated. + * + * @param errorSyms + * a mapping for the prefix-closure filter + * @param mqOracle + * the membership oracle + * + * @return a Mealy learning cache with a tree-based implementation + */ + public static MealyCacheOracle createDynamicTreeCache(Mapping errorSyms, + MembershipOracle> mqOracle) { + return MealyCacheOracle.createDynamicTreeCacheOracle(errorSyms, mqOracle); + } + + /** + * Creates a cache oracle for a Mealy machine learning setup with observable state local inputs for every state of + * the system under learning. + * + * @param initialLocalInputs + * a collection of input symbols that can be executed in the initial state of the system under learning + * @param mqOracle + * the membership oracle + * + * @return a Mealy learning cache with a tree-based implementation + */ + public static MealyCacheOracle> createStateLocalInputTreeCache(Collection initialLocalInputs, + MembershipOracle>> mqOracle) { + return MealyCacheOracle.createStateLocalInputTreeCacheOracle(initialLocalInputs, mqOracle); + } + + /** + * Creates a cache oracle for a Mealy machine learning setup with observable state local inputs for every state of + * the system under learning. + * + * @param initialLocalInputs + * a collection of input symbols that can be executed in the initial state of the system under learning + * @param errorSyms + * a mapping for the prefix-closure filter + * @param mqOracle + * the membership oracle + * + * @return a Mealy learning cache with a tree-based implementation + */ + public static MealyCacheOracle> createStateLocalInputTreeCache(Collection initialLocalInputs, + Mapping, ? extends OutputAndLocalInputs> errorSyms, + MembershipOracle>> mqOracle) { + return MealyCacheOracle.createStateLocalInputTreeCacheOracle(initialLocalInputs, errorSyms, mqOracle); + } + + /** + * A variation of {@link #createStateLocalInputTreeCache(Collection, MembershipOracle)} that returns a {@link + * StateLocalInputMealyCacheOracle}. + * + * @param initialLocalInputs + * a collection of input symbols that can be executed in the initial state of the system under learning + * @param mqOracle + * the membership oracle + * + * @return a Mealy learning cache with a tree-based implementation + */ + public static StateLocalInputMealyCacheOracle createStateLocalInputTreeCache(Collection initialLocalInputs, + StateLocalInputOracle>> mqOracle) { + return StateLocalInputMealyCacheOracle.createStateLocalInputTreeCacheOracle(initialLocalInputs, mqOracle); + } + + /** + * A variation of {@link #createStateLocalInputTreeCache(Collection, MembershipOracle)} that returns a {@link + * StateLocalInputMealyCacheOracle}. + * + * @param initialLocalInputs + * a collection of input symbols that can be executed in the initial state of the system under learning + * @param errorSyms + * a mapping for the prefix-closure filter + * @param mqOracle + * the membership oracle + * + * @return a Mealy learning cache with a tree-based implementation + */ + public static StateLocalInputMealyCacheOracle createStateLocalInputTreeCache(Collection initialLocalInputs, + Mapping, ? extends OutputAndLocalInputs> errorSyms, + StateLocalInputOracle>> mqOracle) { + return StateLocalInputMealyCacheOracle.createStateLocalInputTreeCacheOracle(initialLocalInputs, + errorSyms, + mqOracle); + } + /** * Creates a cache oracle for a Mealy machine learning setup. *

    diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/StateLocalInputCacheConsistencyTest.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/StateLocalInputCacheConsistencyTest.java new file mode 100644 index 0000000000..040894fd92 --- /dev/null +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/StateLocalInputCacheConsistencyTest.java @@ -0,0 +1,69 @@ +/* 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.cache.mealy; + +import java.util.Collection; +import java.util.concurrent.locks.Lock; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.automata.transducers.StateLocalInputMealyMachine; +import net.automatalib.incremental.mealy.IncrementalMealyBuilder; +import net.automatalib.util.automata.transducers.StateLocalInputMealyUtil; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; + +public class StateLocalInputCacheConsistencyTest + implements EquivalenceOracle, I, Word>> { + + private final IncrementalMealyBuilder> incMealy; + private final Lock incMealyLock; + + public StateLocalInputCacheConsistencyTest(IncrementalMealyBuilder> incMealy, + Lock lock) { + this.incMealy = incMealy; + this.incMealyLock = lock; + } + + @Override + public DefaultQuery>> findCounterExample(StateLocalInputMealyMachine hypothesis, + Collection inputs) { + final WordBuilder> wb; + Word w; + + // using null here as sink is fine, because the cache will never traverse undefined transitions of the + // hypothesis (discrepancies will be observed beforehand on the enabled inputs) + final StateLocalInputMealyMachine> wrapped = + StateLocalInputMealyUtil.partialToObservableOutput(hypothesis, null); + + incMealyLock.lock(); + try { + w = incMealy.findSeparatingWord(wrapped, inputs, false); + if (w == null) { + return null; + } + wb = new WordBuilder<>(w.length()); + incMealy.lookup(w, wb); + } finally { + incMealyLock.unlock(); + } + + DefaultQuery>> result = new DefaultQuery<>(w); + result.answer(wb.toWord()); + return result; + } +} diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/StateLocalInputMealyCacheOracle.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/StateLocalInputMealyCacheOracle.java new file mode 100644 index 0000000000..c013888a85 --- /dev/null +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/mealy/StateLocalInputMealyCacheOracle.java @@ -0,0 +1,105 @@ +/* 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.cache.mealy; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import de.learnlib.api.Resumable; +import de.learnlib.api.oracle.StateLocalInputOracle; +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.filter.cache.mealy.StateLocalInputMealyCacheOracle.StateLocalInputMealyCacheOracleState; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.incremental.mealy.IncrementalMealyBuilder; +import net.automatalib.incremental.mealy.tree.dynamic.StateLocalInputIncrementalMealyTreeBuilder; +import net.automatalib.words.Word; + +public class StateLocalInputMealyCacheOracle extends InternalMealyCacheOracle> + implements StateLocalInputMealyOracle>, + Resumable> { + + private final StateLocalInputOracle>> oracle; + private Map, Set> definedInputsCache; + + StateLocalInputMealyCacheOracle(IncrementalMealyBuilder> incrementalBuilder, + Mapping, ? extends OutputAndLocalInputs> errorSyms, + StateLocalInputOracle>> delegate) { + super(incrementalBuilder, errorSyms, delegate); + this.oracle = delegate; + this.definedInputsCache = new HashMap<>(); + } + + public static StateLocalInputMealyCacheOracle createStateLocalInputTreeCacheOracle(Collection initialLocalInputs, + StateLocalInputOracle>> delegate) { + return createStateLocalInputTreeCacheOracle(initialLocalInputs, null, delegate); + } + + public static StateLocalInputMealyCacheOracle createStateLocalInputTreeCacheOracle(Collection initialLocalInputs, + Mapping, ? extends OutputAndLocalInputs> errorSyms, + StateLocalInputOracle>> delegate) { + StateLocalInputIncrementalMealyTreeBuilder incrementalBuilder = + new StateLocalInputIncrementalMealyTreeBuilder<>(initialLocalInputs); + return new StateLocalInputMealyCacheOracle<>(incrementalBuilder, errorSyms, delegate); + } + + public StateLocalInputCacheConsistencyTest createStateLocalInputCacheConsistencyTest() { + return new StateLocalInputCacheConsistencyTest<>(incMealy, incMealyLock); + } + + @Override + public Set definedInputs(Word input) { + if (!definedInputsCache.containsKey(input)) { + definedInputsCache.put(input, oracle.definedInputs(input)); + } + + return definedInputsCache.get(input); + } + + @Override + public StateLocalInputMealyCacheOracleState suspend() { + return new StateLocalInputMealyCacheOracleState<>(incMealy, definedInputsCache); + } + + @Override + public void resume(StateLocalInputMealyCacheOracleState state) { + this.incMealy = state.getBuilder(); + this.definedInputsCache = state.getEnabledInputs(); + } + + public static class StateLocalInputMealyCacheOracleState implements Serializable { + + private final IncrementalMealyBuilder> builder; + private final Map, Set> enabledInputs; + + StateLocalInputMealyCacheOracleState(IncrementalMealyBuilder> builder, + Map, Set> enabledInputs) { + this.builder = builder; + this.enabledInputs = enabledInputs; + } + + IncrementalMealyBuilder> getBuilder() { + return builder; + } + + Map, Set> getEnabledInputs() { + return enabledInputs; + } + } +} 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..13d34a3b17 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,13 +15,22 @@ */ package de.learnlib.filter.cache.mealy; +import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import de.learnlib.api.Resumable; +import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.oracle.SymbolQueryOracle; -import net.automatalib.automata.transout.impl.FastMealy; -import net.automatalib.automata.transout.impl.FastMealyState; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.filter.cache.LearningCacheOracle.MealyLearningCacheOracle; +import de.learnlib.filter.cache.mealy.SymbolQueryCache.SymbolQueryCacheState; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +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,21 +46,20 @@ * * @author frohme */ -// TODO: integrate in existing LearningCache hierarchy -public class SymbolQueryCache implements SymbolQueryOracle { +public class SymbolQueryCache + implements SymbolQueryOracle, MealyLearningCacheOracle, Resumable> { - private final FastMealy cache; + private CompactMealy cache; private final SymbolQueryOracle delegate; private final List currentTrace; - private FastMealyState currentState; + private Integer currentState; private boolean currentTraceValid; public SymbolQueryCache(final SymbolQueryOracle delegate, final Alphabet alphabet) { this.delegate = delegate; - this.cache = new FastMealy<>(alphabet); - this.cache.addInitialState(); - this.currentState = this.cache.getInitialState(); + this.cache = new CompactMealy<>(alphabet); + this.currentState = this.cache.addInitialState(); this.currentTrace = new ArrayList<>(); this.currentTraceValid = false; @@ -61,7 +69,7 @@ public SymbolQueryCache(final SymbolQueryOracle delegate, final Alphabet succ = this.cache.getSuccessor(this.currentState, i); + final Integer succ = this.cache.getSuccessor(this.currentState, i); if (succ != null) { final O output = this.cache.getOutput(this.currentState, i); @@ -78,11 +86,11 @@ public O query(I i) { final O output = this.delegate.query(i); - final FastMealyState nextState; - final FastMealyState succ = this.cache.getSuccessor(this.currentState, i); + final Integer nextState; + final Integer succ = this.cache.getSuccessor(this.currentState, i); if (succ == null) { - final FastMealyState newState = this.cache.addState(); + final Integer newState = this.cache.addState(); this.cache.addTransition(this.currentState, i, newState, output); nextState = newState; } else { @@ -101,4 +109,47 @@ 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; + } + + @Override + public SymbolQueryCacheState suspend() { + return new SymbolQueryCacheState<>(cache); + } + + @Override + public void resume(SymbolQueryCacheState state) { + this.cache = state.getCache(); + } + + public static class SymbolQueryCacheState implements Serializable { + + private final CompactMealy cache; + + SymbolQueryCacheState(CompactMealy cache) { + this.cache = cache; + } + + CompactMealy getCache() { + return cache; + } + } } 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..45cb2b4a6c 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +15,8 @@ */ package de.learnlib.filter.cache.sul; +import java.io.Serializable; +import java.util.Collection; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -22,15 +24,24 @@ import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import de.learnlib.api.Resumable; 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.filter.cache.sul.SULCache.SULCacheState; +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; -import net.automatalib.ts.transout.MealyTransitionSystem; +import net.automatalib.ts.output.MealyTransitionSystem; import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A cache to be used with a {@link SUL}. @@ -50,30 +61,20 @@ * @author Malte Isberner */ @ParametersAreNonnullByDefault -public class SULCache implements SUL, LearningCache.MealyLearningCache { +public class SULCache implements SUL, + MealyLearningCacheOracle, + SupportsGrowingAlphabet, + Resumable> { - private final SULCacheImpl impl; + private static final Logger LOGGER = LoggerFactory.getLogger(SULCache.class); - /** - * 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); - } + private final SULCacheImpl impl; - 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 +106,26 @@ public MealyCacheConsistencyTest createCacheConsistencyTest() { return impl.createCacheConsistencyTest(); } + @Override + public void processQueries(Collection>> queries) { + SULOracle.processQueries(impl, queries); + } + + @Override + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + impl.addAlphabetSymbol(symbol); + } + + @Override + public SULCacheState suspend() { + return impl.suspend(); + } + + @Override + public void resume(SULCacheState state) { + this.impl.resume(state); + } + /** * 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,10 +142,11 @@ public MealyCacheConsistencyTest createCacheConsistencyTest() { * @author Malte Isberner */ @ParametersAreNonnullByDefault - private static final class SULCacheImpl { + private static final class SULCacheImpl + implements SUL, MealyLearningCache, SupportsGrowingAlphabet, Resumable> { - private final IncrementalMealyBuilder incMealy; - private final MealyTransitionSystem mealyTs; + private IncrementalMealyBuilder incMealy; + private MealyTransitionSystem mealyTs; private final SUL delegate; private final WordBuilder inputWord = new WordBuilder<>(); private final Lock incMealyLock; @@ -142,12 +164,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 +208,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,9 +232,51 @@ public void post() { } @Nonnull + @Override public MealyCacheConsistencyTest createCacheConsistencyTest() { return new MealyCacheConsistencyTest<>(incMealy, incMealyLock); } + + @Override + public void addAlphabetSymbol(I symbol) throws GrowingAlphabetNotSupportedException { + incMealy.addAlphabetSymbol(symbol); + } + + @Override + public SULCacheState suspend() { + return new SULCacheState<>(incMealy); + } + + @Override + @SuppressWarnings("unchecked") + public void resume(SULCacheState state) { + final Class thisClass = this.incMealy.getClass(); + final Class stateClass = state.getBuilder().getClass(); + + if (!thisClass.equals(stateClass)) { + LOGGER.warn( + "You currently plan to use a '{}', but the state contained a '{}'. This may yield unexpected behavior.", + thisClass, + stateClass); + } + + this.incMealy = state.getBuilder(); + this.mealyTs = (MealyTransitionSystem) this.incMealy.asTransitionSystem(); + } + } + + public static class SULCacheState implements Serializable { + + private final IncrementalMealyBuilder builder; + + SULCacheState(IncrementalMealyBuilder builder) { + this.builder = builder; + } + + IncrementalMealyBuilder getBuilder() { + return builder; + } + } } diff --git a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCaches.java b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCaches.java index fb8cba7469..cb5d075ea8 100644 --- a/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCaches.java +++ b/oracles/filters/cache/src/main/java/de/learnlib/filter/cache/sul/SULCaches.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..3e88f2768f --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/AbstractCacheTest.java @@ -0,0 +1,213 @@ +/* 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.cache; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import de.learnlib.api.Resumable; +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, A extends Output, I, D> { + + private static final int LENGTH = 5; + private final Random random = new Random(42); + private Alphabet alphabet; + protected OR 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())); + } + + @Test(dependsOnMethods = {"testCacheConsistency"}) + public void testResuming() { + + final OR resumedOracle = getResumedOracle(oracle); + final long oldCount = getNumberOfPosedQueries(); + + resumedOracle.processQueries(queries); + + // resumed oracle should retain cache information + Assert.assertEquals(getNumberOfPosedQueries(), oldCount); + + resumedOracle.answerQuery(generateWord()); + + // but also be able to answer new queries + // note, however, if we use mapping, it may happen, that a query is not posed, even though the cache does not + // have sufficient data on the word. so this check may not be applicable + if (!usesMapping()) { + Assert.assertEquals(getNumberOfPosedQueries(), oldCount + 1); + } + } + + 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 static void serializeResumable(Resumable source, Resumable target) { + + try { + final ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + + try (ObjectOutputStream objectOut = new ObjectOutputStream(byteOut)) { + final T state = source.suspend(); + objectOut.writeObject(state); + } + + try (ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); + ObjectInputStream objectIn = new ObjectInputStream(byteIn)) { + + @SuppressWarnings("unchecked") + final T serializedState = (T) objectIn.readObject(); + target.resume(serializedState); + } + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + protected boolean usesMapping() { + return false; + } + + protected Query getQuery(int i) { + return queries.get(i); + } + + protected abstract Alphabet getAlphabet(); + + protected abstract A getTargetModel(); + + protected abstract A getInvalidTargetModel(); + + protected abstract OR getCachedOracle(); + + protected abstract OR getResumedOracle(OR original); + + 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..10dde4deda --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/CacheTestUtils.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.filter.cache; + +import java.util.Random; + +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.automata.transducers.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..6ed129928e --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/AbstractDFACacheTest.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.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.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, DFA, 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 DFACacheOracle getCachedOracle() { + return getCache(counter); + } + + @Override + protected DFACacheOracle getResumedOracle(DFACacheOracle original) { + final DFACacheOracle fresh = getCache(counter); + serializeResumable(original, fresh); + return fresh; + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getCount(); + } + + @Override + protected boolean supportsPrefixes() { + return false; + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } + + protected abstract DFACacheOracle 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..03d5241a1d --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFADAGCacheTest.java @@ -0,0 +1,29 @@ +/* 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.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..dd7c144d5b --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFAHashCacheTest.java @@ -0,0 +1,73 @@ +/* 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.cache.dfa; + +import de.learnlib.filter.cache.AbstractCacheTest; +import de.learnlib.filter.cache.CacheTestUtils; +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 class DFAHashCacheTest + extends AbstractCacheTest, DFA, Character, Boolean> { + + private final DFACounterOracle counter; + + public DFAHashCacheTest() { + 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 DFAHashCacheOracle getCachedOracle() { + return DFACaches.createHashCache(counter); + } + + @Override + protected DFAHashCacheOracle getResumedOracle(DFAHashCacheOracle original) { + final DFAHashCacheOracle fresh = DFACaches.createHashCache(counter); + serializeResumable(original, fresh); + return fresh; + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getCount(); + } + + @Override + protected boolean supportsPrefixes() { + return false; + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } +} 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..3841a4bcb7 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/dfa/DFATreeCacheTest.java @@ -0,0 +1,29 @@ +/* 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.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..a8b8d800af --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/AbstractMealyCacheTest.java @@ -0,0 +1,88 @@ +/* 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.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.statistic.oracle.CounterOracle.MealyCounterOracle; +import de.learnlib.oracle.membership.SimulatorOracle.MealySimulatorOracle; +import net.automatalib.automata.transducers.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, MealyMachine, 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 MealyCacheOracle getCachedOracle() { + return getCache(counter); + } + + @Override + protected MealyCacheOracle getResumedOracle(MealyCacheOracle original) { + final MealyCacheOracle fresh = getCache(counter); + serializeResumable(original, fresh); + return fresh; + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getCount(); + } + + @Override + protected boolean supportsPrefixes() { + return true; + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } + + protected abstract MealyCacheOracle getCache(MealyMembershipOracle delegate); +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/DynamicMealyTreeCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/DynamicMealyTreeCacheTest.java new file mode 100644 index 0000000000..9fb55d8a94 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/DynamicMealyTreeCacheTest.java @@ -0,0 +1,29 @@ +/* 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.cache.mealy; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; + +/** + * @author frohme + */ +public class DynamicMealyTreeCacheTest extends AbstractMealyCacheTest { + + @Override + protected MealyCacheOracle getCache(MealyMembershipOracle delegate) { + return MealyCaches.createDynamicTreeCache(delegate); + } +} diff --git a/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/DynamicMealyTreeMapperCacheTest.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/DynamicMealyTreeMapperCacheTest.java new file mode 100644 index 0000000000..2c8e73dc47 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/DynamicMealyTreeMapperCacheTest.java @@ -0,0 +1,35 @@ +/* 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.cache.mealy; + +import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; + +/** + * @author frohme + */ +public class DynamicMealyTreeMapperCacheTest extends AbstractMealyCacheTest { + + @Override + protected MealyCacheOracle getCache(MealyMembershipOracle delegate) { + return MealyCaches.createDynamicTreeCache(super.errorMapper, delegate); + } + + @Override + protected boolean usesMapping() { + return true; + } +} + 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..60ef3fd36d --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGCacheTest.java @@ -0,0 +1,29 @@ +/* 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.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..86b44e19d3 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyDAGMapperCacheTest.java @@ -0,0 +1,34 @@ +/* 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.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); + } + + @Override + protected boolean usesMapping() { + return true; + } +} 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..5c8e31db46 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeCacheTest.java @@ -0,0 +1,29 @@ +/* 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.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..88e65f2635 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/MealyTreeMapperCacheTest.java @@ -0,0 +1,34 @@ +/* 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.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); + } + + @Override + protected boolean usesMapping() { + return true; + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..1a240ed051 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/StateLocalInputMealyTreeCacheTest.java @@ -0,0 +1,118 @@ +/* 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.cache.mealy; + +import java.util.Collection; + +import de.learnlib.api.oracle.StateLocalInputOracle.StateLocalInputMealyOracle; +import de.learnlib.driver.util.StateLocalInputMealySimulatorSUL; +import de.learnlib.filter.cache.AbstractCacheTest; +import de.learnlib.filter.cache.CacheTestUtils; +import de.learnlib.filter.statistic.sul.ResetCounterStateLocalInputSUL; +import de.learnlib.oracle.membership.StateLocalInputSULOracle; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.OutputAndLocalInputs; +import net.automatalib.util.automata.transducers.StateLocalInputMealyUtil; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author frohme + */ +public class StateLocalInputMealyTreeCacheTest + extends AbstractCacheTest, MealyMachine>, Character, Word>> { + + private final ResetCounterStateLocalInputSUL counter; + private final StateLocalInputMealyOracle> oracle; + + private final Collection initialInputs; + + public StateLocalInputMealyTreeCacheTest() { + final StateLocalInputMealySimulatorSUL sul = + new StateLocalInputMealySimulatorSUL<>(CacheTestUtils.MEALY); + counter = new ResetCounterStateLocalInputSUL<>("counterOracle", sul); + oracle = new StateLocalInputSULOracle<>(counter); + + sul.pre(); + initialInputs = sul.currentlyEnabledInputs(); + sul.post(); + } + + @Override + protected MealyMachine> getTargetModel() { + return StateLocalInputMealyUtil.partialToObservableOutput(CacheTestUtils.MEALY); + } + + @Override + protected MealyMachine> getInvalidTargetModel() { + return StateLocalInputMealyUtil.partialToObservableOutput(CacheTestUtils.MEALY_INVALID); + } + + @Override + protected StateLocalInputMealyCacheOracle getCachedOracle() { + return MealyCaches.createStateLocalInputTreeCache(initialInputs, oracle); + } + + @Override + protected StateLocalInputMealyCacheOracle getResumedOracle(StateLocalInputMealyCacheOracle original) { + final StateLocalInputMealyCacheOracle fresh = getCachedOracle(); + serializeResumable(original, fresh); + return fresh; + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getStatisticalData().getCount(); + } + + @Override + protected boolean supportsPrefixes() { + return true; + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } + + // dependsOnMethods doesn't seem to work well with Intellij IDEA plugin. + @Test(priority = 1) + public void testQueryWithNoContainedAlphabetSymbol() { + final long oldCount = getNumberOfPosedQueries(); + + final Word oldQuery = getQuery(0).getInput(); + final Word> answer = + super.oracle.answerQuery(oldQuery.concat(Word.fromCharSequence("dcba"))); + + Assert.assertEquals(getNumberOfPosedQueries(), oldCount); + + for (int i = 0; i < answer.length(); i++) { + final OutputAndLocalInputs symbol = answer.getSymbol(i); + + if (i < oldQuery.size()) { + Assert.assertNotNull(symbol.getOutput()); + Assert.assertFalse(symbol.getLocalInputs().isEmpty()); + } else { + Assert.assertNull(symbol.getOutput()); + Assert.assertTrue(symbol.getLocalInputs().isEmpty()); + + } + } + } +} + 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..48bb051bd5 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/mealy/SymbolQueryCacheTest.java @@ -0,0 +1,76 @@ +/* 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.cache.mealy; + +import de.learnlib.driver.util.MealySimulatorSUL; +import de.learnlib.filter.cache.AbstractCacheTest; +import de.learnlib.filter.cache.CacheTestUtils; +import de.learnlib.filter.statistic.oracle.CounterSymbolQueryOracle; +import de.learnlib.oracle.membership.SULSymbolQueryOracle; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class SymbolQueryCacheTest + extends AbstractCacheTest, MealyMachine, 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 SymbolQueryCache getCachedOracle() { + return new SymbolQueryCache<>(counter, getAlphabet()); + } + + @Override + protected SymbolQueryCache getResumedOracle(SymbolQueryCache original) { + final SymbolQueryCache fresh = new SymbolQueryCache<>(counter, getAlphabet()); + serializeResumable(original, fresh); + return fresh; + } + + @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..e769bafce7 --- /dev/null +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/AbstractSULCacheTest.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.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.statistic.sul.ResetCounterSUL; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public abstract class AbstractSULCacheTest + extends AbstractCacheTest, MealyMachine, 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 SULCache getCachedOracle() { + return getCache(counter); + } + + @Override + protected SULCache getResumedOracle(SULCache original) { + final SULCache fresh = getCache(counter); + serializeResumable(original, fresh); + return fresh; + } + + @Override + protected long getNumberOfPosedQueries() { + return counter.getStatisticalData().getCount(); + } + + @Override + protected boolean supportsPrefixes() { + return true; + } + + @Override + protected Alphabet getAlphabet() { + return CacheTestUtils.INPUT_ALPHABET; + } + + protected abstract SULCache getCache(SUL delegate); +} diff --git a/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULDAGCacheTest.java similarity index 64% rename from api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java rename to oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULDAGCacheTest.java index 15968ea62b..178516ef4f 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/feature/SupportsGrowingAlphabet.java +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULDAGCacheTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,13 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.api.algorithm.feature; +package de.learnlib.filter.cache.sul; + +import de.learnlib.api.SUL; /** - * @author Maik Merten + * @author frohme */ -public interface SupportsGrowingAlphabet { - - void addAlphabetSymbol(I symbol); +public class SULDAGCacheTest extends AbstractSULCacheTest { + @Override + protected SULCache getCache(SUL delegate) { + return SULCaches.createCache(getAlphabet(), delegate); + } } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/NoSuchRowException.java b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULTreeCacheTest.java similarity index 63% rename from datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/NoSuchRowException.java rename to oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULTreeCacheTest.java index acf922ce5d..884840687c 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/NoSuchRowException.java +++ b/oracles/filters/cache/src/test/java/de/learnlib/filter/cache/sul/SULTreeCacheTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.datastructure.observationtable; +package de.learnlib.filter.cache.sul; -public class NoSuchRowException extends IllegalArgumentException { +import de.learnlib.api.SUL; - private static final long serialVersionUID = 1L; - - public NoSuchRowException() { - } +/** + * @author frohme + */ +public class SULTreeCacheTest extends AbstractSULCacheTest { - public NoSuchRowException(String s) { - super(s); + @Override + protected SULCache getCache(SUL delegate) { + return SULCaches.createTreeCache(getAlphabet(), delegate); } - } diff --git a/oracles/filters/pom.xml b/oracles/filters/pom.xml index 4f1a586db0..41d5c4195a 100644 --- a/oracles/filters/pom.xml +++ b/oracles/filters/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-oracles-parent de.learnlib - 0.13.1 + learnlib-oracles-parent + 0.14.0 ../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 7a74fd692d..336b6f53e9 100644 --- a/oracles/filters/reuse/pom.xml +++ b/oracles/filters/reuse/pom.xml @@ -1,6 +1,6 @@ + 4.0.0 + - learnlib-filters-parent de.learnlib - 0.13.1 + learnlib-filters-parent + 0.14.0 ../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/reuse/src/main/java/de/learnlib/filter/reuse/ReuseCapableOracle.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseCapableOracle.java index a66bfaeab8..30a3256345 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseCapableOracle.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseCapableOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseException.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseException.java index cc3539d1a1..3a3e1a23ae 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseException.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseException.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseOracle.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseOracle.java index 4bd1399cd8..003b5410be 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseOracle.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/ReuseOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/BoundedDeque.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/BoundedDeque.java index 45a30ad48f..a09a3942d4 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/BoundedDeque.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/BoundedDeque.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..ed980b3986 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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) { diff --git a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseNode.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseNode.java index 96bc62f015..7b84f5b235 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseNode.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseNode.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseTree.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseTree.java index 3eb345fb98..26b0ba8e2c 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseTree.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseTree.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseTreeDotHelper.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseTreeDotHelper.java index dfa8b636c8..e67ea32cc3 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseTreeDotHelper.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/ReuseTreeDotHelper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/SystemStateHandler.java b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/SystemStateHandler.java index e3cba7d5d4..5d4fa987a3 100644 --- a/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/SystemStateHandler.java +++ b/oracles/filters/reuse/src/main/java/de/learnlib/filter/reuse/tree/SystemStateHandler.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..4486dea999 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/LearningTest.java b/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/LearningTest.java index ef92c92fa3..c4b539fcad 100644 --- a/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/LearningTest.java +++ b/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/LearningTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/QuiescenceTest.java b/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/QuiescenceTest.java index 8ec0c7378e..734515178b 100644 --- a/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/QuiescenceTest.java +++ b/oracles/filters/reuse/src/test/java/de/learnlib/filter/reuse/test/QuiescenceTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..32888323d5 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/oracles/filters/statistics/pom.xml b/oracles/filters/statistics/pom.xml index 2c0a90cd07..853c0df7f8 100644 --- a/oracles/filters/statistics/pom.xml +++ b/oracles/filters/statistics/pom.xml @@ -1,6 +1,6 @@ + 4.0.0 + - learnlib-filters-parent de.learnlib - 0.13.1 + learnlib-filters-parent + 0.14.0 ../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/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..82896a0d62 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/filters/statistics/src/main/java/de/learnlib/filter/statistic/Counter.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/Counter.java index b2d43339ce..4e690fb702 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/Counter.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/Counter.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/HistogramDataSet.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/HistogramDataSet.java index 8b80b2a98d..de7f9f935a 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/HistogramDataSet.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/HistogramDataSet.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..f13f3eb444 --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/learner/RefinementCounterLearner.java @@ -0,0 +1,95 @@ +/* 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.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.transducers.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/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterOracle.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterOracle.java index 3b8e752bfe..59fab6f046 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterOracle.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..db08a3683d --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterSymbolQueryOracle.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.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(); + } +} diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/HistogramOracle.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/HistogramOracle.java index 5ff2c0e49f..cb0c5f2c27 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/HistogramOracle.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/HistogramOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/JointCounterOracle.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/JointCounterOracle.java index 55025f3a09..cf459b343b 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/JointCounterOracle.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/JointCounterOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..ce807abb65 --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/ResetCounterObservableSUL.java @@ -0,0 +1,69 @@ +/* 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 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..342b9bdf64 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/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/SymbolCounterObservableSUL.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterObservableSUL.java new file mode 100644 index 0000000000..2fead87dfc --- /dev/null +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/sul/SymbolCounterObservableSUL.java @@ -0,0 +1,69 @@ +/* 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 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..94172dbd27 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/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/filters/statistics/src/test/java/de/learnlib/filter/statistic/CounterOracleTest.java b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/CounterOracleTest.java index 806ce8c7ec..6706e414f8 100644 --- a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/CounterOracleTest.java +++ b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/CounterOracleTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/oracles/ConstantOutputOracle.java b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/oracles/ConstantOutputOracle.java index 4d9fa19604..93b98cc840 100644 --- a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/oracles/ConstantOutputOracle.java +++ b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/oracles/ConstantOutputOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/oracles/NoopOracle.java b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/oracles/NoopOracle.java index b7fd53a4ae..5039532d0f 100644 --- a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/oracles/NoopOracle.java +++ b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/oracles/NoopOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/AbstractTestQueries.java b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/AbstractTestQueries.java index 267df734a1..c1b77fb8b1 100644 --- a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/AbstractTestQueries.java +++ b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/AbstractTestQueries.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/NoopQuery.java b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/NoopQuery.java index b8c78c342a..86b944399f 100644 --- a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/NoopQuery.java +++ b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/NoopQuery.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/UnanswerableQuery.java b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/UnanswerableQuery.java index ba41433d76..e056856d32 100644 --- a/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/UnanswerableQuery.java +++ b/oracles/filters/statistics/src/test/java/de/learnlib/filter/statistic/queries/UnanswerableQuery.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/membership-oracles/pom.xml b/oracles/membership-oracles/pom.xml index ecd694090f..ea80b39025 100644 --- a/oracles/membership-oracles/pom.xml +++ b/oracles/membership-oracles/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-oracles-parent de.learnlib - 0.13.1 + learnlib-oracles-parent + 0.14.0 ../pom.xml learnlib-membership-oracles + LearnLib :: Oracles :: Membership Oracles A collection of membership oracles @@ -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..8b75894bfe --- /dev/null +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/AbstractSULOmegaOracle.java @@ -0,0 +1,321 @@ +/* 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.ArrayList; +import java.util.Collection; +import java.util.List; + +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 (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. + * + * @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() { + if (sul.canFork()) { + return localSul.get(); + } else { + 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, 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, Integer> answerQuery(ObservableSUL sul, Word prefix, Word loop, int repeat) + throws SULException { + assert repeat > 0; + sul.pre(); + try { + 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); + + for (int i = 0; i < prefix.length(); i++) { + outputBuilder.append(sul.step(prefix.getSymbol(i))); + } + 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); + + int prefixLength = prefix.length(); + for (Q q: states) { + 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); + } finally { + sul.post(); + } + } + + @Override + public MealyMembershipOracle getMembershipOracle() { + 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) { + if (!s1.equals(s2)) { + 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(); + final ObservableSUL sul2 = forkedSUL; + + // assert sul1 is already in the correct state + assert s1.equals(sul1.getState().hashCode()); + + sul2.pre(); + try { + // 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 { + sul2.post(); + } + } + } + } + + /** + * 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/FilterChain.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/FilterChain.java index fa711dd224..a3bd69d39a 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/FilterChain.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/FilterChain.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/MappedOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/MappedOracle.java index 2838ce2d65..105051c40d 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/MappedOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/MappedOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..a6ef9208ba 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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 diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SULSymbolQueryOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SULSymbolQueryOracle.java index 63278ff1cd..e1f76a650d 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SULSymbolQueryOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SULSymbolQueryOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..20de4141eb --- /dev/null +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOmegaOracle.java @@ -0,0 +1,182 @@ +/* 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.ArrayList; +import java.util.Collection; +import java.util.List; + +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; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.transducers.MealyMachine; +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. + * + * @author Jeroen Meijer + * + * @see SimulatorOracle + * + * @param the state type. + * @param the input type. + * @param the output type. + */ +public class SimulatorOmegaOracle + implements SingleQueryOmegaOracle { + + /** + * The automaton to simulate. + */ + private final SimpleDTS simpleDTS; + + /** + * @see #getMembershipOracle() + */ + private final SimulatorOracle simulatorOracle; + + /** + * Constructs a new {@link SimulatorOmegaOracle}. + * + * @param automaton the automaton to simulate. + * @param simulatorOracle the {@link SimulatorOracle} used to answer {@link Query}s. + * @param the automaton type. + */ + public & SimpleDTS> SimulatorOmegaOracle(A automaton, SimulatorOracle simulatorOracle) { + this.simpleDTS = automaton; + this.simulatorOracle = simulatorOracle; + } + + /** + * Gets the {@link SimulatorOracle} used to answer {@link de.learnlib.api.query.Query}s. + * + * @return the SimulatorOracle. + */ + @Override + public MembershipOracle getMembershipOracle() { + 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 + * two access sequences to states in the simulated automaton. + * + * @see OmegaQueryAnswerer#answerQuery(Word, Word, int) + */ + @Override + 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 = 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(null, -1); + } + + public static class DFASimulatorOmegaOracle + extends SimulatorOmegaOracle + implements DFAOmegaMembershipOracle { + + private final DFA automaton; + + public DFASimulatorOmegaOracle(DFA automaton) { + super(automaton, new DFASimulatorOracle<>(automaton)); + this.automaton = automaton; + } + + @Override + public DFAMembershipOracle getMembershipOracle() { + return new DFASimulatorOracle<>(automaton); + } + } + + public static class MealySimulatorOmegaOracle + extends SimulatorOmegaOracle> + implements MealyOmegaMembershipOracle { + + private final MealyMachine automaton; + + public MealySimulatorOmegaOracle(MealyMachine automaton) { + super(automaton, new MealySimulatorOracle<>(automaton)); + this.automaton = automaton; + } + + @Override + public MealyMembershipOracle getMembershipOracle() { + return new MealySimulatorOracle<>(automaton); + } + } +} diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOracle.java index 8b30f2263e..a6d4d4a5f9 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOracle.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ 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.automata.transducers.MealyMachine; import net.automatalib.words.Word; /** 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/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..01faf3d9b8 --- /dev/null +++ b/oracles/membership-oracles/src/test/java/de/learnlib/oracle/membership/SimulatorOmegaOracleTest.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.oracle.membership; + +import java.util.ArrayList; +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.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).getLoop().size(), 3); + Assert.assertEquals(queries.get(1).getLoop().size(), 3); + + oracle.processQueries(queries); + + // Paul loves Mary... + 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); + } +} 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 97% 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..a589ee23c9 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,7 +30,7 @@ /** * @author Maik Merten */ -public class OracleTest { +public class SimulatorOracleTest { @Test public void testDFASimulatorOracle() { diff --git a/oracles/parallelism/pom.xml b/oracles/parallelism/pom.xml index 91698999c1..d12262ad47 100644 --- a/oracles/parallelism/pom.xml +++ b/oracles/parallelism/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-oracles-parent de.learnlib - 0.13.1 + learnlib-oracles-parent + 0.14.0 ../pom.xml learnlib-parallelism + LearnLib :: Oracles :: Parallelism Support for parallelizing membership queries @@ -44,6 +44,14 @@ limitations under the License. net.automatalib automata-api + + net.automatalib + automata-commons-util + + + net.automatalib + automata-commons-smartcollections + com.google.guava diff --git a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/AbstractQueriesJob.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/AbstractQueriesJob.java index 942544545b..7f2f933f4c 100644 --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/AbstractQueriesJob.java +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/AbstractQueriesJob.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..74830a4e8b 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/DynamicParallelOracleBuilder.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicParallelOracleBuilder.java index 3f45f72db8..b48ab0c441 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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.smartcollections.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/DynamicQueriesJob.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicQueriesJob.java index 1e4098f9ba..5ab5d92a01 100644 --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicQueriesJob.java +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/DynamicQueriesJob.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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..7534f26746 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..604af29a68 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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/ParallelOracleInterruptedException.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracleInterruptedException.java
    index 255f6436b5..aaebebed82 100644
    --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracleInterruptedException.java
    +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/ParallelOracleInterruptedException.java
    @@ -1,4 +1,4 @@
    -/* Copyright (C) 2013-2018 TU Dortmund
    +/* Copyright (C) 2013-2019 TU Dortmund
      * This file is part of LearnLib, http://www.learnlib.de/.
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
    diff --git a/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..0b6f2ce543 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
    @@ -1,4 +1,4 @@
    -/* Copyright (C) 2013-2018 TU Dortmund
    +/* Copyright (C) 2013-2019 TU Dortmund
      * This file is part of LearnLib, http://www.learnlib.de/.
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
    @@ -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
    @@ -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/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..d97f27e82d 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
    @@ -1,4 +1,4 @@
    -/* Copyright (C) 2013-2018 TU Dortmund
    +/* Copyright (C) 2013-2019 TU Dortmund
      * This file is part of LearnLib, http://www.learnlib.de/.
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
    @@ -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/main/java/de/learnlib/oracle/parallelism/StaticQueriesJob.java b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticQueriesJob.java
    index 334e906797..2d6641d305 100644
    --- a/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticQueriesJob.java
    +++ b/oracles/parallelism/src/main/java/de/learnlib/oracle/parallelism/StaticQueriesJob.java
    @@ -1,4 +1,4 @@
    -/* Copyright (C) 2013-2018 TU Dortmund
    +/* Copyright (C) 2013-2019 TU Dortmund
      * This file is part of LearnLib, http://www.learnlib.de/.
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
    diff --git a/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..413a0575f3 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
    @@ -1,4 +1,4 @@
    -/* Copyright (C) 2013-2018 TU Dortmund
    +/* Copyright (C) 2013-2019 TU Dortmund
      * This file is part of LearnLib, http://www.learnlib.de/.
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
    @@ -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..0ef007605e 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
    @@ -1,4 +1,4 @@
    -/* Copyright (C) 2013-2018 TU Dortmund
    +/* Copyright (C) 2013-2019 TU Dortmund
      * This file is part of LearnLib, http://www.learnlib.de/.
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
    @@ -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
    diff --git a/oracles/pom.xml b/oracles/pom.xml
    index 8fa0d6a20c..26cc92c930 100644
    --- a/oracles/pom.xml
    +++ b/oracles/pom.xml
    @@ -1,6 +1,6 @@
     
     
     
    -
         4.0.0
     
         
    -        learnlib-build-parent
             de.learnlib
    -        0.13.1
    +        learnlib-build-parent
    +        0.14.0
             ../build-parent/pom.xml
         
     
         learnlib-oracles-parent
    +    pom
    +
         LearnLib :: Oracles
         Parent module for oracles and oracle-related modules
     
    -    pom
    -
         
    +        emptiness-oracles
    +        equivalence-oracles
             filters
             membership-oracles
    -        equivalence-oracles
             parallelism
    +        property-oracles
         
    -
    -
    \ No newline at end of file
    +
    diff --git a/oracles/property-oracles/pom.xml b/oracles/property-oracles/pom.xml
    new file mode 100644
    index 0000000000..18687b4711
    --- /dev/null
    +++ b/oracles/property-oracles/pom.xml
    @@ -0,0 +1,36 @@
    +
    +
    +    4.0.0
    +
    +    
    +        de.learnlib
    +        learnlib-oracles-parent
    +        0.14.0
    +        ../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..0eda6c4224
    --- /dev/null
    +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/AbstractPropertyOracle.java
    @@ -0,0 +1,97 @@
    +/* 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.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 modelCheck(A hypothesis, Collection inputs); + + @Nullable + @Override + 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 = 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 new file mode 100644 index 0000000000..4116885f07 --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFAFinitePropertyOracle.java @@ -0,0 +1,51 @@ +/* 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.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 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 new file mode 100644 index 0000000000..700ca6cc2a --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/DFALassoPropertyOracle.java @@ -0,0 +1,52 @@ +/* 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.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 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 new file mode 100644 index 0000000000..8c85575fa0 --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyFinitePropertyOracle.java @@ -0,0 +1,56 @@ +/* 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.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.transducers.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 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 new file mode 100644 index 0000000000..86cbd4005a --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/MealyLassoPropertyOracle.java @@ -0,0 +1,56 @@ +/* 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.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.transducers.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 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..72ba83d276 --- /dev/null +++ b/oracles/property-oracles/src/main/java/de/learnlib/oracle/property/PropertyOracleChain.java @@ -0,0 +1,147 @@ +/* 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.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.transducers.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); + } + } +} diff --git a/pom.xml b/pom.xml index 53c914e0da..fd2370c4ab 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 de.learnlib learnlib-parent - 0.13.1 + 0.14.0 pom + LearnLib - http://learnlib.github.io/learnlib/maven-site/${project.version} A framework for active automata learning and experimentation - + http://learnlib.github.io/learnlib/maven-site/${project.version} Apache License, Version 2.0 @@ -37,35 +36,6 @@ limitations under the License. - - https://github.com/LearnLib/learnlib/issues - GitHub Issues - - - - - 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 - - - mtf90 @@ -121,16 +91,41 @@ limitations under the License. + + + Jeroen Meijer + j.j.g.meijer@utwente.nl + University of Twente, Formal Methods and Tools + http://fmt.cs.utwente.nl/ + + Developer + + + - - - 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 - + + + 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 + learnlib-0.14.0 + + + https://github.com/LearnLib/learnlib/issues + GitHub Issues + + + Travis + https://travis-ci.org/LearnLib/automatalib + + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + + + local + file://${user.home}/learnlib-site + + + @@ -163,38 +192,44 @@ limitations under the License. 1.8 3.0.1 - 3.0.0 + 3.1.0 3.0.0 - 2.17 + 3.0.0 + 3.8.0 4.3.0 - 3.0.1 - 1.4.1 + 3.1.1 + 3.0.0-M1 + 3.0.0-M2 1.6.0 - 2.20 - 3.0.5 + 2.22.1 1.6 - 2.9 - 0.7.9 - 2.10.4 + 3.0.0 + 0.8.2 + 3.0.1 1.0.0 - 3.8 + 3.10.0 2.5.3 3.0.2 - 1.1 - 3.6 + 3.0.0 + 3.7.1 3.0.1 - 2.20 - 1.1 + 3.1.7 + 2.22.1 + 1.1.0 - 0.7.1 + 0.8.0 0.1 - 8.1 + 1.9 + 8.14 3.0.2 - 22.0 + 27.0-jre + 1.43 1.2.3 + 1.7 + 2.23.0 1.7.25 - 6.11 + 6.14.3 http://docs.oracle.com/javase/8/docs/api/ @@ -202,696 +237,135 @@ 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-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.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 - - - - - - + + + de.learnlib + learnlib-api + ${project.version} + - - - - - 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 + de.learnlib.archetypes + learnlib-archetypes-parent ${project.version} pom - de.learnlib - learnlib-algorithms-active-parent + de.learnlib.archetypes + basic ${project.version} - pom - de.learnlib - learnlib-adt + de.learnlib.archetypes + complete ${project.version} + + de.learnlib - learnlib-dhc + learnlib-build-parent ${project.version} + pom + + de.learnlib - learnlib-discrimination-tree + learnlib-build-tools ${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 - learnlib-build-parent - ${project.version} - pom - - - - - de.learnlib - learnlib-build-tools - ${project.version} - - - + + de.learnlib learnlib-commons-parent @@ -993,6 +467,11 @@ limitations under the License. ${project.version} pom + + de.learnlib + learnlib-emptiness-oracles + ${project.version} + de.learnlib learnlib-equivalence-oracles @@ -1028,6 +507,11 @@ limitations under the License. learnlib-parallelism ${project.version} + + de.learnlib + learnlib-property-oracles + ${project.version} + @@ -1048,6 +532,12 @@ limitations under the License. ${project.version} test + + de.learnlib.testsupport + learnlib-test-support + ${project.version} + test + @@ -1066,6 +556,29 @@ limitations under the License. test + + + org.mockito + mockito-core + ${mockito.version} + test + + + + + org.jmockit + jmockit + ${jmockit.version} + test + + + + + net.java.openjdk.cacio + cacio-tta + ${cacio.version} + test + @@ -1090,6 +603,13 @@ limitations under the License. provided + + org.kohsuke.metainf-services + metainf-services + ${metainf-services.version} + provided + + org.slf4j slf4j-api @@ -1112,22 +632,572 @@ limitations under the License. - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - - - local - file://${user.home}/learnlib-site - - + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${dependency-plugin.version} + + + org.apache.maven.plugins + maven-deploy-plugin + ${deploy-plugin.version} + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle-plugin.version} + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd-plugin.version} + + true + true + false + + target/generated-sources + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-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 + ${maven.compiler.source} + 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.codehaus.mojo + tidy-maven-plugin + ${tidy-pom.version} + + + + + + org.apache.maven.plugins + maven-site-plugin + + + attach-descriptor + false + + attach-descriptor + + + + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + + index + licenses + team + mailing-lists + scm + issue-management + ci-management + dependencies + dependency-info + modules + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + true + ${maven.compiler.source} + 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 + tidy-maven-plugin + + + validate + verify + + check + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + analyze + + + analyze-only + + + true + + true + + + + + + + + + + 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 56a8af2bb1..21ea6fd90c 100644 --- a/test-support/learner-it-support/pom.xml +++ b/test-support/learner-it-support/pom.xml @@ -1,6 +1,6 @@ + compile + de.learnlib @@ -74,8 +84,8 @@ limitations under the License. org.testng testng - compile + compile + - 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 6a851dc7e9..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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.oracle.membership.SimulatorOracle; +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; @@ -50,7 +54,16 @@ protected DFA getTarget(Alphabet alphabet) { @Override protected MembershipOracle getOracle(DFA target) { - return new SimulatorOracle<>(target); + 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 e78c4a055c..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,13 +16,17 @@ 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.oracle.membership.SimulatorOracle; -import net.automatalib.automata.transout.MealyMachine; +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; import net.automatalib.words.Word; @@ -54,7 +58,15 @@ protected Collection getAlphabetExtensions() { @Override protected MembershipOracle> getOracle(MealyMachine target) { - return new SimulatorOracle<>(target); + return ((QueryAnswerer>) 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 00f1c6bc60..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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.SupportsGrowingAlphabet; 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); diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java index da1b676a6f..eec91a845f 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerDFATest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,10 +18,12 @@ import java.io.Serializable; import java.util.Random; +import de.learnlib.api.Resumable; 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.oracle.membership.SimulatorOracle; +import de.learnlib.api.oracle.QueryAnswerer; +import de.learnlib.oracle.equivalence.SimulatorEQOracle.DFASimulatorEQOracle; import net.automatalib.automata.fsa.DFA; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; @@ -30,7 +32,7 @@ /** * @author bainczyk */ -public abstract class AbstractResumableLearnerDFATest & LearningAlgorithm, Character, Boolean>, T extends Serializable> +public abstract class AbstractResumableLearnerDFATest & LearningAlgorithm, Character, Boolean>, T extends Serializable> extends AbstractResumableLearnerTest, MembershipOracle, Character, Boolean, T> { private static final int AUTOMATON_SIZE = 50; @@ -47,7 +49,12 @@ protected DFA getTarget(Alphabet alphabet) { @Override protected MembershipOracle getOracle(DFA target) { - return new SimulatorOracle<>(target); + return ((QueryAnswerer) target::computeSuffixOutput).asOracle(); + } + + @Override + protected DFAEquivalenceOracle getEquivalenceOracle(DFA target) { + return new DFASimulatorEQOracle<>(target); } } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java index db2995aa6f..9d946971ed 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMealyTest.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,11 +18,13 @@ import java.io.Serializable; import java.util.Random; +import de.learnlib.api.Resumable; 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.oracle.membership.SimulatorOracle; -import net.automatalib.automata.transout.MealyMachine; +import de.learnlib.api.oracle.QueryAnswerer; +import de.learnlib.oracle.equivalence.SimulatorEQOracle.MealySimulatorEQOracle; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.util.automata.random.RandomAutomata; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -31,7 +33,7 @@ /** * @author bainczyk */ -public abstract class AbstractResumableLearnerMealyTest & LearningAlgorithm, Character, Word>, T extends Serializable> +public abstract class AbstractResumableLearnerMealyTest & LearningAlgorithm, Character, Word>, T extends Serializable> extends AbstractResumableLearnerTest, MembershipOracle>, Character, Word, T> { private static final int AUTOMATON_SIZE = 20; @@ -51,6 +53,11 @@ protected Alphabet getInitialAlphabet() { @Override protected MembershipOracle> getOracle(MealyMachine target) { - return new SimulatorOracle<>(target); + return ((QueryAnswerer>) target::computeSuffixOutput).asOracle(); + } + + @Override + protected MealyEquivalenceOracle getEquivalenceOracle(MealyMachine target) { + return new MealySimulatorEQOracle<>(target); } } 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..be27bc5c04 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,24 +21,36 @@ import java.io.ObjectOutputStream; import java.io.Serializable; +import de.learnlib.api.Resumable; 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; /** - * Test class that checks the workflow of a learning algorithm that implements {@link ResumableLearner}. + * Test class that checks the workflow of a learning algorithm that implements {@link Resumable}. + * + * @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++; } @@ -122,6 +139,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); } } 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..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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; @@ -37,7 +38,7 @@ * * @author Malte Isberner */ -public abstract class AbstractDFALearnerIT extends AbstractLearnerIT { +public abstract class AbstractDFALearnerIT { @Factory public Object[] createExampleITCases() { @@ -58,7 +59,9 @@ 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, + new SimulatorEQOracle<>(example.getReferenceAutomaton())); } /** 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..c36e216bd1 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -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..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,10 +21,11 @@ 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; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import org.testng.annotations.Factory; @@ -38,7 +39,7 @@ * * @author Malte Isberner */ -public abstract class AbstractMealyLearnerIT extends AbstractLearnerIT { +public abstract class AbstractMealyLearnerIT { @Factory public Object[] createExampleITCases() { @@ -60,7 +61,9 @@ public Object[] createExampleITCases() { final MealyLearnerVariantListImpl variants = new MealyLearnerVariantListImpl<>(); addLearnerVariants(alphabet, mqOracle, variants); - return super.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/AbstractMealyPassiveLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealyPassiveLearnerIT.java index b47833d922..1e611d3966 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ import de.learnlib.examples.LearningExample; import de.learnlib.examples.LearningExamples; import de.learnlib.examples.PassiveLearningExample; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import org.testng.annotations.Factory; @@ -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..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,11 +22,12 @@ 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; import de.learnlib.util.mealy.MealyUtil; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import org.testng.annotations.Factory; @@ -40,7 +41,7 @@ * * @author Malte Isberner */ -public abstract class AbstractMealySymLearnerIT extends AbstractLearnerIT { +public abstract class AbstractMealySymLearnerIT { @Factory public Object[] createExampleITCases() { @@ -62,7 +63,9 @@ 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(), + 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/AbstractVPDALearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractVPDALearnerIT.java index e793f5ed63..6a561f7ac7 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractVPDALearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractVPDALearnerIT.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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 65% 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..46fe443393 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,35 +20,60 @@ 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; 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 > 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, eqOracle)); + } + + 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 +87,7 @@ protected > List & SuffixOutput> Collection> generateSamples( + public static & SuffixOutput> Collection> generateSamples( Alphabet alphabet, M reference) { @@ -87,5 +112,4 @@ protected > List & 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 ff0f60d09d..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,9 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +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 3a04d7e188..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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,9 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.util.mealy.MealyUtil; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +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/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariant.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariant.java index 473255a44c..680f9089a6 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariant.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariant.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantList.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantList.java index 1426b09b4d..ce75221d07 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantList.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantList.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ import de.learnlib.api.algorithm.PassiveLearningAlgorithm; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Word; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantListImpl.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantListImpl.java index e06ef149a2..0638816593 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantListImpl.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantListImpl.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import de.learnlib.api.algorithm.PassiveLearningAlgorithm; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.transout.MealyMachine; +import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; public class PassiveLearnerVariantListImpl implements PassiveLearnerVariantList { diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantTICase.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantTICase.java index e44acef6ca..b2398a142a 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantTICase.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/PassiveLearnerVariantTICase.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/VPDALearnerITCase.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/VPDALearnerITCase.java index 45c0914ae0..f375d18ab5 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/VPDALearnerITCase.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/VPDALearnerITCase.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-support/learning-examples/pom.xml b/test-support/learning-examples/pom.xml index a94aa2e453..1784e70fc3 100644 --- a/test-support/learning-examples/pom.xml +++ b/test-support/learning-examples/pom.xml @@ -1,6 +1,6 @@ + + org.testng + testng + compile + + + + org.mockito + mockito-core + compile + + + + diff --git a/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractBFOracleTest.java b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractBFOracleTest.java new file mode 100644 index 0000000000..222339b4c9 --- /dev/null +++ b/test-support/test-support/src/main/java/de/learnlib/testsupport/AbstractBFOracleTest.java @@ -0,0 +1,82 @@ +/* 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; + +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 AbstractBFOracle}. + * + * @author Jeroen Meijer + */ +public abstract class AbstractBFOracleTest { + + public static final Alphabet ALPHABET = Alphabets.singleton('a'); + + public static final double MULTIPLIER = 2.0; + + private AbstractBFOracle, Character, D> bfo; + + protected abstract AbstractBFOracle, Character, D> createBreadthFirstOracle( + double multiplier); + + @BeforeMethod + public void setUp() { + MockitoAnnotations.initMocks(this); + bfo = createBreadthFirstOracle(MULTIPLIER); + } + + @Test + public void testGetMultiplier() { + Assert.assertEquals(bfo.getMultiplier(), MULTIPLIER); + } + + /** + * 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.epsilon()); + Assert.assertEquals(bfo.nextInput(), Word.fromLetter('a')); + Assert.assertEquals(bfo.nextInput(), Word.fromLetter('b')); + } + + @Test + public void testAddWord() { + bfo.pre(); + bfo.addWord(Word.epsilon()); + Assert.assertEquals(bfo.nextInput(), Word.epsilon()); + } + + @Test + public void testPre() { + bfo.pre(); + bfo.addWord(Word.epsilon()); + bfo.pre(); + Assert.assertEquals(bfo.nextInput(), Word.epsilon()); + } +}

    + * 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 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 Example4() {} + + 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 + @SuppressWarnings("unchecked") + 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. + @SuppressWarnings("unchecked") + 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/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..50207c327b --- /dev/null +++ b/examples/src/main/java/de/learnlib/examples/sli/Example2.java @@ -0,0 +1,213 @@ +/* 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.ArrayList; +import java.util.List; +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; +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.cache.mealy.MealyCacheOracle; +import de.learnlib.filter.cache.mealy.MealyCaches; +import de.learnlib.filter.cache.mealy.StateLocalInputMealyCacheOracle; +import de.learnlib.filter.statistic.sul.ResetCounterStateLocalInputSUL; +import de.learnlib.filter.statistic.sul.SymbolCounterStateLocalInputSUL; +import de.learnlib.oracle.equivalence.EQOracleChain; +import de.learnlib.oracle.equivalence.EQOracleChain.MealyEQOracleChain; +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.Word; +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(false); + runPartialLearner(true); + runTransformedLearner(false); + runTransformedLearner(true); + } + + /** + * Uses the raw {@link StateLocalInputSUL} to infer a (potentially) partial {@link MealyMachine}. + */ + static void runPartialLearner(boolean withCache) { + + // 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 storage for EquivalenceOracle chain, because we want to use the potential cache as well + List, Integer, Word>>> + eqOracles = new ArrayList<>(2); + + if (withCache) { + StateLocalInputMealyCacheOracle mqCache = + MealyCaches.createStateLocalInputTreeCache(mqOracle.definedInputs(Word.epsilon()), mqOracle); + eqOracles.add(mqCache.createStateLocalInputCacheConsistencyTest()); + mqOracle = mqCache; + } + + // construct L* instance + PartialLStarMealy lstar = + new PartialLStarMealyBuilder().withOracle(mqOracle) + .withCexHandler(ObservationTableCEXHandlers.RIVEST_SCHAPIRE) + .create(); + + // here, we simply fallback to an equivalence check for the original automaton model + eqOracles.add(new StateLocalInputMealySimulatorEQOracle<>(TARGET)); + + // construct single EQ oracle + EquivalenceOracle, Integer, Word>> + eqOracle = new EQOracleChain<>(eqOracles); + + // 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("Partial Hypothesis" + (withCache ? ", with cache" : "")); + 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(boolean withCache) { + + // 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 storage for EquivalenceOracle chain, because we want to use the potential cache as well + List>> eqOracles = new ArrayList<>(2); + + if (withCache) { + MealyCacheOracle> mqCache = + MealyCaches.createStateLocalInputTreeCache(INPUTS, mqOracle); + eqOracles.add(mqCache.createCacheConsistencyTest()); + mqOracle = mqCache; + } + + // construct L* instance + ExtensibleLStarMealy> lstar = + new ExtensibleLStarMealyBuilder>().withAlphabet(INPUTS) + .withOracle(mqOracle) + .withCexHandler( + ObservationTableCEXHandlers.RIVEST_SCHAPIRE) + .create(); + + // here, we simply fallback to an equivalence check for the transformed automaton model + eqOracles.add(new MealySimulatorEQOracle<>(TRANSFORMED_TARGET)); + + // construct single EQ oracle + MealyEquivalenceOracle> eqOracle = + new MealyEQOracleChain<>(eqOracles); + + // construct the experiment + MealyExperiment> experiment = + new MealyExperiment<>(lstar, eqOracle, INPUTS); + + // run experiment + experiment.run(); + + // report results + System.out.println("Transformed Hypothesis" + (withCache ? ", with cache" : "")); + System.out.println("-------------------------------------------------------"); + + System.out.println(resetCounter.getStatisticalData().getSummary()); + System.out.println(symbolCounter.getStatisticalData().getSummary()); + + System.out.println("-------------------------------------------------------"); + } + +} 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 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..3644c2639a --- /dev/null +++ b/examples/src/test/java/de/learnlib/examples/ExamplesTest.java @@ -0,0 +1,143 @@ +/* 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; + +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.modelcheckers.ltsmin.LTSminVersion; +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(3, 0, 0); + de.learnlib.examples.bbc.Example1.main(new String[0]); + } + + @Test + public void testBBCExample2() { + checkLTSminAvailability(3, 0, 0); + de.learnlib.examples.bbc.Example2.main(new String[0]); + } + + @Test + public void testBBCExample3() { + 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 + 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(); + + // 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 { + Example1.main(new String[0]); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + @Test + public void testExample2() throws InvocationTargetException, InterruptedException { + checkJVMCompatibility(); + SwingUtilities.invokeAndWait(() -> { + try { + Example2.main(new String[0]); + } catch (IOException | NoSuchMethodException e) { + throw new RuntimeException(e); + } + }); + } + + @Test + public void testExample3() throws InvocationTargetException, InterruptedException { + checkJVMCompatibility(); + SwingUtilities.invokeAndWait(() -> Example3.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(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"); + } + } + +} diff --git a/oracles/emptiness-oracles/pom.xml b/oracles/emptiness-oracles/pom.xml new file mode 100644 index 0000000000..166e8702c8 --- /dev/null +++ b/oracles/emptiness-oracles/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + + de.learnlib + learnlib-oracles-parent + 0.14.0 + ../pom.xml + + + learnlib-emptiness-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 + + + net.automatalib + automata-util + + + net.automatalib + automata-api + + + + org.testng + testng + + + org.mockito + mockito-core + + + de.learnlib.testsupport + learnlib-test-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..1351031685 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracle.java @@ -0,0 +1,56 @@ +/* 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.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..b4555722ef --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracle.java @@ -0,0 +1,29 @@ +/* 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.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..43a204a5ab --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImpl.java @@ -0,0 +1,29 @@ +/* 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.emptiness; + +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.DFALasso; + +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 new file mode 100644 index 0000000000..16ee66d1d6 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/LassoEmptinessOracleImpl.java @@ -0,0 +1,70 @@ +/* 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.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 net.automatalib.automata.concepts.Output; +import net.automatalib.modelchecking.Lasso; +import net.automatalib.words.Word; + +public class LassoEmptinessOracleImpl, S, I, D> + implements LassoEmptinessOracle, LassoOracle { + + /** + * The {@link OmegaMembershipOracle} used to answer {@link OmegaQuery}s. + */ + private final OmegaMembershipOracle omegaMembershipOracle; + + public LassoEmptinessOracleImpl(OmegaMembershipOracle omegaMembershipOracle) { + this.omegaMembershipOracle = omegaMembershipOracle; + } + + public OmegaMembershipOracle getOmegaMembershipOracle() { + return omegaMembershipOracle; + } + + @Override + 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(Output hypothesis, Iterable input, @Nullable D output) { + return LassoEmptinessOracle.super.isCounterExample(hypothesis, input, output); + } + + @Nullable + @Override + public DefaultQuery findCounterExample(L hypothesis, Collection inputs) { + return LassoOracle.super.findCounterExample(hypothesis, inputs); + } + + @Override + public boolean isOmegaCounterExample(boolean isUltimatelyPeriodic) { + return LassoEmptinessOracle.super.isOmegaCounterExample(isUltimatelyPeriodic); + } +} 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..83e6f18735 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracle.java @@ -0,0 +1,30 @@ +/* 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.emptiness; + +import de.learnlib.api.oracle.AutomatonOracle; +import de.learnlib.api.oracle.EmptinessOracle; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.transducers.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..051fe5f234 --- /dev/null +++ b/oracles/emptiness-oracles/src/main/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImpl.java @@ -0,0 +1,30 @@ +/* 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.emptiness; + +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.MealyLasso; +import net.automatalib.words.Word; + +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/AbstractBFEmptinessOracleTest.java b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java new file mode 100644 index 0000000000..8986007ab0 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractBFEmptinessOracleTest.java @@ -0,0 +1,70 @@ +/* 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.emptiness; + +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.testsupport.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 emptiness oracle. + * + * @author Jeroen Meijer + */ +public abstract class AbstractBFEmptinessOracleTest, D> + extends AbstractBFOracleTest { + + private AbstractBFEmptinessOracle bfeo; + + private A automaton; + + private DefaultQuery query; + + protected abstract AbstractBFEmptinessOracle createBreadthFirstEmptinessOracle(); + + protected abstract A createAutomaton(); + + protected abstract DefaultQuery createQuery(); + + @BeforeMethod + public void setUp() { + super.setUp(); + bfeo = createBreadthFirstEmptinessOracle(); + automaton = createAutomaton(); + 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(cex, query); + } + + @Test + public void testIsCounterExample() { + 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..cf4f5661e4 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/AbstractLassoEmptinessOracleImplTest.java @@ -0,0 +1,103 @@ +/* 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.emptiness; + +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +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.Mockito; +import org.mockito.MockitoAnnotations; +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> { + + public static final Alphabet ALPHABET = Alphabets.singleton('a'); + + 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() { + MockitoAnnotations.initMocks(this); + leo = createLassoEmptinessOracleImpl(); + automaton = createAutomaton(); + query = createQuery(); + output = createOutput(); + } + + @Test + public void testProcessInput() { + 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()); + + 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); + } + + @Test + public void testFindCounterExample() { + final DefaultQuery cex = leo.findCounterExample(automaton, ALPHABET); + Assert.assertEquals(cex, query); + } + + @Test + public void testIsCounterExample() { + 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..89133aabf2 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFABFEmptinessOracleTest.java @@ -0,0 +1,66 @@ +/* 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.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() { + return AutomatonBuilders.forDFA(new CompactDFA<>(ALPHABET)). + from("q0").on('a').loop().withAccepting("q0").withInitial("q0").create(); + } + + @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..d77e11c1ca --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/DFALassoEmptinessOracleImplTest.java @@ -0,0 +1,79 @@ +/* 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.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..88e0eb2323 --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyBFEmptinessOracleTest.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.oracle.emptiness; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.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..30357e0d9a --- /dev/null +++ b/oracles/emptiness-oracles/src/test/java/de/learnlib/oracle/emptiness/MealyLassoEmptinessOracleImplTest.java @@ -0,0 +1,80 @@ +/* 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.emptiness; + +import de.learnlib.api.oracle.OmegaMembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.api.query.OmegaQuery; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.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 b2dffeb6f3..b3500699ee 100644 --- a/oracles/equivalence-oracles/pom.xml +++ b/oracles/equivalence-oracles/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 - learnlib-oracles-parent de.learnlib - 0.13.1 + learnlib-oracles-parent + 0.14.0 ../pom.xml learnlib-equivalence-oracles + LearnLib :: Oracles :: Equivalence Oracles A collection of equivalence oracles @@ -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-test-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..be80dab0ab --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractBFInclusionOracle.java @@ -0,0 +1,53 @@ +/* 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; + +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/AbstractTestWordEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java index 5f970fb28a..da44e9f900 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 TU Dortmund +/* Copyright (C) 2013-2019 TU Dortmund * This file is part of LearnLib, http://www.learnlib.de/. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,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; @@ -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 -> { @@ -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()); 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..59d11e65ae --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CExFirstOracle.java @@ -0,0 +1,114 @@ +/* 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; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +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.transducers.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. + *