Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a25f85e
feat: lsharp
tiferrei Nov 24, 2023
eff33af
fix: LSoracle Rule3 SepSeq mode
tiferrei Nov 24, 2023
292f73b
fix: tidy pom
tiferrei Nov 24, 2023
9063d00
chore: tidy imports
tiferrei Nov 24, 2023
84091e0
chore: spotbugs
tiferrei Nov 24, 2023
df6bd5b
chore: spotbugs
tiferrei Nov 24, 2023
64cb06f
chore: spotbugs
tiferrei Nov 24, 2023
e085263
chore: spotbugs
tiferrei Nov 24, 2023
1d9c6e5
chore: spotbugs
tiferrei Nov 24, 2023
4bb54ab
chore: pmd
tiferrei Nov 24, 2023
51f362e
chore: pmd
tiferrei Nov 24, 2023
7695c3d
chore: pmd
tiferrei Nov 24, 2023
7ebb34b
chore: pmd
tiferrei Nov 24, 2023
9481acc
chore: pmd
tiferrei Nov 24, 2023
81e8cc7
chore: pmd
tiferrei Nov 25, 2023
4f43440
chore: checkstyle
tiferrei Nov 27, 2023
ca93112
chore: checkstyle
tiferrei Nov 27, 2023
b2402f2
chore: checkstyle
tiferrei Nov 27, 2023
6e91dff
chore: checkstyle
tiferrei Nov 27, 2023
74bf41f
fix: use SymbolQueryOracle instead of MembershipOracle in LSharp
tiferrei Jan 13, 2025
788bad6
chore: update CI
tiferrei Jan 13, 2025
616e48e
chore: update CI
tiferrei Jan 13, 2025
884ae3f
chore: remove L# test. I couldn't get it to work with MealyIT given t…
tiferrei Jan 13, 2025
6e5a1b4
Merge branch 'develop' into feat/lsharp
mtf90 Jan 25, 2025
8944920
update to latest refactorings
mtf90 Jan 25, 2025
2c106c6
restore old integration test
mtf90 Jan 25, 2025
af2bda6
initial cleanup
mtf90 Jan 25, 2025
2906e50
replace LSMealyMachine with CompactMealy
mtf90 Jan 25, 2025
b77b096
determinize integration tests
mtf90 Jan 25, 2025
e1b42d1
de-stream-ify code
mtf90 Jan 25, 2025
cee5dac
do not use exceptions for control flow
mtf90 Jan 26, 2025
d77c4c2
cleanup dependencies
mtf90 Jan 26, 2025
b27294b
fix issues reported by checkerframework
mtf90 Jan 26, 2025
dac8dd7
include into existing hierarchies
mtf90 Jan 26, 2025
23297f7
general cleanups
mtf90 Jan 26, 2025
45e0e8a
documentation
mtf90 Jan 26, 2025
a2d6e45
ignore LSharp builder in coverage
mtf90 Jan 26, 2025
e148d9b
add comment detailing the scope of the implementation
mtf90 Jan 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added

* LearnLib now supports JPMS modules. All artifacts now provide a `module-info` descriptor except of the distribution artifacts (for Maven-less environments) which only provide an `Automatic-Module-Name` due to non-modular dependencies. Note that while this is a Java 9+ feature, LearnLib still supports Java 8 byte code for the remaining class files.
* Added the L# active learning algorithm (thanks to [Tiago Ferreira](https://github.com/tiferrei)).
* The `ADTLearner` has been refactored to no longer use the (now-removed) `SymbolQueryOracle` but a new `AdaptiveMembershipOracle` instead which supports answering queries in parallel (thanks to [Leon Vitorovic](https://github.com/leonthalee)).
* Added an `InterningMembershipOracle` (including refinements) to the `learnlib-cache` artifact that interns query responses to reduce memory consumption of large data structures. This exports the internal concepts of the DHC learner (which no longer interns query responses automatically).
* `StaticParallelOracleBuilder` now supports custom executor services.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Currently, the following learning algorithms with respective target models are s
| DHC | `Mealy` | | | |
| Kearns & Vazirani | `DFA` `Mealy` | | | |
| Lambda | `DFA` `Mealy` | | | |
| L# | `Mealy` | | | |
| L* (incl. variants) | `DFA` `Mealy` `Moore` | | | |
| NL* | `NFA` | | | |
| Observation Pack | `DFA` `Mealy` `Moore` `VPA` | | | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import de.learnlib.oracle.membership.MealySimulatorOracle;
import de.learnlib.oracle.membership.SULAdaptiveOracle;
import de.learnlib.sul.SUL;
import de.learnlib.testsupport.MQ2AQWrapper;
import de.learnlib.testsupport.it.learner.AbstractMealyLearnerIT;
import de.learnlib.testsupport.it.learner.LearnerVariantList;
import de.learnlib.util.Experiment.MealyExperiment;
Expand Down
94 changes: 94 additions & 0 deletions algorithms/active/lsharp/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?xml version="1.0"?>
<!--
Copyright (C) 2013-2025 TU Dortmund University
This file is part of LearnLib <https://learnlib.de>.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>de.learnlib</groupId>
<artifactId>learnlib-algorithms-active-parent</artifactId>
<version>0.18.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>learnlib-lsharp</artifactId>

<name>LearnLib :: Algorithms :: L#</name>
<description>
This artifact provides the implementation of the L# algorithm as described in the paper "A New Approach for
Active Automata Learning Based on Apartness" (https://doi.org/10.1007/978-3-030-99524-9_12) by Frits Vaandrager,
Bharat Garhewal, Jurriaan Rot, and Thorsten Wißmann.
</description>

<dependencies>
<!-- internal -->
<dependency>
<groupId>de.learnlib</groupId>
<artifactId>learnlib-api</artifactId>
</dependency>
<dependency>
<groupId>de.learnlib</groupId>
<artifactId>learnlib-util</artifactId>
</dependency>

<!-- external -->
<dependency>
<groupId>net.automatalib</groupId>
<artifactId>automata-api</artifactId>
</dependency>
<dependency>
<groupId>net.automatalib</groupId>
<artifactId>automata-core</artifactId>
</dependency>
<dependency>
<groupId>net.automatalib</groupId>
<artifactId>automata-commons-util</artifactId>
</dependency>

<!-- build -->
<dependency>
<groupId>de.learnlib.tooling</groupId>
<artifactId>annotations</artifactId>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
</dependency>

<!-- test -->
<dependency>
<groupId>de.learnlib.testsupport</groupId>
<artifactId>learnlib-learner-it-support</artifactId>
</dependency>
<dependency>
<groupId>de.learnlib.testsupport</groupId>
<artifactId>learnlib-test-support</artifactId>
</dependency>

<dependency>
<groupId>net.automatalib</groupId>
<artifactId>automata-serialization-dot</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</dependency>

</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/* Copyright (C) 2013-2025 TU Dortmund University
* This file is part of LearnLib <https://learnlib.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.learnlib.algorithm.lsharp;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Objects;

import net.automatalib.automaton.transducer.MealyMachine;
import net.automatalib.common.util.Pair;
import net.automatalib.word.Word;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

public final class ApartnessUtil {

private ApartnessUtil() {
// prevent instantiation
}

public static <S extends Comparable<S>, I, O> @Nullable Word<I> computeWitness(ObservationTree<S, I, O> tree,
S s1,
S s2) {
S t = showsStatesAreApart(tree, s1, s2);
if (t == null) {
return null;
}

return tree.getTransferSeq(t, s1);
}

public static <S extends Comparable<S>, I, O> boolean statesAreApart(ObservationTree<S, I, O> tree, S s1, S s2) {
return showsStatesAreApart(tree, s1, s2) != null;
}

public static <S extends Comparable<S>, I, O> boolean accStatesAreApart(ObservationTree<S, I, O> tree,
Word<I> s1a,
Word<I> s2a) {
S s1 = tree.getSucc(tree.defaultState(), s1a);
assert s1 != null;
S s2 = tree.getSucc(tree.defaultState(), s2a);
assert s2 != null;
return statesAreApart(tree, s1, s2);
}

public static <S1 extends Comparable<S1>, S2, I, O> @Nullable Word<I> treeAndHypComputeWitness(ObservationTree<S1, I, O> tree,
S1 st,
MealyMachine<S2, I, ?, O> fsm,
S2 sh) {
S1 s = treeAndHypShowsStatesAreApart(tree, st, sh, fsm);
if (s == null) {
return null;
}

return tree.getTransferSeq(s, st);
}

public static <S1 extends Comparable<S1>, S2, I, O> @Nullable S1 treeAndHypShowsStatesAreApart(ObservationTree<S1, I, O> tree,
S1 st,
S2 sh,
MealyMachine<S2, I, ?, O> fsm) {
Deque<Pair<S1, S2>> queue = new ArrayDeque<>();
queue.push(Pair.of(st, sh));
while (!queue.isEmpty()) {
@SuppressWarnings("nullness") // false positive https://github.com/typetools/checker-framework/issues/399
@NonNull Pair<S1, S2> pair = queue.poll();
S1 q = pair.getFirst();
S2 r = pair.getSecond();

for (I i : tree.getInputAlphabet()) {
Pair<O, S1> stepFree = tree.getOutSucc(q, i);
if (stepFree != null) {
S2 dh = fsm.getSuccessor(r, i);
assert dh != null;
O outHyp = fsm.getOutput(r, i);
assert outHyp != null;

if (outHyp.equals(stepFree.getFirst())) {
queue.push(Pair.of(stepFree.getSecond(), dh));
} else {
return stepFree.getSecond();
}
}
}
}

return null;
}

private static <S extends Comparable<S>, I, O> @Nullable Pair<O, S> step(ObservationTree<S, I, O> tree, S x, I i) {
return tree.getOutSucc(x, i);
}

private static <S extends Comparable<S>, I, O> @Nullable Pair<Pair<O, S>, Pair<O, S>> treeRespPairInput(
ObservationTree<S, I, O> tree,
S x,
S y,
I i) {
Pair<O, S> s1 = step(tree, x, i);
Pair<O, S> s2 = step(tree, y, i);

if (s1 == null || s2 == null) {
return null;
}

return Pair.of(s1, s2);

}

public static <S extends Comparable<S>, I, O> @Nullable S showsStatesAreApart(ObservationTree<S, I, O> tree,
S s1,
S s2) {
Deque<Pair<S, S>> workList = new ArrayDeque<>();
workList.add(Pair.of(s1, s2));
while (!workList.isEmpty()) {
Pair<S, S> pair = workList.pop();
S fst = pair.getFirst();
S snd = pair.getSecond();

for (I i : tree.getInputAlphabet()) {
Pair<Pair<O, S>, Pair<O, S>> p = treeRespPairInput(tree, fst, snd, i);
if (p != null) {
Pair<O, S> fstOD = p.getFirst();
Pair<O, S> sndOD = p.getSecond();

O fstO = fstOD.getFirst();
S fstD = fstOD.getSecond();
O sndO = sndOD.getFirst();
S sndD = sndOD.getSecond();
if (Objects.equals(fstO, sndO)) {
workList.push(Pair.of(fstD, sndD));
} else {
return fstD;
}
}
}
}

return null;
}
}
Loading
Loading