Skip to content

Execution of TTT results in ConflictException on deterministic models #126

@emuskardin

Description

@emuskardin

Hi :)

Describe the bug
Learning of Mealy Machines with TTT results in a cache ConflictException. When caching is removed, the algorithm learns the correct model.

Learning is done on randomly generated models, therefore there should be no non-deterministic behavior. In addition, if the learning algorithm is replaced, lets say with KV, the learning finishes as expected. So it seems that there might be some bug in TTT's handling of caching.

To Reproduce
I put a test script below that contains two seeds that reproduce the behavior and have included a screenshot of the output for one failing seed.

Desktop (please complete the following information):

  • OS: Windows,
  • Java version: 11
  • LearnLib version: 0.17.0

Additional context
This happens relatively rarely, I encountered it while benchmarking random automata.

** Files **
Output:
fail_seed_584

Code to reproduce:

import de.learnlib.algorithm.LearningAlgorithm;
import de.learnlib.algorithm.ttt.mealy.TTTLearnerMealy;
import de.learnlib.driver.simulator.MealySimulatorSUL;
import de.learnlib.filter.cache.sul.SULCaches;
import de.learnlib.filter.statistic.Counter;
import de.learnlib.filter.statistic.sul.ResetCounterSUL;
import de.learnlib.filter.statistic.sul.SymbolCounterSUL;
import de.learnlib.oracle.EquivalenceOracle;
import de.learnlib.oracle.equivalence.MealyRandomWordsEQOracle;
import de.learnlib.oracle.membership.MealySimulatorOracle;
import de.learnlib.oracle.membership.SULOracle;
import de.learnlib.statistic.StatisticSUL;
import de.learnlib.sul.SUL;
import de.learnlib.util.Experiment;
import de.learnlib.util.statistic.SimpleProfiler;
import net.automatalib.alphabet.Alphabet;
import net.automatalib.alphabet.ListAlphabet;
import net.automatalib.automaton.transducer.CompactMealy;
import net.automatalib.automaton.transducer.MealyMachine;
import net.automatalib.util.automaton.random.RandomAutomata;
import net.automatalib.word.Word;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import static de.learnlib.acex.AcexAnalyzers.BINARY_SEARCH_BWD;

public class TTTCacheError {
    public static void findFailing() throws IOException {

        int numStates = 1000;

        List<Integer> inputs = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4));
        List<Integer> outputs = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4));

        Alphabet<Integer> alphabet = new ListAlphabet<>(inputs);
        Alphabet<Integer> outputAlphabet =  new ListAlphabet<>(outputs);

        // Failing seeds 584,789
        int[] failingSeeds = {584,789};

        // can be used to find more failing
        // for (int k = 1000; k < 2000; k++) {

        for (int seedNum : failingSeeds){
            System.out.println("Failing seed " + seedNum);
            Random seed = new Random(seedNum);

            CompactMealy<Integer, Integer> target = RandomAutomata.randomMealy(seed, numStates, alphabet, outputAlphabet, true);
            
            MealySimulatorSUL<Integer, Integer> driver = new MealySimulatorSUL<>(target);

            StatisticSUL<Integer, Integer> queryStatisticSul = new ResetCounterSUL<>("membership queries", driver);
            StatisticSUL<Integer, Integer> stepStatisticSul = new SymbolCounterSUL<>("steps", queryStatisticSul);

            SUL<Integer, Integer> effectiveSul = stepStatisticSul;
            effectiveSul = SULCaches.createCache(alphabet, effectiveSul);

            SULOracle<Integer, Integer> mqOracle = new SULOracle<>(effectiveSul);
            LearningAlgorithm<? extends MealyMachine<?, Integer, ?, Integer>, Integer, Word<Integer>> learningAlg = null;

            learningAlg = new TTTLearnerMealy<>(alphabet, mqOracle, BINARY_SEARCH_BWD);
            // Seems to work for KV
            // learningAlg = new KearnsVaziraniMealy<>(alphabet, mqOracle, true, BINARY_SEARCH_BWD);


            EquivalenceOracle.MealyEquivalenceOracle<Integer, Integer> eqOracle = new MealyRandomWordsEQOracle<>(
                    new MealySimulatorOracle<>(target),
                    10,
                    50,
                    30000,
                    seed // make results reproducible
            );

            Experiment.MealyExperiment<Integer, Integer> experiment = new Experiment.MealyExperiment<>(learningAlg, eqOracle, alphabet);
            experiment.setProfile(true);
            experiment.setLogModels(false);
            SimpleProfiler.reset();

            experiment.run();

            Counter e = SimpleProfiler.cumulated("Learning");

            assert e != null;

            SimpleProfiler.logResults();

            MealyMachine<?, Integer, ?, Integer> result = experiment.getFinalHypothesis();
            // model statistics
            if (result.size() != target.size()) {
                System.out.println("Learning failed." + result.size() + " vs " + numStates);
            }
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException, NoSuchMethodException {
        findFailing();
    }

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions