Skip to content

Integrate M3C, a model checker for context-free modal process systems #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 110 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
9d1435d
initial m3c configuration
mtf90 Jan 21, 2021
17fd9b1
fix typo
mtf90 Jan 21, 2021
3891aa4
add further exclusions for generated classes
mtf90 Jan 21, 2021
c11374f
M3C with JavaCC grammars
AlnisM Jan 27, 2021
9002b86
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Feb 3, 2021
561d2e5
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Feb 3, 2021
339067e
initial draft of MCFPS interfaces
mtf90 Feb 3, 2021
36171c6
Adapt Solver to work with ModalContextFreeProcessSystem, add headers,…
AlnisM Feb 8, 2021
46888d5
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Mar 15, 2021
2dd9b43
add experimental support for M3C-modelchecking SPAs
mtf90 Mar 17, 2021
a574cc7
general cleanups
mtf90 Mar 17, 2021
d9bc052
make formulas parameterizable in label and proposition type
mtf90 Mar 17, 2021
432e9e6
add new (failing) testcases
mtf90 Mar 17, 2021
d3673e7
add some experimental (broken) refactorings to NNFVisitor
mtf90 Mar 17, 2021
665b207
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Mar 20, 2021
c1eb879
move ToString visitor in toString method of FormulaNodes
mtf90 Mar 22, 2021
e1505b9
make abstract classes start with Abstract
mtf90 Mar 22, 2021
bea92c5
fix indentions
mtf90 Mar 22, 2021
809c408
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Mar 22, 2021
2c6d60e
Decide procedurality via edge properties rather than input alphabets
mtf90 Mar 22, 2021
3774dc5
reactivate tests + cleanup
mtf90 Mar 22, 2021
e8a7d6b
Fix broken Transformer tests
AlnisM Mar 23, 2021
82a598e
clean up NNFVisitor
mtf90 Mar 23, 2021
665792c
clean up AbstractFormulaNode
mtf90 Mar 23, 2021
ccd2767
fix PMD warning
mtf90 Mar 23, 2021
e7a32b7
fix broken and add new parser tests
AlnisM Mar 25, 2021
3babf94
reorder functions to address checkstyle errors
mtf90 Mar 25, 2021
6a40a7d
first try at new solver API
mtf90 Mar 25, 2021
576f8c3
configure ADDLib as optional dependency
mtf90 Apr 12, 2021
d681e19
simplify some equals methods
mtf90 May 2, 2021
c1fad71
add Alnis metadata
mtf90 May 2, 2021
5e9efe8
cleanups and new design experiments on solver API
mtf90 May 3, 2021
6ac0387
remove unused code
mtf90 May 3, 2021
2ad5eb9
update cf config
mtf90 May 3, 2021
349ae66
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Jun 24, 2021
36de71b
small cleanups
mtf90 Jun 26, 2021
8162b42
delete unused methods and refactor BDDTransformer
AlnisM Jun 29, 2021
339dbb8
fix operator precedence in ctl parser
AlnisM Jun 29, 2021
1a024af
fix typedADDSolver
AlnisM Jun 29, 2021
91d4d66
cleanups
mtf90 Jun 29, 2021
c02c7af
remove setADD in ADDTransformer
AlnisM Jun 30, 2021
7b76b67
replace AtomicInteger with int
mtf90 Jun 30, 2021
6c82ab0
cleanups
mtf90 Jun 30, 2021
3086519
test solver with mcfps with atomic propositions
AlnisM Jun 30, 2021
42eee4f
replace loop by containsAll in atomicPropositions check
AlnisM Jul 1, 2021
b358f7a
add SolverHistory
AlnisM Jul 6, 2021
a3a6aaa
cleanups
mtf90 Jul 8, 2021
4a8f385
experimrent with aggregated work units
mtf90 Jul 8, 2021
1254a0c
finish work unit refactoring
mtf90 Jul 9, 2021
a64e730
add MCFPS visualization and other improvements
mtf90 Jul 12, 2021
3547b2f
cleanups + fixes
mtf90 Jul 14, 2021
7e1b057
cleanup / improve tests and test cases
mtf90 Jul 14, 2021
bbda523
cleanups + failing test case
mtf90 Jul 14, 2021
9126abe
add internal (integration) tests
mtf90 Jul 16, 2021
6c3b0f9
add EOF token to ctl and mucalc grammars
AlnisM Jul 23, 2021
396e5b2
SolverHistory changes
AlnisM Jul 23, 2021
2f162ad
SolverHistoryTest wip
AlnisM Jul 23, 2021
3129862
refactor {,Unary,Binary}FormulaNodes
mtf90 Jul 23, 2021
490e45f
cleanup
mtf90 Jul 23, 2021
d2e23ba
add rudimentary documentation
mtf90 Jul 23, 2021
8a7853c
remove obsolete AbstractFormulaNodeVisitor
mtf90 Jul 23, 2021
2de5fb8
add specialized mappings for simple graphs
mtf90 Jul 28, 2021
7f59819
attempt at cleaning up SolverHistory
mtf90 Jul 28, 2021
8aca0ed
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Jul 29, 2021
26bef4e
Revert "add specialized mappings for simple graphs"
mtf90 Jul 29, 2021
5480dcd
add missing dependency
mtf90 Jul 29, 2021
38372e4
test formulas with negated ap, complete SolverHistoryTest
AlnisM Jul 30, 2021
f1b76a2
quit ddmanager in SolverHistoryTest
AlnisM Jul 30, 2021
af8b690
try pipeline without SolverHistoryTest
AlnisM Jul 30, 2021
07aaff2
disable history test
AlnisM Jul 30, 2021
b43955e
cleanups
mtf90 Jul 30, 2021
4af148b
fix reference in CHANGELOG
mtf90 Jul 31, 2021
29f3b39
fix formula
mtf90 Jul 31, 2021
fa22021
add (failing) integration test and cleanup existing format
mtf90 Jul 31, 2021
2504c1c
cleanup visualization of MCFPSs
mtf90 Jul 31, 2021
ddcee75
cleanup and add new tests
mtf90 Aug 1, 2021
b3289bc
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Aug 1, 2021
a3bc50d
remove redundant information from external systems
mtf90 Aug 1, 2021
a0ff7d2
fix update in ADDTransformer so transformer before update is preserved
AlnisM Aug 3, 2021
2fc11a2
fix ADDTransformer update bug (preserving other blocks), merge Extern…
AlnisM Aug 6, 2021
295ac8c
cleanup
mtf90 Aug 8, 2021
be8afaa
externalize transformer serialization + cleanups
mtf90 Aug 10, 2021
7383eb4
javadoc
AlnisM Aug 25, 2021
5fc8e22
fix ampersand in javadoc
AlnisM Aug 25, 2021
a30301b
more javadoc
AlnisM Aug 25, 2021
e606fa2
fix javadoc error
AlnisM Aug 25, 2021
a15a023
refactor JavaDoc
mtf90 Aug 25, 2021
137c131
refactor type names to better match paper definitions
mtf90 Aug 25, 2021
93a8e9e
small cleanup
mtf90 Aug 25, 2021
c7b2838
small cleanup
mtf90 Aug 25, 2021
f0c627d
new addlib version for m3c
AlnisM Aug 28, 2021
a097a6f
fix inclusion of new ADDLib snapshots
mtf90 Aug 28, 2021
6e8d63f
tidy up pom
mtf90 Aug 28, 2021
a91b2b0
cleanup dependencies
mtf90 Aug 28, 2021
945e47e
SolverHistoryTest with ADDs
AlnisM Aug 30, 2021
c54e9dd
use parameter-less DDManager constructors
AlnisM Aug 30, 2021
7c05e71
cleanups
mtf90 Aug 30, 2021
e75d62e
test invalid input
AlnisM Aug 30, 2021
fe9b770
replace try catch Assert.fail() by expectedExceptions
AlnisM Aug 30, 2021
a69d1af
add tests for parser detection
AlnisM Aug 30, 2021
b4369cb
unify ctl and mu calc parser
AlnisM Aug 30, 2021
9a169fb
cleanups
mtf90 Aug 30, 2021
1f9d358
cleanups
mtf90 Aug 30, 2021
6b73a9c
Merge remote-tracking branch 'upstream/develop' into m3c
mtf90 Aug 30, 2021
03328e8
cleanups
mtf90 Aug 30, 2021
25b4dd1
naming: state -> node
AlnisM Sep 1, 2021
580afc7
AtomicNode: Set<AP> -> AP
AlnisM Sep 1, 2021
e8a3af5
naming: solve -> solver
AlnisM Sep 1, 2021
c5710b9
remove nullables
AlnisM Sep 1, 2021
20303da
cleanups
mtf90 Sep 1, 2021
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
test-output/
target/
*.versionsBackup
.DS_STORE
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Added modal transition systems (MTSs), modal contracts (MCs) and Membership-MCs (MMCs).
* Added `SubsequentialTransducer` interface and implementations/utilities.
* Added support for systems of procedural automata (SPAs) as well as related concepts (equivalence, etc.).
* Added the M3C model-checker for verifying µ-calculus and CTL formulas on context-free modal process systems (thanks to [Alnis Murtovi](https://github.com/AlnisM)).

### Changed

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Furthermore, a plethora of graph-/automata-based algorithms is implemented, cove

* graph theory (traversal, shortest paths, strongly-connected components)
* automata theory (equivalence, minimization)
* model checking (adaptive distinguishing sequences, W(p)Method, characterizing sets, state/transition covers, LTL checking (via [LTSMin][ltsmin]))
* model-based testing (adaptive distinguishing sequences, W(p)Method, characterizing sets, state/transition covers)
* model verification (LTL checking (via [LTSMin][ltsmin]), CTL & µ-calculus checking (via [M3C][m3c] & [ADDlib][addlib]))

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.
Expand Down Expand Up @@ -97,3 +98,5 @@ For developing the code base of AutomataLib it is suggested to use one of the ma
[intellij]: https://www.jetbrains.com/idea/
[eclipse]: https://www.eclipse.org/
[ltsmin]: https://ltsmin.utwente.nl/
[m3c]: http://dx.doi.org/10.1007/978-3-030-00244-2_15
[addlib]: https://add-lib.scce.info/
197 changes: 197 additions & 0 deletions api/src/main/java/net/automatalib/automata/spa/CFMPSView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/* Copyright (C) 2013-2021 TU Dortmund
* This file is part of AutomataLib, http://www.automatalib.net/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.automatalib.automata.spa;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.common.collect.Maps;
import net.automatalib.automata.fsa.DFA;
import net.automatalib.graphs.ContextFreeModalProcessSystem;
import net.automatalib.graphs.ProceduralModalProcessGraph;
import net.automatalib.ts.modal.transition.ProceduralModalEdgeProperty;
import net.automatalib.ts.modal.transition.ProceduralModalEdgeProperty.ProceduralType;
import net.automatalib.words.SPAAlphabet;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
* This class represent a {@link ContextFreeModalProcessSystem}-based view on the instrumented language of a given
* {@link SPA}, which allows to model-check language properties of an {@link SPA} with tools such as M3C.
*
* @param <I>
* input symbol type
*
* @author frohme
*/
public class CFMPSView<I> implements ContextFreeModalProcessSystem<I, Void> {

private final SPA<?, I> spa;
private final Map<I, ProceduralModalProcessGraph<?, I, ?, Void, ?>> pmpgs;

public CFMPSView(SPA<?, I> spa) {
this.spa = spa;

final SPAAlphabet<I> spaAlphabet = spa.getInputAlphabet();
final Map<I, DFA<?, I>> procedures = spa.getProcedures();
this.pmpgs = Maps.newHashMapWithExpectedSize(procedures.size());
for (Entry<I, DFA<?, I>> e : procedures.entrySet()) {
this.pmpgs.put(e.getKey(), new MPGView<>(spaAlphabet, e.getKey(), e.getValue()));
}
}

@Override
public Map<I, ProceduralModalProcessGraph<?, I, ?, Void, ?>> getPMPGs() {
return this.pmpgs;
}

@Override
public @Nullable I getMainProcess() {
return this.spa.getInitialProcedure();
}

private static class MPGView<S, I>
implements ProceduralModalProcessGraph<S, I, SPAEdge<I, S>, Void, ProceduralModalEdgeProperty> {

private static final Object INIT = new Object();
private static final Object END = new Object();

private final SPAAlphabet<I> spaAlphabet;
private final I procedure;
private final DFA<S, I> dfa;
private final S dfaInit;

private final S init;
private final S end;

// we make sure to handle 'init' and 'end' correctly
@SuppressWarnings("unchecked")
MPGView(SPAAlphabet<I> spaAlphabet, I procedure, DFA<S, I> dfa) {
this.spaAlphabet = spaAlphabet;
this.procedure = procedure;
this.dfa = dfa;

final S dfaInit = this.dfa.getInitialState();
if (dfaInit == null) {
throw new IllegalArgumentException("Empty DFAs cannot be mapped to ModalProcessGraphs");
}
this.dfaInit = dfaInit;

this.init = (S) INIT;
this.end = (S) END;
}

@Override
public Collection<SPAEdge<I, S>> getOutgoingEdges(S node) {
if (node == init) {
return Collections.singletonList(new SPAEdge<>(this.procedure, this.dfaInit, ProceduralType.INTERNAL));
} else if (node == end) {
return Collections.emptyList();
} else {
final List<SPAEdge<I, S>> result = new ArrayList<>(this.spaAlphabet.size());

for (I i : this.spaAlphabet.getInternalAlphabet()) {
final S succ = this.dfa.getSuccessor(node, i);
if (succ != null) {
result.add(new SPAEdge<>(i, succ, ProceduralType.INTERNAL));
}
}

for (I i : this.spaAlphabet.getCallAlphabet()) {
final S succ = this.dfa.getSuccessor(node, i);
if (succ != null) {
result.add(new SPAEdge<>(i, succ, ProceduralType.PROCESS));
}
}

if (this.dfa.isAccepting(node)) {
result.add(new SPAEdge<>(this.spaAlphabet.getReturnSymbol(),
this.getFinalNode(),
ProceduralType.INTERNAL));
}

return result;
}
}

@Override
public S getTarget(SPAEdge<I, S> edge) {
return edge.succ;
}

@Override
public Collection<S> getNodes() {
final List<S> nodes = new ArrayList<>(dfa.size() + 2);
nodes.add(this.init);
nodes.add(this.end);
nodes.addAll(dfa.getStates());
return nodes;
}

@Override
public Set<Void> getNodeProperty(S node) {
return Collections.emptySet();
}

@Override
public ProceduralModalEdgeProperty getEdgeProperty(SPAEdge<I, S> edge) {
return edge;
}

@Override
public I getEdgeLabel(SPAEdge<I, S> edge) {
return edge.input;
}

@Override
public S getFinalNode() {
return this.end;
}

@Override
public S getInitialNode() {
return this.init;
}
}

private static class SPAEdge<I, S> implements ProceduralModalEdgeProperty {

private final I input;
private final S succ;
private final ProceduralType type;

SPAEdge(I input, S succ, ProceduralType type) {
this.input = input;
this.succ = succ;
this.type = type;
}

@Override
public ModalType getModalType() {
return ModalType.MUST;
}

@Override
public ProceduralType getProceduralType() {
return this.type;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public Collection<Pair<I, S>> getNodes() {
public Collection<Triple<I, I, S>> getOutgoingEdges(Pair<I, S> node) {
final I procedure = node.getFirst();
final S state = node.getSecond();
@SuppressWarnings("assignment.type.incompatible") // we only use identifier for which procedures exists
@SuppressWarnings("assignment.type.incompatible") // we only use identifier for which procedures exist
final @NonNull DFA<S, I> subModel = subModels.get(procedure);

final List<Triple<I, I, S>> result = new ArrayList<>(this.proceduralAlphabet.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public boolean getEdgeProperties(S src, TransitionEdge<I, T> edge, S tgt, Map<St
properties.put(EdgeAttrs.COLOR, "red");
}

properties.put(MCEdgeAttrs.CONTRACT, transitionProperty.getColor().toString());
properties.put(MCEdgeAttrs.CONTRACT, transitionProperty.getColor().name());

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public boolean getEdgeProperties(S src, TransitionEdge<I, T> edge, S tgt, Map<St
properties.put(EdgeAttrs.STYLE, EdgeStyles.DASHED);
}

properties.put(MTSEdgeAttrs.MODALITY, transitionProperty.getType().toString());
properties.put(MTSEdgeAttrs.MODALITY, transitionProperty.getModalType().name());

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public boolean getEdgeProperties(Pair<I, S> src,
properties.put(EdgeAttrs.LABEL, String.valueOf(edge.getSecond()));

if (callAlphabet.containsSymbol(edge.getSecond())) {
properties.put(EdgeAttrs.STYLE, EdgeStyles.DASHED);
properties.put(EdgeAttrs.STYLE, EdgeStyles.BOLD);
}

return true;
Expand Down
98 changes: 98 additions & 0 deletions api/src/main/java/net/automatalib/graphs/CFMPSGraphView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/* Copyright (C) 2013-2021 TU Dortmund
* This file is part of AutomataLib, http://www.automatalib.net/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.automatalib.graphs;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.automatalib.commons.util.Pair;
import net.automatalib.graphs.visualization.CFMPSVisualizationHelper;
import net.automatalib.visualization.VisualizationHelper;
import org.checkerframework.checker.nullness.qual.NonNull;

/**
* Graph representation of a {@link ContextFreeModalProcessSystem} that displays all nodes of its sub-procedures once,
* i.e., without incorporating execution semantics such as stack contents.
*
* @param <S>
* common procedural state type
* @param <L>
* label type
* @param <E>
* edge type
* @param <AP>
* atomic proposition type
*
* @author frohme
*/
public class CFMPSGraphView<S, L, E, AP> implements Graph<Pair<L, S>, Pair<L, E>> {

private final Map<L, ProceduralModalProcessGraph<S, L, E, AP, ?>> pmpgs;

// cast is fine, because we make sure to only query nodes/edges belonging to the respective procedures
@SuppressWarnings("unchecked")
public CFMPSGraphView(Map<L, ? extends ProceduralModalProcessGraph<? extends S, L, ? extends E, AP, ?>> pmpgs) {
this.pmpgs = (Map<L, ProceduralModalProcessGraph<S, L, E, AP, ?>>) pmpgs;
}

@Override
public Collection<Pair<L, E>> getOutgoingEdges(Pair<L, S> node) {
final L process = node.getFirst();
@SuppressWarnings("assignment.type.incompatible") // we only use identifier for which pmpgs exist
final @NonNull ProceduralModalProcessGraph<S, L, E, AP, ?> pmpg = pmpgs.get(process);
final Collection<E> outgoingEdges = pmpg.getOutgoingEdges(node.getSecond());

final Collection<Pair<L, E>> result = new ArrayList<>(outgoingEdges.size());

for (E e : outgoingEdges) {
result.add(Pair.of(process, e));
}

return result;
}

@Override
public Pair<L, S> getTarget(Pair<L, E> edge) {
final L process = edge.getFirst();
@SuppressWarnings("assignment.type.incompatible") // we only use identifier for which pmpgs exist
final @NonNull ProceduralModalProcessGraph<S, L, E, AP, ?> pmpg = pmpgs.get(process);

return Pair.of(process, pmpg.getTarget(edge.getSecond()));
}

@Override
public Collection<Pair<L, S>> getNodes() {
final int numNodes = this.pmpgs.values().stream().mapToInt(Graph::size).sum();
final List<Pair<L, S>> result = new ArrayList<>(numNodes);

for (Entry<L, ProceduralModalProcessGraph<S, L, E, AP, ?>> e : this.pmpgs.entrySet()) {
final L process = e.getKey();
for (S s : e.getValue()) {
result.add(Pair.of(process, s));
}
}

return result;
}

@Override
public VisualizationHelper<Pair<L, S>, Pair<L, E>> getVisualizationHelper() {
return new CFMPSVisualizationHelper<>(this.pmpgs);
}
}
Loading