• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LearnLib / learnlib / 31522550532

11 Aug 2026 06:24PM UTC coverage: 95.489% (+0.2%) from 95.334%
31522550532

push

github

web-flow
LearnLib CLI (#166)

* initial work on CLI application

* update build profiles

* github: add worflow for attaching cli artifacts

* cli: include OS classifiers in artifact name

* do not include cli module in releases for now

* update docs

* tidy:pom

* add support for SAF serialization

* cli: add ADT and LSHARP algorithm

* cli oracles still need some rework regarding error handling

* cleanup CLI oracles

* experiment: allow for logging intermediate hypotheses

* jacoco: also depend on cli module before aggregating reports

* cli: improve documentation

* fix code-analysis

* cli: add support for parallel oracles

* cli: add unit- and integration-tests

* add support for snapshotting

* use LocalDateTime

* simplify --eqo-* param names

* Revert "simplify --eqo-* param names"

This reverts commit d209e962d.

* add MalerPnueli + RivestSchapire learner and adjust learner names

* include license information in jlink artifact

* cleanup checkerframework config

* add rudimentary class validation during deserialization + cleanups

* add changelog

* add missing --add-opens + test

* cleanup

* wording

* handle python availability more gracefully

* conditionally set --add-opens option

* cli: invoke script via python interpreter

as on Windows the scripts alone are not detected as executable applications

* sett full (and platform-specific) path in jlink IT

* wording

* coveralls: s/Example/Experiment/

685 of 703 new or added lines in 31 files covered. (97.44%)

2 existing lines in 1 file now uncovered.

15536 of 16270 relevant lines covered (95.49%)

1.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.87
/cli/src/main/java/de/learnlib/cli/util/AbstractRunner.java
1
/* Copyright (C) 2013-2026 TU Dortmund University
2
 * This file is part of LearnLib <https://learnlib.de>.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package de.learnlib.cli.util;
17

18
import java.io.ByteArrayOutputStream;
19
import java.io.IOException;
20
import java.nio.charset.StandardCharsets;
21
import java.nio.file.Files;
22
import java.util.function.BiFunction;
23
import java.util.function.Function;
24

25
import de.learnlib.Resumable;
26
import de.learnlib.algorithm.LearningAlgorithm;
27
import de.learnlib.cli.option.Options;
28
import de.learnlib.logging.Category;
29
import de.learnlib.oracle.EquivalenceOracle;
30
import de.learnlib.statistic.Statistics;
31
import de.learnlib.statistic.StatisticsService;
32
import de.learnlib.util.Experiment;
33
import net.automatalib.alphabet.Alphabet;
34
import net.automatalib.automaton.concept.FiniteRepresentation;
35
import net.automatalib.serialization.InputModelSerializer;
36
import net.automatalib.ts.simple.SimpleTS;
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
39

40
public abstract class AbstractRunner<A extends Alphabet<I>, M extends SimpleTS<?, I> & FiniteRepresentation, I, D, OR>
41
        implements Runner {
42

43
    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRunner.class);
1✔
44

45
    public static final String LEARNER_KEY = "learner";
46
    public static final String EQO_KEY = "eqo";
47

48
    private final Function<Options, A> alphabetCreator;
49
    private final BiFunction<Options, ? super A, OR> mqoCreator;
50
    private final Function<Options, Constructor<A, M, I, D, OR>> learnerCreator;
51
    private final BiFunction<Options, OR, EquivalenceOracle<M, I, D>> eqoCreator;
52
    private final Function<Options, InputModelSerializer<I, M>> serializerCreator;
53

54
    public AbstractRunner(Function<Options, A> alphabetCreator,
55
                          BiFunction<Options, ? super A, OR> mqoCreator,
56
                          Function<Options, Constructor<A, M, I, D, OR>> learnerCreator,
57
                          BiFunction<Options, OR, EquivalenceOracle<M, I, D>> eqoCreator,
58
                          Function<Options, InputModelSerializer<I, M>> serializerCreator) {
1✔
59
        this.alphabetCreator = alphabetCreator;
1✔
60
        this.mqoCreator = mqoCreator;
1✔
61
        this.learnerCreator = learnerCreator;
1✔
62
        this.eqoCreator = eqoCreator;
1✔
63
        this.serializerCreator = serializerCreator;
1✔
64
    }
1✔
65

66
    @Override
67
    public void run(Options options) {
68

69
        final A alphabet = alphabetCreator.apply(options);
1✔
70
        final OR mqo = mqoCreator.apply(options, alphabet);
1✔
71

72
        final OR learnerOracle;
73
        if (options.statistics) {
1✔
74
            learnerOracle = getCounter(mqo, LEARNER_KEY);
1✔
75
        } else {
76
            learnerOracle = mqo;
1✔
77
        }
78

79
        final LearningAlgorithm<M, I, D> learner =
1✔
80
                learnerCreator.apply(options).constructLearner(alphabet, learnerOracle);
1✔
81

82
        final OR eqoOracle;
83
        if (options.statistics) {
1✔
84
            eqoOracle = getCounter(mqo, EQO_KEY);
1✔
85
        } else {
86
            eqoOracle = mqo;
1✔
87
        }
88

89
        final EquivalenceOracle<M, I, D> eqo = eqoCreator.apply(options, eqoOracle);
1✔
90
        final InputModelSerializer<I, M> serializer = serializerCreator.apply(options);
1✔
91
        final Experiment<M, I, D> experiment = buildExperiment(learner, eqo, alphabet, serializer, options);
1✔
92

93
        final M hyp = experiment.run();
1✔
94

95
        if (options.statistics) {
1✔
96
            final StatisticsService service = Statistics.getService();
1✔
97
            LOGGER.info(Category.STATISTIC, service.print());
1✔
98
        }
99

100
        try {
101
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1✔
102
            serializer.writeModel(baos, hyp, alphabet);
1✔
103

104
            LOGGER.info(Category.MODEL, "Final hypothesis:\n{}", baos.toString(StandardCharsets.UTF_8));
1✔
105
            if (options.output != null) {
1✔
106
                Files.write(options.output, baos.toByteArray());
1✔
107
            }
NEW
108
        } catch (IOException e) {
×
NEW
109
            LOGGER.warn("Could not write hypothesis", e);
×
110
        }
1✔
111
    }
1✔
112

113
    private Experiment<M, I, D> buildExperiment(LearningAlgorithm<M, I, D> learner,
114
                                                EquivalenceOracle<M, I, D> eqo,
115
                                                Alphabet<I> alphabet,
116
                                                InputModelSerializer<I, M> serializer,
117
                                                Options options) {
118
        if (learner instanceof Resumable<?> r) {
1✔
119
            return new SnapshottingExperiment<>(learner, r, eqo, alphabet, serializer, options);
1✔
120
        } else {
121
            if (options.resumeFrom != null || options.snapshotDir != null) {
1✔
122
                throw new IllegalArgumentException(String.format(
1✔
123
                        "Resuming learning processes is not supported by '%s' ('%s')",
124
                        options.learner,
125
                        options.type));
126
            }
127
            return new Experiment<>(learner, eqo, alphabet, serializer);
1✔
128
        }
129
    }
130

131
    protected abstract OR getCounter(OR delegate, String id);
132
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc