diff --git a/.gitignore b/.gitignore index 413b726301..467ad4925f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ test-output/ target/ *.versionsBackup +.DS_STORE diff --git a/CHANGELOG.md b/CHANGELOG.md index 77a2dea611..967f2a636d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 4df6d21b65..abcd065dd4 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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/ diff --git a/api/src/main/java/net/automatalib/automata/spa/CFMPSView.java b/api/src/main/java/net/automatalib/automata/spa/CFMPSView.java new file mode 100644 index 0000000000..dd4c15f05d --- /dev/null +++ b/api/src/main/java/net/automatalib/automata/spa/CFMPSView.java @@ -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 + * input symbol type + * + * @author frohme + */ +public class CFMPSView implements ContextFreeModalProcessSystem { + + private final SPA spa; + private final Map> pmpgs; + + public CFMPSView(SPA spa) { + this.spa = spa; + + final SPAAlphabet spaAlphabet = spa.getInputAlphabet(); + final Map> procedures = spa.getProcedures(); + this.pmpgs = Maps.newHashMapWithExpectedSize(procedures.size()); + for (Entry> e : procedures.entrySet()) { + this.pmpgs.put(e.getKey(), new MPGView<>(spaAlphabet, e.getKey(), e.getValue())); + } + } + + @Override + public Map> getPMPGs() { + return this.pmpgs; + } + + @Override + public @Nullable I getMainProcess() { + return this.spa.getInitialProcedure(); + } + + private static class MPGView + implements ProceduralModalProcessGraph, Void, ProceduralModalEdgeProperty> { + + private static final Object INIT = new Object(); + private static final Object END = new Object(); + + private final SPAAlphabet spaAlphabet; + private final I procedure; + private final DFA 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 spaAlphabet, I procedure, DFA 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> 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> 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 edge) { + return edge.succ; + } + + @Override + public Collection getNodes() { + final List nodes = new ArrayList<>(dfa.size() + 2); + nodes.add(this.init); + nodes.add(this.end); + nodes.addAll(dfa.getStates()); + return nodes; + } + + @Override + public Set getNodeProperty(S node) { + return Collections.emptySet(); + } + + @Override + public ProceduralModalEdgeProperty getEdgeProperty(SPAEdge edge) { + return edge; + } + + @Override + public I getEdgeLabel(SPAEdge edge) { + return edge.input; + } + + @Override + public S getFinalNode() { + return this.end; + } + + @Override + public S getInitialNode() { + return this.init; + } + } + + private static class SPAEdge 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; + } + } + +} diff --git a/api/src/main/java/net/automatalib/automata/spa/SPAGraphView.java b/api/src/main/java/net/automatalib/automata/spa/SPAGraphView.java index c6dd631560..dbc8be6118 100644 --- a/api/src/main/java/net/automatalib/automata/spa/SPAGraphView.java +++ b/api/src/main/java/net/automatalib/automata/spa/SPAGraphView.java @@ -74,7 +74,7 @@ public Collection> getNodes() { public Collection> getOutgoingEdges(Pair 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 subModel = subModels.get(procedure); final List> result = new ArrayList<>(this.proceduralAlphabet.size()); diff --git a/api/src/main/java/net/automatalib/automata/visualization/MCVisualizationHelper.java b/api/src/main/java/net/automatalib/automata/visualization/MCVisualizationHelper.java index ae00827ff2..84d3f4c663 100644 --- a/api/src/main/java/net/automatalib/automata/visualization/MCVisualizationHelper.java +++ b/api/src/main/java/net/automatalib/automata/visualization/MCVisualizationHelper.java @@ -48,7 +48,7 @@ public boolean getEdgeProperties(S src, TransitionEdge edge, S tgt, Map edge, S tgt, Map 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; diff --git a/api/src/main/java/net/automatalib/graphs/CFMPSGraphView.java b/api/src/main/java/net/automatalib/graphs/CFMPSGraphView.java new file mode 100644 index 0000000000..1ad10521ac --- /dev/null +++ b/api/src/main/java/net/automatalib/graphs/CFMPSGraphView.java @@ -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 + * common procedural state type + * @param + * label type + * @param + * edge type + * @param + * atomic proposition type + * + * @author frohme + */ +public class CFMPSGraphView implements Graph, Pair> { + + private final Map> pmpgs; + + // cast is fine, because we make sure to only query nodes/edges belonging to the respective procedures + @SuppressWarnings("unchecked") + public CFMPSGraphView(Map> pmpgs) { + this.pmpgs = (Map>) pmpgs; + } + + @Override + public Collection> getOutgoingEdges(Pair node) { + final L process = node.getFirst(); + @SuppressWarnings("assignment.type.incompatible") // we only use identifier for which pmpgs exist + final @NonNull ProceduralModalProcessGraph pmpg = pmpgs.get(process); + final Collection outgoingEdges = pmpg.getOutgoingEdges(node.getSecond()); + + final Collection> result = new ArrayList<>(outgoingEdges.size()); + + for (E e : outgoingEdges) { + result.add(Pair.of(process, e)); + } + + return result; + } + + @Override + public Pair getTarget(Pair edge) { + final L process = edge.getFirst(); + @SuppressWarnings("assignment.type.incompatible") // we only use identifier for which pmpgs exist + final @NonNull ProceduralModalProcessGraph pmpg = pmpgs.get(process); + + return Pair.of(process, pmpg.getTarget(edge.getSecond())); + } + + @Override + public Collection> getNodes() { + final int numNodes = this.pmpgs.values().stream().mapToInt(Graph::size).sum(); + final List> result = new ArrayList<>(numNodes); + + for (Entry> 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> getVisualizationHelper() { + return new CFMPSVisualizationHelper<>(this.pmpgs); + } +} diff --git a/api/src/main/java/net/automatalib/graphs/ContextFreeModalProcessSystem.java b/api/src/main/java/net/automatalib/graphs/ContextFreeModalProcessSystem.java new file mode 100644 index 0000000000..c4ef84af54 --- /dev/null +++ b/api/src/main/java/net/automatalib/graphs/ContextFreeModalProcessSystem.java @@ -0,0 +1,55 @@ +/* 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.Map; + +import net.automatalib.automata.concepts.FiniteRepresentation; +import net.automatalib.graphs.concepts.GraphViewable; +import net.automatalib.ts.TransitionSystem; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Represents a Context-Free Modal Transition System as defined in the paper M3C: + * Modal Meta Model Checking. Note that we use the term process system from the original paper to prevent confusion with + * AutomataLib's concept of {@link TransitionSystem}s. + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author frohme + * @author murtovi + */ +public interface ContextFreeModalProcessSystem extends FiniteRepresentation, GraphViewable { + + Map> getPMPGs(); + + @Nullable L getMainProcess(); + + @Override + default int size() { + return getPMPGs().values().stream().mapToInt(ProceduralModalProcessGraph::size).sum(); + } + + @Override + default Graph graphView() { + // explicit type specification is required by checker-framework + return new CFMPSGraphView<@Nullable Object, L, @Nullable Object, AP>(getPMPGs()); + } +} diff --git a/api/src/main/java/net/automatalib/graphs/MutableProceduralModalProcessGraph.java b/api/src/main/java/net/automatalib/graphs/MutableProceduralModalProcessGraph.java new file mode 100644 index 0000000000..9f4f4f9306 --- /dev/null +++ b/api/src/main/java/net/automatalib/graphs/MutableProceduralModalProcessGraph.java @@ -0,0 +1,60 @@ +/* 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.Collections; +import java.util.Set; + +import net.automatalib.graphs.concepts.MutableEdgeLabels; +import net.automatalib.graphs.concepts.MutableKripkeInterpretation; +import net.automatalib.ts.modal.transition.MutableProceduralModalEdgeProperty; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A mutable version of the {@link ProceduralModalProcessGraph}. + * + * @param + * node type + * @param + * edge label type + * @param + * edge type + * @param + * atomic proposition type + * @param + * edge proposition type + */ +public interface MutableProceduralModalProcessGraph extends + ProceduralModalProcessGraph, + MutableGraph, TP>, + MutableKripkeInterpretation, + MutableEdgeLabels { + + void setInitialNode(@Nullable N initialNode); + + void setFinalNode(@Nullable N finalNode); + + @Override + default void setAtomicPropositions(N node, Set atomicPropositions) { + setNodeProperty(node, atomicPropositions); + } + + @Override + default N addNode() { + return addNode(Collections.emptySet()); + } + +} diff --git a/api/src/main/java/net/automatalib/graphs/ProceduralModalProcessGraph.java b/api/src/main/java/net/automatalib/graphs/ProceduralModalProcessGraph.java new file mode 100644 index 0000000000..4df5411b87 --- /dev/null +++ b/api/src/main/java/net/automatalib/graphs/ProceduralModalProcessGraph.java @@ -0,0 +1,57 @@ +/* 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.Set; + +import net.automatalib.graphs.concepts.FinalNode; +import net.automatalib.graphs.concepts.InitialNode; +import net.automatalib.ts.TransitionSystem; +import net.automatalib.ts.modal.transition.ProceduralModalEdgeProperty; + +/** + * Represents a Procedural Modal Transition System as defined in the paper M3C: Modal Meta Model Checking. Note that we use the term + * process graph from the original paper to + * prevent confusion with AutomataLib's concept of {@link TransitionSystem}s. + * + * @param + * node type + * @param + * edge label type + * @param + * edge type + * @param + * atomic proposition type + * @param + * edge property type + * + * @author frohme + * @author murtovi + */ +public interface ProceduralModalProcessGraph + extends UniversalGraph, TP>, + FiniteKripkeStructure, + FiniteLabeledGraph, + InitialNode, + FinalNode { + + @Override + default Set getAtomicPropositions(N node) { + return getNodeProperty(node); + } + +} diff --git a/api/src/main/java/net/automatalib/graphs/concepts/FinalNode.java b/api/src/main/java/net/automatalib/graphs/concepts/FinalNode.java new file mode 100644 index 0000000000..0031030da4 --- /dev/null +++ b/api/src/main/java/net/automatalib/graphs/concepts/FinalNode.java @@ -0,0 +1,28 @@ +/* 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.concepts; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public interface FinalNode { + + /** + * Retrieves the final node, or {@code null} if this graph does not have a final node. + * + * @return the final node. + */ + @Nullable N getFinalNode(); +} diff --git a/api/src/main/java/net/automatalib/graphs/concepts/MutableEdgeLabels.java b/api/src/main/java/net/automatalib/graphs/concepts/MutableEdgeLabels.java new file mode 100644 index 0000000000..da1ae161b4 --- /dev/null +++ b/api/src/main/java/net/automatalib/graphs/concepts/MutableEdgeLabels.java @@ -0,0 +1,21 @@ +/* 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.concepts; + +public interface MutableEdgeLabels extends EdgeLabels { + + void setEdgeLabel(E edge, L label); +} diff --git a/api/src/main/java/net/automatalib/graphs/concepts/MutableKripkeInterpretation.java b/api/src/main/java/net/automatalib/graphs/concepts/MutableKripkeInterpretation.java new file mode 100644 index 0000000000..3e1299f0b0 --- /dev/null +++ b/api/src/main/java/net/automatalib/graphs/concepts/MutableKripkeInterpretation.java @@ -0,0 +1,23 @@ +/* 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.concepts; + +import java.util.Set; + +public interface MutableKripkeInterpretation extends KripkeInterpretation { + + void setAtomicPropositions(N node, Set atomicPropositions); +} diff --git a/api/src/main/java/net/automatalib/graphs/visualization/CFMPSVisualizationHelper.java b/api/src/main/java/net/automatalib/graphs/visualization/CFMPSVisualizationHelper.java new file mode 100644 index 0000000000..764d5204fb --- /dev/null +++ b/api/src/main/java/net/automatalib/graphs/visualization/CFMPSVisualizationHelper.java @@ -0,0 +1,106 @@ +/* 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.visualization; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.StringJoiner; + +import net.automatalib.commons.util.Pair; +import net.automatalib.graphs.ProceduralModalProcessGraph; +import net.automatalib.ts.modal.transition.ProceduralModalEdgeProperty; +import net.automatalib.visualization.DefaultVisualizationHelper; +import org.checkerframework.checker.nullness.qual.NonNull; + +public class CFMPSVisualizationHelper extends DefaultVisualizationHelper, Pair> { + + private final Map> pmpgs; + + // cast is fine, because we make sure to only query nodes/edges belonging to the respective procedures + @SuppressWarnings("unchecked") + public CFMPSVisualizationHelper(Map> pmpgs) { + this.pmpgs = (Map>) pmpgs; + } + + @Override + protected Collection> initialNodes() { + final List> initialNodes = new ArrayList<>(this.pmpgs.size()); + + for (Entry> e : this.pmpgs.entrySet()) { + final N init = e.getValue().getInitialNode(); + if (init != null) { + initialNodes.add(Pair.of(e.getKey(), init)); + } + } + + return initialNodes; + } + + @Override + public boolean getNodeProperties(Pair node, Map properties) { + + if (!super.getNodeProperties(node, properties)) { + return false; + } + + final L process = node.getFirst(); + @SuppressWarnings("assignment.type.incompatible") // we only use identifier for which procedures exists + final @NonNull ProceduralModalProcessGraph pmpg = this.pmpgs.get(process); + final Set aps = pmpg.getNodeProperty(node.getSecond()); + + if (aps.isEmpty()) { + properties.put(NodeAttrs.LABEL, ""); + } else { + properties.put(NodeAttrs.LABEL, aps.toString()); + } + + properties.put(NodeAttrs.SHAPE, NodeShapes.CIRCLE); + + return true; + } + + @Override + public boolean getEdgeProperties(Pair src, Pair edge, Pair tgt, Map properties) { + + if (!super.getEdgeProperties(src, edge, tgt, properties)) { + return false; + } + + final L process = edge.getFirst(); + @SuppressWarnings("assignment.type.incompatible") // we only use identifier for which procedures exists + final @NonNull ProceduralModalProcessGraph pmpg = this.pmpgs.get(process); + final ProceduralModalEdgeProperty prop = pmpg.getEdgeProperty(edge.getSecond()); + final StringJoiner styleJoiner = new StringJoiner(","); + + if (prop.isMayOnly()) { + styleJoiner.add(EdgeStyles.DASHED); + } + + if (prop.isProcess()) { + styleJoiner.add(EdgeStyles.BOLD); + } + + properties.put(EdgeAttrs.LABEL, String.valueOf(pmpg.getEdgeLabel(edge.getSecond()))); + properties.put(EdgeAttrs.STYLE, styleJoiner.toString()); + + return true; + } + +} diff --git a/api/src/main/java/net/automatalib/ts/modal/transition/ModalEdgeProperty.java b/api/src/main/java/net/automatalib/ts/modal/transition/ModalEdgeProperty.java index fe9df6d514..aeaa79892e 100644 --- a/api/src/main/java/net/automatalib/ts/modal/transition/ModalEdgeProperty.java +++ b/api/src/main/java/net/automatalib/ts/modal/transition/ModalEdgeProperty.java @@ -22,14 +22,14 @@ enum ModalType { MUST } - ModalType getType(); + ModalType getModalType(); default boolean isMayOnly() { - return getType() == ModalType.MAY; + return getModalType() == ModalType.MAY; } default boolean isMust() { - return getType() == ModalType.MUST; + return getModalType() == ModalType.MUST; } } diff --git a/api/src/main/java/net/automatalib/ts/modal/transition/MutableModalEdgeProperty.java b/api/src/main/java/net/automatalib/ts/modal/transition/MutableModalEdgeProperty.java index 085d9328d2..c0fc7d4002 100644 --- a/api/src/main/java/net/automatalib/ts/modal/transition/MutableModalEdgeProperty.java +++ b/api/src/main/java/net/automatalib/ts/modal/transition/MutableModalEdgeProperty.java @@ -17,14 +17,14 @@ public interface MutableModalEdgeProperty extends ModalEdgeProperty { - void setType(ModalType type); + void setModalType(ModalType type); default void setMayOnly() { - setType(ModalType.MAY); + setModalType(ModalType.MAY); } default void setMust() { - setType(ModalType.MUST); + setModalType(ModalType.MUST); } } diff --git a/api/src/main/java/net/automatalib/ts/modal/transition/MutableProceduralModalEdgeProperty.java b/api/src/main/java/net/automatalib/ts/modal/transition/MutableProceduralModalEdgeProperty.java new file mode 100644 index 0000000000..5c81a7d85e --- /dev/null +++ b/api/src/main/java/net/automatalib/ts/modal/transition/MutableProceduralModalEdgeProperty.java @@ -0,0 +1,30 @@ +/* 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.ts.modal.transition; + +public interface MutableProceduralModalEdgeProperty extends ProceduralModalEdgeProperty, MutableModalEdgeProperty { + + void setProceduralType(ProceduralType type); + + default void setProcess() { + setProceduralType(ProceduralType.PROCESS); + } + + default void setInternal() { + setProceduralType(ProceduralType.INTERNAL); + } + +} diff --git a/api/src/main/java/net/automatalib/ts/modal/transition/ProceduralModalEdgeProperty.java b/api/src/main/java/net/automatalib/ts/modal/transition/ProceduralModalEdgeProperty.java new file mode 100644 index 0000000000..0db1e51507 --- /dev/null +++ b/api/src/main/java/net/automatalib/ts/modal/transition/ProceduralModalEdgeProperty.java @@ -0,0 +1,35 @@ +/* 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.ts.modal.transition; + +public interface ProceduralModalEdgeProperty extends ModalEdgeProperty { + + enum ProceduralType { + PROCESS, + INTERNAL + } + + ProceduralType getProceduralType(); + + default boolean isProcess() { + return getProceduralType() == ProceduralType.PROCESS; + } + + default boolean isInternal() { + return getProceduralType() == ProceduralType.INTERNAL; + } + +} diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 6aa3ab9587..807fa469bf 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -76,6 +76,13 @@ limitations under the License. net/automatalib/modelcheckers/ltsmin/Token.class net/automatalib/modelcheckers/ltsmin/TokenMgrError.class + + net/automatalib/modelcheckers/m3c/formula/parser/InternalM3CParser*.class + net/automatalib/modelcheckers/m3c/formula/parser/ParseException.class + net/automatalib/modelcheckers/m3c/formula/parser/SimpleCharStream.class + net/automatalib/modelcheckers/m3c/formula/parser/Token.class + net/automatalib/modelcheckers/m3c/formula/parser/TokenMgrError.class + net/automatalib/modelcheckers/ltsmin/ltl/LTSminLTLAlternatingBuilder.class net/automatalib/modelcheckers/ltsmin/ltl/LTSminLTLDFABuilder.class @@ -254,6 +261,7 @@ limitations under the License. -AskipDefs=^net.automatalib.serialization.taf.parser.(Internal.*|Token.*|SimpleCharStream)|\ ^net.automatalib.serialization.dot.(Internal.*|Token.*|SimpleCharStream)|\ ^net.automatalib.modelcheckers.ltsmin.(Internal.*|Token.*|SimpleCharStream)|\ + ^net.automatalib.modelcheckers.m3c.formula.parser.(Internal.*|Token.*|SimpleCharStream)|\ -AskipUses=^com.google.*|\ ^java.(awt.*|util.Arrays|io.StreamTokenizer)|\ diff --git a/build-tools/src/main/resources/automatalib-spotbugs-exclusions.xml b/build-tools/src/main/resources/automatalib-spotbugs-exclusions.xml index 93b12b13dd..ff87bbbcbb 100644 --- a/build-tools/src/main/resources/automatalib-spotbugs-exclusions.xml +++ b/build-tools/src/main/resources/automatalib-spotbugs-exclusions.xml @@ -96,6 +96,14 @@ limitations under the License. + + + + + + + + \ No newline at end of file diff --git a/core/src/main/java/net/automatalib/graphs/base/DefaultMCFPS.java b/core/src/main/java/net/automatalib/graphs/base/DefaultMCFPS.java new file mode 100644 index 0000000000..0fe1089471 --- /dev/null +++ b/core/src/main/java/net/automatalib/graphs/base/DefaultMCFPS.java @@ -0,0 +1,48 @@ +/* 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.base; + +import java.util.Collections; +import java.util.Map; + +import com.google.common.base.Preconditions; +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.graphs.ProceduralModalProcessGraph; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class DefaultMCFPS implements ContextFreeModalProcessSystem { + + private final Map> pmpgs; + private final L mainProcess; + + public DefaultMCFPS(L mainProcess, Map> pmpgs) { + Preconditions.checkArgument(pmpgs.containsKey(mainProcess), + "There exists no process graph for the main process"); + + this.pmpgs = Collections.unmodifiableMap(pmpgs); + this.mainProcess = mainProcess; + } + + @Override + public Map> getPMPGs() { + return this.pmpgs; + } + + @Override + public @Nullable L getMainProcess() { + return this.mainProcess; + } +} diff --git a/core/src/main/java/net/automatalib/graphs/base/compact/CompactPMPG.java b/core/src/main/java/net/automatalib/graphs/base/compact/CompactPMPG.java new file mode 100644 index 0000000000..f7e85ba2d5 --- /dev/null +++ b/core/src/main/java/net/automatalib/graphs/base/compact/CompactPMPG.java @@ -0,0 +1,114 @@ +/* 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.base.compact; + +import java.util.Collections; +import java.util.Set; + +import net.automatalib.commons.smartcollections.ResizingArrayStorage; +import net.automatalib.graphs.MutableProceduralModalProcessGraph; +import net.automatalib.ts.modal.transition.ModalEdgeProperty.ModalType; +import net.automatalib.ts.modal.transition.MutableProceduralModalEdgeProperty; +import net.automatalib.ts.modal.transition.ProceduralModalEdgeProperty.ProceduralType; +import net.automatalib.ts.modal.transition.ProceduralModalEdgePropertyImpl; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class CompactPMPG + extends AbstractCompactGraph, Set, MutableProceduralModalEdgeProperty> + implements MutableProceduralModalProcessGraph, AP, MutableProceduralModalEdgeProperty> { + + private final ResizingArrayStorage<@Nullable Set> nodeProperties; + private final L defaultLabel; + private int initialNode; + private int finalNode; + + public CompactPMPG(L defaultLabel) { + super(); + this.nodeProperties = new ResizingArrayStorage<>(Set.class); + this.defaultLabel = defaultLabel; + this.initialNode = -1; + this.finalNode = -1; + } + + @Override + public void setInitialNode(@Nullable Integer initialNode) { + if (initialNode == null) { + this.initialNode = -1; + } else { + this.initialNode = initialNode; + } + } + + @Override + public void setFinalNode(@Nullable Integer finalNode) { + if (finalNode == null) { + this.finalNode = -1; + } else { + this.finalNode = finalNode; + } + } + + @Override + public L getEdgeLabel(CompactPMPGEdge edge) { + return edge.getLabel(); + } + + @Override + public void setEdgeLabel(CompactPMPGEdge edge, L label) { + edge.setLabel(label); + } + + @Override + public @Nullable Integer getFinalNode() { + return this.finalNode < 0 ? null : this.finalNode; + } + + @Override + public @Nullable Integer getInitialNode() { + return this.initialNode < 0 ? null : this.initialNode; + } + + @Override + public void setNodeProperty(int node, @Nullable Set property) { + nodeProperties.ensureCapacity(node + 1); + nodeProperties.array[node] = property; + } + + @Override + protected CompactPMPGEdge createEdge(int source, + int target, + @Nullable MutableProceduralModalEdgeProperty property) { + final MutableProceduralModalEdgeProperty prop; + + if (property == null) { + prop = new ProceduralModalEdgePropertyImpl(ProceduralType.INTERNAL, ModalType.MUST); + } else { + prop = property; + } + + return new CompactPMPGEdge<>(target, prop, this.defaultLabel); + } + + @Override + public Set getNodeProperties(int node) { + if (node > nodeProperties.array.length) { + return Collections.emptySet(); + } + + final Set props = nodeProperties.array[node]; + return props == null ? Collections.emptySet() : props; + } +} diff --git a/core/src/main/java/net/automatalib/graphs/base/compact/CompactPMPGEdge.java b/core/src/main/java/net/automatalib/graphs/base/compact/CompactPMPGEdge.java new file mode 100644 index 0000000000..408b733a58 --- /dev/null +++ b/core/src/main/java/net/automatalib/graphs/base/compact/CompactPMPGEdge.java @@ -0,0 +1,34 @@ +/* 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.base.compact; + +public class CompactPMPGEdge extends CompactEdge { + + private L label; + + public CompactPMPGEdge(int target, EP property, L label) { + super(target, property); + this.label = label; + } + + public L getLabel() { + return label; + } + + void setLabel(L label) { + this.label = label; + } +} diff --git a/core/src/main/java/net/automatalib/ts/modal/transition/ModalContractEdgePropertyImpl.java b/core/src/main/java/net/automatalib/ts/modal/transition/ModalContractEdgePropertyImpl.java index dbb9e0ef7b..a3cf0134c2 100644 --- a/core/src/main/java/net/automatalib/ts/modal/transition/ModalContractEdgePropertyImpl.java +++ b/core/src/main/java/net/automatalib/ts/modal/transition/ModalContractEdgePropertyImpl.java @@ -52,16 +52,13 @@ public void setColor(EdgeColor color) { @Override public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final ModalContractEdgePropertyImpl that = (ModalContractEdgePropertyImpl) o; - return this.getType() == that.getType() && this.tau == that.tau && this.color == that.color; + return this.tau == that.tau && this.color == that.color; } @Override diff --git a/core/src/main/java/net/automatalib/ts/modal/transition/ModalContractMembershipEdgePropertyImpl.java b/core/src/main/java/net/automatalib/ts/modal/transition/ModalContractMembershipEdgePropertyImpl.java index a26d682c2c..0687a8ab60 100644 --- a/core/src/main/java/net/automatalib/ts/modal/transition/ModalContractMembershipEdgePropertyImpl.java +++ b/core/src/main/java/net/automatalib/ts/modal/transition/ModalContractMembershipEdgePropertyImpl.java @@ -15,8 +15,6 @@ */ package net.automatalib.ts.modal.transition; -import java.util.Objects; - import org.checkerframework.checker.nullness.qual.Nullable; public class ModalContractMembershipEdgePropertyImpl extends ModalContractEdgePropertyImpl @@ -39,28 +37,21 @@ public int getMemberId() { return memberId; } - @Override - public String toString() { - return "color={" + getColor() + "}, memberId={" + memberId + "}, type={" + getType() + '}'; - } - @Override public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final ModalContractMembershipEdgePropertyImpl that = (ModalContractMembershipEdgePropertyImpl) o; - return this.getType() == that.getType() && this.isTau() == that.isTau() && this.getColor() == that.getColor() && - memberId == that.memberId; + return this.memberId == that.memberId; } @Override public int hashCode() { - return Objects.hash(super.hashCode(), memberId); + int result = super.hashCode(); + result = 31 * result + Integer.hashCode(memberId); + return result; } } diff --git a/core/src/main/java/net/automatalib/ts/modal/transition/ModalEdgePropertyImpl.java b/core/src/main/java/net/automatalib/ts/modal/transition/ModalEdgePropertyImpl.java index 142562d1b2..f5157a47a8 100644 --- a/core/src/main/java/net/automatalib/ts/modal/transition/ModalEdgePropertyImpl.java +++ b/core/src/main/java/net/automatalib/ts/modal/transition/ModalEdgePropertyImpl.java @@ -21,25 +21,20 @@ public class ModalEdgePropertyImpl implements MutableModalEdgeProperty { - private ModalType type; + private ModalType modalType; - public ModalEdgePropertyImpl(ModalType type) { - this.type = type; + public ModalEdgePropertyImpl(ModalType modalType) { + this.modalType = modalType; } @Override - public ModalType getType() { - return this.type; + public ModalType getModalType() { + return this.modalType; } @Override - public void setType(ModalType type) { - this.type = type; - } - - @Override - public String toString() { - return "[type=" + type + ']'; + public void setModalType(ModalType type) { + this.modalType = type; } @Override @@ -52,11 +47,12 @@ public boolean equals(@Nullable Object o) { } final ModalEdgePropertyImpl that = (ModalEdgePropertyImpl) o; - return type == that.type; + + return this.modalType == that.modalType; } @Override public int hashCode() { - return Objects.hashCode(type); + return Objects.hashCode(modalType); } } diff --git a/core/src/main/java/net/automatalib/ts/modal/transition/ProceduralModalEdgePropertyImpl.java b/core/src/main/java/net/automatalib/ts/modal/transition/ProceduralModalEdgePropertyImpl.java new file mode 100644 index 0000000000..948556fc44 --- /dev/null +++ b/core/src/main/java/net/automatalib/ts/modal/transition/ProceduralModalEdgePropertyImpl.java @@ -0,0 +1,59 @@ +/* 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.ts.modal.transition; + +import java.util.Objects; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public class ProceduralModalEdgePropertyImpl extends ModalEdgePropertyImpl + implements MutableProceduralModalEdgeProperty { + + private ProceduralType proceduralType; + + public ProceduralModalEdgePropertyImpl(ProceduralType proceduralType, ModalType modalType) { + super(modalType); + this.proceduralType = proceduralType; + } + + @Override + public ProceduralType getProceduralType() { + return this.proceduralType; + } + + @Override + public void setProceduralType(ProceduralType type) { + this.proceduralType = type; + } + + @Override + public boolean equals(@Nullable Object o) { + if (!super.equals(o)) { + return false; + } + + final ProceduralModalEdgePropertyImpl that = (ProceduralModalEdgePropertyImpl) o; + + return this.proceduralType == that.proceduralType; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(this.proceduralType); + return result; + } +} diff --git a/core/src/test/java/net/automatalib/ts/modal/CompactMTSTest.java b/core/src/test/java/net/automatalib/ts/modal/CompactMTSTest.java index a5960f3c04..f6cd1f3f56 100644 --- a/core/src/test/java/net/automatalib/ts/modal/CompactMTSTest.java +++ b/core/src/test/java/net/automatalib/ts/modal/CompactMTSTest.java @@ -160,26 +160,26 @@ void testJasper() { Assertions.assertThat(s.getTransitions(as0, "b")) .containsExactly(t2) .allMatch(t -> Objects.equals(t.getTarget(), as1)) - .allMatch(t -> t.getProperty().getType() == ModalType.MUST); + .allMatch(t -> t.getProperty().getModalType() == ModalType.MUST); Assertions.assertThat(s.getTransitions(as1, "a")) .containsExactly(t3) .allMatch(t -> Objects.equals(t.getTarget(), as1)) - .allMatch(t -> t.getProperty().getType() == ModalType.MUST); + .allMatch(t -> t.getProperty().getModalType() == ModalType.MUST); Assertions.assertThat(s.getTransitions(as1, "b")) .containsExactly(t4) .allMatch(t -> Objects.equals(t.getTarget(), as2)) - .allMatch(t -> t.getProperty().getType() == ModalType.MAY); + .allMatch(t -> t.getProperty().getModalType() == ModalType.MAY); Assertions.assertThat(s.getTransitions(as2, "a")) .containsExactly(t5) .allMatch(t -> Objects.equals(t.getTarget(), as2)) - .allMatch(t -> t.getProperty().getType() == ModalType.MAY); + .allMatch(t -> t.getProperty().getModalType() == ModalType.MAY); Assertions.assertThat(s.getTransitions(as2, "b")) .containsExactly(t6) .allMatch(t -> Objects.equals(t.getTarget(), as2)) - .allMatch(t -> t.getProperty().getType() == ModalType.MAY); + .allMatch(t -> t.getProperty().getModalType() == ModalType.MAY); } } \ No newline at end of file diff --git a/distribution/pom.xml b/distribution/pom.xml index 1c5eca10a2..260968dcc7 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -87,6 +87,11 @@ limitations under the License. automata-modelchecking-ltsmin + + net.automatalib + automata-modelchecking-m3c + + net.automatalib @@ -246,6 +251,13 @@ limitations under the License. sources + + net.automatalib + automata-modelchecking-m3c + ${project.version} + sources + + net.automatalib diff --git a/examples/pom.xml b/examples/pom.xml index b8a4b29b9a..fd4caed34d 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -66,6 +66,10 @@ limitations under the License. net.automatalib automata-modelchecking-ltsmin + + net.automatalib + automata-modelchecking-m3c + net.automatalib automata-serialization-dot @@ -85,6 +89,11 @@ limitations under the License. dk.brics.automaton automaton + + info.scce + addlib-cudd + runtime + org.slf4j slf4j-api diff --git a/examples/src/main/java/net/automatalib/examples/modelchecking/M3CSPAExample.java b/examples/src/main/java/net/automatalib/examples/modelchecking/M3CSPAExample.java new file mode 100644 index 0000000000..276f40dc0c --- /dev/null +++ b/examples/src/main/java/net/automatalib/examples/modelchecking/M3CSPAExample.java @@ -0,0 +1,79 @@ +/* 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.examples.modelchecking; + +import java.util.function.Function; + +import net.automatalib.automata.spa.CFMPSView; +import net.automatalib.automata.spa.SPA; +import net.automatalib.examples.spa.PalindromeExample; +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import net.automatalib.modelcheckers.m3c.solver.M3CSolver; +import net.automatalib.modelcheckers.m3c.solver.M3CSolver.TypedM3CSolver; +import net.automatalib.modelcheckers.m3c.solver.M3CSolvers; +import net.automatalib.visualization.Visualization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An example in which we transform the {@link PalindromeExample palindrome SPA} into a {@link + * ContextFreeModalProcessSystem} and use the {@link M3CSolver} to evaluate properties on the system. + * + * @author frohme + */ +public final class M3CSPAExample { + + private static final Logger LOGGER = LoggerFactory.getLogger(M3CSPAExample.class); + + private M3CSPAExample() { + // prevent initialization + } + + public static void main(String[] args) throws ParseException { + final SPA spa = PalindromeExample.buildSPA(); + final CFMPSView view = new CFMPSView<>(spa); + + //@formatter:off + final String[] formulas = {"mu X.(<>X || true)", // there exists a path with "bb" + "mu X.(<>X || true)", // there exists a path with "bSb" + "mu X.(<>X || true)", // there exists a path with "bTb" + "true", // There exists a starting sequence of STa + "true", // There exists a starting sequence of STb + "true", // There exists a starting sequence of STc + "true", // There exists a starting sequence of SaTc + "true", // There exists a starting sequence of SaSTc + "nu X. ([]X && [] false)", // all paths reach the final state + "mu X. (<>X || [] false)", // there exists a path to the final state + "nu X. ([]X && mu Y. (<>Y || [] false))", // on all paths there exists a path to the final state + "nu X. ([]X && (true -> [S](mu Y. (<>Y || true))))", // globally, if there exists an S, it must be followed by an R eventually + }; + //@formatter:on + + final Function labelParser = s -> s.charAt(0); + final Function apParser = s -> null; + final TypedM3CSolver> solver = M3CSolvers.typedSolver(view); + + for (String f : formulas) { + final FormulaNode formula = M3CParser.parse(f, labelParser, apParser); + LOGGER.info("Is '{}' satisfied? {}", f, solver.solve(formula)); + } + + Visualization.visualize(view); + } +} diff --git a/examples/src/main/java/net/automatalib/examples/spa/PalindromeExample.java b/examples/src/main/java/net/automatalib/examples/spa/PalindromeExample.java index d41513c07f..8aab8b65ad 100644 --- a/examples/src/main/java/net/automatalib/examples/spa/PalindromeExample.java +++ b/examples/src/main/java/net/automatalib/examples/spa/PalindromeExample.java @@ -30,6 +30,7 @@ import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; import net.automatalib.words.impl.DefaultSPAAlphabet; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,19 +49,7 @@ private PalindromeExample() { } public static void main(String[] args) { - - final Alphabet internalAlphabet = Alphabets.characters('a', 'c'); - final Alphabet callAlphabet = Alphabets.characters('S', 'T'); - final SPAAlphabet alphabet = new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, 'R'); - - final DFA sProcedure = buildSProcedure(alphabet); - final DFA tProcedure = buildTProcedure(alphabet); - - final Map> subModels = new HashMap<>(); - subModels.put('S', sProcedure); - subModels.put('T', tProcedure); - - final SPA spa = new StackSPA<>(alphabet, 'S', subModels); + final SPA spa = buildSPA(); LOGGER.info("Well-matched palindromes"); checkWord(spa, Word.fromCharSequence("SR")); @@ -88,6 +77,22 @@ private static void checkWord(SPA spa, Word input) { LOGGER.info("Word '{}' is {}accepted by the SPA", input, accepted ? "" : "not "); } + public static SPA buildSPA() { + final Alphabet internalAlphabet = Alphabets.characters('a', 'c'); + final Alphabet callAlphabet = Alphabets.characters('S', 'T'); + final SPAAlphabet alphabet = new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, 'R'); + + final DFA sProcedure = buildSProcedure(alphabet); + final DFA tProcedure = buildTProcedure(alphabet); + + final Map> subModels = new HashMap<>(); + subModels.put('S', sProcedure); + subModels.put('T', tProcedure); + + // explicit type variable declaration to make checker-framework happy + return new StackSPA<@Nullable Object, Character>(alphabet, 'S', subModels); + } + /** * Utility method for building a procedure based on a {@link CompactDFA} that emits terminal symbols 'a', 'b' or * delegates to procedure {@link #buildTProcedure(SPAAlphabet) 'T'}. diff --git a/examples/src/test/java/net/automatalib/examples/ExamplesTest.java b/examples/src/test/java/net/automatalib/examples/ExamplesTest.java index 7c878e90cd..00a6f42a93 100644 --- a/examples/src/test/java/net/automatalib/examples/ExamplesTest.java +++ b/examples/src/test/java/net/automatalib/examples/ExamplesTest.java @@ -34,10 +34,12 @@ import net.automatalib.examples.incremental.IncrementalPCDFAExample; import net.automatalib.examples.modelchecking.LTSminExample; import net.automatalib.examples.modelchecking.LTSminMonitorExample; +import net.automatalib.examples.modelchecking.M3CSPAExample; import net.automatalib.examples.spa.PalindromeExample; import net.automatalib.examples.vpda.OneSEVPAExample; import net.automatalib.modelcheckers.ltsmin.LTSminUtil; import net.automatalib.modelcheckers.ltsmin.LTSminVersion; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -125,6 +127,18 @@ public void testLTSminMonitorExample() { LTSminMonitorExample.main(new String[0]); } + @Test + public void testM3CSPAExample() throws InterruptedException, InvocationTargetException { + checkJVMCompatibility(); + SwingUtilities.invokeAndWait(() -> { + try { + M3CSPAExample.main(new String[0]); + } catch (ParseException e) { + throw new RuntimeException(e); + } + }); + } + @Test public void testSPAPalindromeExample() throws InvocationTargetException, InterruptedException { checkJVMCompatibility(); diff --git a/modelchecking/m3c/pom.xml b/modelchecking/m3c/pom.xml new file mode 100644 index 0000000000..5293225919 --- /dev/null +++ b/modelchecking/m3c/pom.xml @@ -0,0 +1,91 @@ + + + + 4.0.0 + + + net.automatalib + automata-modelchecking-parent + 0.11.0-SNAPSHOT + ../pom.xml + + + automata-modelchecking-m3c + + AutomataLib :: Model Checking :: M3C + The Modal Meta Model Checker as presented in the paper "M3C: Modal Meta Model Checking". Note that this + implementation requires a dependency to a specific ADDLib backend (see https://add-lib.scce.info/), which is + not explicitly included due to packaging reasons. + + + + + + net.automatalib + automata-api + + + net.automatalib + automata-commons-util + + + + + com.google.guava + guava + + + + info.scce + addlib-core + ${addlib.version} + + + + + org.checkerframework + checker-qual + + + + + info.scce + addlib-cudd + ${addlib.version} + test + + + net.automatalib + automata-core + test + + + org.testng + testng + + + + + + + org.codehaus.mojo + javacc-maven-plugin + + + + diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractBinaryFormulaNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractBinaryFormulaNode.java new file mode 100644 index 0000000000..69a3bcf2ad --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractBinaryFormulaNode.java @@ -0,0 +1,99 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Abstract super-class for binary (sub-) formulas. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public abstract class AbstractBinaryFormulaNode extends AbstractFormulaNode { + + private final FormulaNode leftChild; + private final FormulaNode rightChild; + + public AbstractBinaryFormulaNode(FormulaNode leftChild, FormulaNode rightChild) { + this.leftChild = leftChild; + this.rightChild = rightChild; + } + + public FormulaNode getRightChild() { + return this.rightChild; + } + + public int getVarNumberRight() { + return this.rightChild.getVarNumber(); + } + + public FormulaNode getLeftChild() { + return this.leftChild; + } + + public int getVarNumberLeft() { + return this.leftChild.getVarNumber(); + } + + @Override + public boolean equals(@Nullable Object o) { + if (!super.equals(o)) { + return false; + } + + final AbstractBinaryFormulaNode that = (AbstractBinaryFormulaNode) o; + + return this.leftChild.equals(that.leftChild) && this.rightChild.equals(that.rightChild); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + leftChild.hashCode(); + result = 31 * result + rightChild.hashCode(); + return result; + } + + protected void printBinaryFormulaNode(Appendable a, String operator) throws IOException { + a.append('('); + getLeftChild().print(a); + a.append(' '); + a.append(operator); + a.append(' '); + getRightChild().print(a); + a.append(')'); + } + + protected void printUntilNode(Appendable a, char quantifier, char weakOrStrong) throws IOException { + a.append('('); + a.append(quantifier); + a.append('('); + getLeftChild().print(a); + a.append(' '); + a.append(weakOrStrong); + a.append(' '); + getRightChild().print(a); + a.append("))"); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractFormulaNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractFormulaNode.java new file mode 100644 index 0000000000..5b440b942c --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractFormulaNode.java @@ -0,0 +1,64 @@ +/* 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.modelcheckers.m3c.formula; + +import net.automatalib.commons.util.strings.AbstractPrintable; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Abstract super-class for (sub-) formulas. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public abstract class AbstractFormulaNode extends AbstractPrintable implements FormulaNode { + + private int varNumber; + + @Override + public int getVarNumber() { + return varNumber; + } + + @Override + public void setVarNumber(int varNumber) { + this.varNumber = varNumber; + } + + @Override + public int hashCode() { + return Integer.hashCode(varNumber); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final AbstractFormulaNode that = (AbstractFormulaNode) o; + + return this.varNumber == that.varNumber; + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractModalFormulaNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractModalFormulaNode.java new file mode 100644 index 0000000000..6a93de431a --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractModalFormulaNode.java @@ -0,0 +1,78 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; +import java.util.Objects; + +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Abstract super-class for modal (sub-) formulas. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public abstract class AbstractModalFormulaNode extends AbstractUnaryFormulaNode { + + private final @Nullable L action; + + public AbstractModalFormulaNode(@Nullable L action, FormulaNode node) { + super(node); + this.action = action; + } + + public @Nullable L getAction() { + return action; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(action); + return result; + } + + @Override + public boolean equals(@Nullable Object o) { + if (!super.equals(o)) { + return false; + } + + final AbstractModalFormulaNode that = (AbstractModalFormulaNode) o; + + return Objects.equals(this.action, that.action); + } + + protected void printMuCalcNode(Appendable a, char leftModalitySymbol, char rightModalitySymbol) throws IOException { + a.append('('); + a.append(leftModalitySymbol); + + if (action != null) { + a.append(action.toString()); + } + + a.append(rightModalitySymbol); + a.append(' '); + getChild().print(a); + a.append(')'); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractUnaryFormulaNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractUnaryFormulaNode.java new file mode 100644 index 0000000000..a36e5c3d65 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AbstractUnaryFormulaNode.java @@ -0,0 +1,73 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Abstract super-class for unary (sub-) formulas. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public abstract class AbstractUnaryFormulaNode extends AbstractFormulaNode { + + private final FormulaNode child; + + public AbstractUnaryFormulaNode(FormulaNode child) { + this.child = child; + } + + public FormulaNode getChild() { + return this.child; + } + + public int getVarNumberChild() { + return this.child.getVarNumber(); + } + + @Override + public boolean equals(@Nullable Object o) { + if (!super.equals(o)) { + return false; + } + + final AbstractUnaryFormulaNode that = (AbstractUnaryFormulaNode) o; + + return this.child.equals(that.child); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + child.hashCode(); + return result; + } + + protected void printUnaryFormulaNode(Appendable a, String operator) throws IOException { + a.append('('); + a.append(operator); + a.append(' '); + getChild().print(a); + a.append(')'); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AndNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AndNode.java new file mode 100644 index 0000000000..fa42960eb9 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AndNode.java @@ -0,0 +1,48 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "{@literal &&}" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class AndNode extends AbstractBinaryFormulaNode { + + public AndNode(FormulaNode leftChild, FormulaNode rightChild) { + super(leftChild, rightChild); + } + + @Override + public void print(Appendable a) throws IOException { + printBinaryFormulaNode(a, "&&"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AtomicNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AtomicNode.java new file mode 100644 index 0000000000..50b2fa532e --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/AtomicNode.java @@ -0,0 +1,75 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; +import java.util.Objects; + +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Java representation of an "atomic proposition" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class AtomicNode extends AbstractFormulaNode { + + private final AP proposition; + + public AtomicNode(AP proposition) { + this.proposition = proposition; + } + + public AP getProposition() { + return proposition; + } + + @Override + public void print(Appendable a) throws IOException { + a.append('\"'); + a.append(Objects.toString(proposition)); + a.append('\"'); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hash(proposition); + return result; + } + + @Override + public boolean equals(@Nullable Object o) { + if (!super.equals(o)) { + return false; + } + + final AtomicNode that = (AtomicNode) o; + return Objects.equals(this.proposition, that.proposition); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/BoxNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/BoxNode.java new file mode 100644 index 0000000000..38435d6c23 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/BoxNode.java @@ -0,0 +1,53 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Java representation of a "[]" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class BoxNode extends AbstractModalFormulaNode { + + public BoxNode(FormulaNode node) { + this(null, node); + } + + public BoxNode(@Nullable L action, FormulaNode node) { + super(action, node); + } + + @Override + public void print(Appendable a) throws IOException { + printMuCalcNode(a, '[', ']'); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/DependencyGraph.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/DependencyGraph.java new file mode 100644 index 0000000000..32d8082457 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/DependencyGraph.java @@ -0,0 +1,191 @@ +/* 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.modelcheckers.m3c.formula; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.automatalib.modelcheckers.m3c.formula.modalmu.AbstractFixedPointFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.GfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.VariableNode; + +/** + * A dependency graph is used to represent a hierarchical equational system. + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public final class DependencyGraph { + + /* All formulaNodes except FixedPoint- and VariableNode */ + private final List> formulaNodes; + + /* FormulaNodes divided into equational blocks */ + private final List> blocks; + + /* nu X1 -> fixedPointVarMap.get("X1") returns the node associated to nu X1 */ + private final Map> fixedPointVarMap; + private final FormulaNode ast; + private final int numVars; + + public DependencyGraph(FormulaNode root) { + this.formulaNodes = new ArrayList<>(); + this.blocks = new ArrayList<>(); + this.fixedPointVarMap = new HashMap<>(); + this.ast = root.toNNF(); + this.numVars = setVarNumbers(ast, 0); + createEquationalBlocks(ast); + } + + private void sortBlocks() { + for (EquationalBlock block : blocks) { + Collections.reverse(block.getNodes()); + } + } + + private void createEquationalBlocks(FormulaNode root) { + boolean isMax = !(root instanceof LfpNode); + EquationalBlock block = new EquationalBlock<>(isMax); + blocks.add(block); + createEquationalBlocks(root, 0); + sortBlocks(); + } + + private void createEquationalBlocks(FormulaNode node, int blockNumber) { + EquationalBlock currentBlock = blocks.get(blockNumber); + boolean isMax = currentBlock.isMaxBlock(); + + /* Check if new equational block has to be created */ + int newBlockNumber = blockNumber; + if (node instanceof GfpNode && !isMax) { + newBlockNumber = blocks.size(); + currentBlock = new EquationalBlock<>(true); + blocks.add(currentBlock); + } else if (node instanceof LfpNode && isMax) { + newBlockNumber = blocks.size(); + currentBlock = new EquationalBlock<>(false); + blocks.add(currentBlock); + } + + /* Only keep track of non FixedPoint/VariableNodes in blocks */ + if (!(node instanceof AbstractFixedPointFormulaNode || node instanceof VariableNode)) { + currentBlock.addNode(node); + } + + /* Recurse into subtrees */ + if (node instanceof AbstractUnaryFormulaNode) { + final AbstractUnaryFormulaNode unaryNode = (AbstractUnaryFormulaNode) node; + createEquationalBlocks(unaryNode.getChild(), newBlockNumber); + } else if (node instanceof AbstractBinaryFormulaNode) { + final AbstractBinaryFormulaNode binaryNode = (AbstractBinaryFormulaNode) node; + createEquationalBlocks(binaryNode.getLeftChild(), newBlockNumber); + createEquationalBlocks(binaryNode.getRightChild(), newBlockNumber); + } + } + + private int setVarNumbers(FormulaNode node, int varNumber) { + /* Fill fixedPointVarMap */ + if (node instanceof AbstractFixedPointFormulaNode) { + fixedPointVarMap.put(((AbstractFixedPointFormulaNode) node).getVariable(), node); + } + + /* Set node's variableNumber */ + if (node instanceof VariableNode) { + /* VariableNode has same variableNumber as the fixed point it references */ + String refVariable = ((VariableNode) node).getVariable(); + FormulaNode refNode = fixedPointVarMap.get(refVariable); + assert refNode != null : "Cannot reference unknown variable"; // validated by the parser + node.setVarNumber(refNode.getVarNumber()); + } else { + node.setVarNumber(varNumber); + } + + int newVarNumber = varNumber; + /* Only count non FixedPoint/VariableNodes */ + if (!(node instanceof AbstractFixedPointFormulaNode || node instanceof VariableNode)) { + newVarNumber++; + formulaNodes.add(node); + } + + /* Recurse into subtrees */ + if (node instanceof AbstractUnaryFormulaNode) { + final AbstractUnaryFormulaNode unaryNode = (AbstractUnaryFormulaNode) node; + newVarNumber = setVarNumbers(unaryNode.getChild(), newVarNumber); + } else if (node instanceof AbstractBinaryFormulaNode) { + final AbstractBinaryFormulaNode binaryNode = (AbstractBinaryFormulaNode) node; + newVarNumber = setVarNumbers(binaryNode.getLeftChild(), newVarNumber); + newVarNumber = setVarNumbers(binaryNode.getRightChild(), newVarNumber); + } + + return newVarNumber; + } + + /** + * Returns the equational block for the given index. + * + * @param index + * index of the equational block to return + * + * @return the equational block at the given {@code index}. + */ + public EquationalBlock getBlock(int index) { + return blocks.get(index); + } + + /** + * Returns the number of variables which is equal to the number of subformulas. + * + * @return the number of variables. + */ + public int getNumVariables() { + return numVars; + } + + /** + * Returns the list of all subformulas. + * + * @return the list of all subformulas. + */ + public List> getFormulaNodes() { + return formulaNodes; + } + + /** + * Returns all equational blocks of the equational system. + * + * @return all equational blocks of the equational system. + */ + public List> getBlocks() { + return blocks; + } + + /** + * Returns the abstract syntax tree of the input formula after it has been transformed into negation normal form. + * + * @return the abstract syntax tree in negation normal form. + */ + public FormulaNode getAST() { + return ast; + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/DiamondNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/DiamondNode.java new file mode 100644 index 0000000000..4f537ae327 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/DiamondNode.java @@ -0,0 +1,53 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Java representation of a "{@literal <>}" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class DiamondNode extends AbstractModalFormulaNode { + + public DiamondNode(FormulaNode node) { + this(null, node); + } + + public DiamondNode(@Nullable L action, FormulaNode node) { + super(action, node); + } + + @Override + public void print(Appendable a) throws IOException { + printMuCalcNode(a, '<', '>'); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/EquationalBlock.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/EquationalBlock.java new file mode 100644 index 0000000000..6733fd69d9 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/EquationalBlock.java @@ -0,0 +1,53 @@ +/* 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.modelcheckers.m3c.formula; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents an equational block that aggregates its reference formula nodes. + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class EquationalBlock { + + private final List> nodes; + private final boolean isMaxBlock; + + public EquationalBlock(boolean isMaxBlock) { + this.isMaxBlock = isMaxBlock; + this.nodes = new ArrayList<>(); + } + + public List> getNodes() { + return nodes; + } + + public void addNode(FormulaNode node) { + nodes.add(node); + } + + public boolean isMaxBlock() { + return isMaxBlock; + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/FalseNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/FalseNode.java new file mode 100644 index 0000000000..06ad0ec47f --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/FalseNode.java @@ -0,0 +1,44 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "false" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class FalseNode extends AbstractFormulaNode { + + @Override + public void print(Appendable a) throws IOException { + a.append("false"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/FormulaNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/FormulaNode.java new file mode 100644 index 0000000000..69e056bfd8 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/FormulaNode.java @@ -0,0 +1,45 @@ +/* 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.modelcheckers.m3c.formula; + +import net.automatalib.commons.util.strings.Printable; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; +import net.automatalib.modelcheckers.m3c.formula.visitor.NNFVisitor; + +/** + * Generic interface for formulas return by {@link M3CParser}s. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + * @author frohme + */ +public interface FormulaNode extends Printable { + + T accept(FormulaNodeVisitor visitor); + + default FormulaNode toNNF() { + return new NNFVisitor().transformToNNF(this); + } + + int getVarNumber(); + + void setVarNumber(int varNumber); +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/NotNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/NotNode.java new file mode 100644 index 0000000000..0643c62ffe --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/NotNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "!" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class NotNode extends AbstractUnaryFormulaNode { + + public NotNode(FormulaNode node) { + super(node); + } + + @Override + public void print(Appendable a) throws IOException { + a.append("(!"); + getChild().print(a); + a.append(')'); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/OrNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/OrNode.java new file mode 100644 index 0000000000..9f2c10dc55 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/OrNode.java @@ -0,0 +1,48 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "||" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class OrNode extends AbstractBinaryFormulaNode { + + public OrNode(FormulaNode leftChild, FormulaNode rightChild) { + super(leftChild, rightChild); + } + + @Override + public void print(Appendable a) throws IOException { + printBinaryFormulaNode(a, "||"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/TrueNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/TrueNode.java new file mode 100644 index 0000000000..bd7fa3e4c1 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/TrueNode.java @@ -0,0 +1,44 @@ +/* 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.modelcheckers.m3c.formula; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "true" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class TrueNode extends AbstractFormulaNode { + + @Override + public void print(Appendable a) throws IOException { + a.append("true"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AFNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AFNode.java new file mode 100644 index 0000000000..cdef39d3bb --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AFNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula.ctl; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.AbstractUnaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "AF" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class AFNode extends AbstractUnaryFormulaNode { + + public AFNode(FormulaNode childNode) { + super(childNode); + } + + @Override + public void print(Appendable a) throws IOException { + printUnaryFormulaNode(a, "AF"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AGNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AGNode.java new file mode 100644 index 0000000000..eb5c1b6695 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AGNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula.ctl; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.AbstractUnaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "AG" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class AGNode extends AbstractUnaryFormulaNode { + + public AGNode(FormulaNode node) { + super(node); + } + + @Override + public void print(Appendable a) throws IOException { + printUnaryFormulaNode(a, "AG"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AUNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AUNode.java new file mode 100644 index 0000000000..ed35a2e6af --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AUNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula.ctl; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.AbstractBinaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "AU" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class AUNode extends AbstractBinaryFormulaNode { + + public AUNode(FormulaNode leftChild, FormulaNode rightChild) { + super(leftChild, rightChild); + } + + @Override + public void print(Appendable a) throws IOException { + printUntilNode(a, 'A', 'U'); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AWUNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AWUNode.java new file mode 100644 index 0000000000..f26c98df7f --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/AWUNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula.ctl; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.AbstractBinaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "AWU" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class AWUNode extends AbstractBinaryFormulaNode { + + public AWUNode(FormulaNode leftChild, FormulaNode rightChild) { + super(leftChild, rightChild); + } + + @Override + public void print(Appendable a) throws IOException { + printUntilNode(a, 'A', 'W'); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EFNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EFNode.java new file mode 100644 index 0000000000..e543943005 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EFNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula.ctl; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.AbstractUnaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "EF" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class EFNode extends AbstractUnaryFormulaNode { + + public EFNode(FormulaNode node) { + super(node); + } + + @Override + public void print(Appendable a) throws IOException { + printUnaryFormulaNode(a, "EF"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EGNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EGNode.java new file mode 100644 index 0000000000..4b808f2677 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EGNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula.ctl; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.AbstractUnaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "EG" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class EGNode extends AbstractUnaryFormulaNode { + + public EGNode(FormulaNode node) { + super(node); + } + + @Override + public void print(Appendable a) throws IOException { + printUnaryFormulaNode(a, "EG"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EUNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EUNode.java new file mode 100644 index 0000000000..5595c626b5 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EUNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula.ctl; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.AbstractBinaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "EU" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class EUNode extends AbstractBinaryFormulaNode { + + public EUNode(FormulaNode leftChild, FormulaNode rightChild) { + super(leftChild, rightChild); + } + + @Override + public void print(Appendable a) throws IOException { + printUntilNode(a, 'E', 'U'); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EWUNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EWUNode.java new file mode 100644 index 0000000000..994a4821fe --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/ctl/EWUNode.java @@ -0,0 +1,50 @@ +/* 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.modelcheckers.m3c.formula.ctl; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.AbstractBinaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "EWU" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class EWUNode extends AbstractBinaryFormulaNode { + + public EWUNode(FormulaNode leftChild, FormulaNode rightChild) { + super(leftChild, rightChild); + } + + @Override + public void print(Appendable a) throws IOException { + printUntilNode(a, 'E', 'W'); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/AbstractFixedPointFormulaNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/AbstractFixedPointFormulaNode.java new file mode 100644 index 0000000000..58cc11597f --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/AbstractFixedPointFormulaNode.java @@ -0,0 +1,76 @@ +/* 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.modelcheckers.m3c.formula.modalmu; + +import java.io.IOException; +import java.util.Objects; + +import net.automatalib.modelcheckers.m3c.formula.AbstractUnaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Abstract super-class for fix-point (sub-) formulas. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public abstract class AbstractFixedPointFormulaNode extends AbstractUnaryFormulaNode { + + private final String variable; + + public AbstractFixedPointFormulaNode(String variable, FormulaNode child) { + super(child); + this.variable = variable; + } + + public String getVariable() { + return variable; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(variable); + return result; + } + + @Override + public boolean equals(@Nullable Object o) { + if (!super.equals(o)) { + return false; + } + + final AbstractFixedPointFormulaNode that = (AbstractFixedPointFormulaNode) o; + + return this.variable.equals(that.variable); + } + + protected void printMuCalcNode(Appendable a, String fixedPoint) throws IOException { + a.append('('); + a.append(fixedPoint); + a.append(' '); + a.append(variable); + a.append(".("); + getChild().print(a); + a.append("))"); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/GfpNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/GfpNode.java new file mode 100644 index 0000000000..88e810224f --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/GfpNode.java @@ -0,0 +1,49 @@ +/* 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.modelcheckers.m3c.formula.modalmu; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "nu" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class GfpNode extends AbstractFixedPointFormulaNode { + + public GfpNode(String variable, FormulaNode node) { + super(variable, node); + } + + @Override + public void print(Appendable a) throws IOException { + printMuCalcNode(a, "nu"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/LfpNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/LfpNode.java new file mode 100644 index 0000000000..77a594f2ca --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/LfpNode.java @@ -0,0 +1,49 @@ +/* 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.modelcheckers.m3c.formula.modalmu; + +import java.io.IOException; + +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; + +/** + * Java representation of a "mu" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class LfpNode extends AbstractFixedPointFormulaNode { + + public LfpNode(String variable, FormulaNode node) { + super(variable, node); + } + + @Override + public void print(Appendable a) throws IOException { + printMuCalcNode(a, "mu"); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/VariableNode.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/VariableNode.java new file mode 100644 index 0000000000..476f12d048 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/modalmu/VariableNode.java @@ -0,0 +1,74 @@ +/* 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.modelcheckers.m3c.formula.modalmu; + +import java.io.IOException; +import java.util.Objects; + +import net.automatalib.modelcheckers.m3c.formula.AbstractFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.FormulaNodeVisitor; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Java representation of an "X" (sub-)formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class VariableNode extends AbstractFormulaNode { + + private final String variable; + + public VariableNode(String variable) { + this.variable = variable; + } + + public String getVariable() { + return variable; + } + + @Override + public void print(Appendable a) throws IOException { + a.append(variable); + } + + @Override + public T accept(FormulaNodeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(variable); + return result; + } + + @Override + public boolean equals(@Nullable Object o) { + if (!super.equals(o)) { + return false; + } + + final VariableNode that = (VariableNode) o; + + return this.variable.equals(that.variable); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/parser/M3CParser.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/parser/M3CParser.java new file mode 100644 index 0000000000..b733acdf1b --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/parser/M3CParser.java @@ -0,0 +1,102 @@ +/* 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.modelcheckers.m3c.formula.parser; + +import java.io.StringReader; +import java.util.function.Function; + +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; + +/** + * This class can be used to parse formulas in CTL and the mu-calculus. + * + *
    + *
  • + * CTL grammar: + *
    + * f := true | false | AP | (f) |
    + *      !f | f && f | f || f | f -> f | f <-> f |
    + *      <>f | <ID>f | []f | [ID]f |
    + *      AF f | AG f | A(f U f) | A(f W f) | EF f | EG f | E(f U f) | E(f W f)
    + * 
    + *
  • + *
  • + * mu-calculus grammar: + *
    + * f := true | false | AP | (f) |
    + *      !f | f && f | f || f | f -> f | f <-> f |
    + *      <>f | <ID>f | []f | [ID]f |
    + *      mu ID.(f) | nu ID.(f) | ID
    + * 
    + *
  • + *
+ *
+ * AP := "arbitrary string not containing double quotation marks" | 'arbitrary string not containing single quotation marks'
+ * ID := ["a"-"z","A"-"Z"] (["a"-"z","A"-"Z"] | ["0"-"9"] | "_")*
+ * 
+ */ +public final class M3CParser { + + private M3CParser() { + // prevent initialization + } + + /** + * Returns the abstract syntax tree of a given formula. Each label is transformed to a {@code String}. Each atomic + * proposition is transformed to a {@code String}. + * + * @param formula + * ctl or mu-calculus formula to be parsed + * + * @return {@code formula}'s abstract syntax tree. + * + * @throws ParseException + * if {@code formula} is not a valid formula. + */ + public static FormulaNode parse(String formula) throws ParseException { + return parse(formula, Function.identity(), Function.identity()); + } + + /** + * Returns the abstract syntax tree of a given formula. Each label and atomic proposition is transformed according + * to the given parsers. + * + * @param formula + * ctl or mu-calculus formula to be parsed + * @param labelParser + * parser to transform the labels of the formula + * @param apParser + * parser to transform the atomic propositions of the formula + * @param + * edge label type + * @param + * atomic proposition type + * + * @return {@code formula}'s abstract syntax tree. + * + * @throws ParseException + * if {@code formula} is not a valid formula. + */ + public static FormulaNode parse(String formula, + Function labelParser, + Function apParser) throws ParseException { + try (StringReader reader = new StringReader(formula)) { + final InternalM3CParser parser = new InternalM3CParser<>(reader); + return parser.parse(labelParser, apParser); + } + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/CTLToMuCalc.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/CTLToMuCalc.java new file mode 100644 index 0000000000..27819b3950 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/CTLToMuCalc.java @@ -0,0 +1,222 @@ +/* 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.modelcheckers.m3c.formula.visitor; + +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AFNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AGNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AWUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EFNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EGNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EWUNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.GfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.VariableNode; + +/** + * A visitor that transforms a given CTL formula to an equivalent mu-calculus formula. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class CTLToMuCalc implements FormulaNodeVisitor, L, AP> { + + private int numFixedPointVars; + + public CTLToMuCalc() { + numFixedPointVars = 0; + } + + public FormulaNode toMuCalc(FormulaNode ctlFormula) { + numFixedPointVars = 0; + return visit(ctlFormula); + } + + @Override + public FormulaNode visit(FormulaNode node) { + return node.accept(this); + } + + @Override + public FormulaNode visit(AFNode node) { + /* AF p = mu X.(toMu(p) | (<>true & []X)) */ + FormulaNode p = visit(node.getChild()); + String fixedPointVar = getFixedPointVar(); + DiamondNode hasSuccessor = new DiamondNode<>(new TrueNode<>()); + BoxNode allSuccessorSatisfyX = new BoxNode<>(new VariableNode<>(fixedPointVar)); + AndNode and = new AndNode<>(hasSuccessor, allSuccessorSatisfyX); + OrNode or = new OrNode<>(p, and); + return new LfpNode<>(fixedPointVar, or); + } + + @Override + public FormulaNode visit(AGNode node) { + /* AG p = nu X.(p & []X) */ + FormulaNode p = visit(node.getChild()); + String fixedPointVar = getFixedPointVar(); + BoxNode allSuccessorsSatisfyX = new BoxNode<>(new VariableNode<>(fixedPointVar)); + AndNode and = new AndNode<>(p, allSuccessorsSatisfyX); + return new GfpNode<>(fixedPointVar, and); + } + + @Override + public FormulaNode visit(AUNode node) { + /* A[p U q] = mu X.(toMu(q) | (toMu(p) & (<>true & []X))) */ + FormulaNode p = visit(node.getLeftChild()); + FormulaNode q = visit(node.getRightChild()); + String fixedPointVar = getFixedPointVar(); + DiamondNode hasSuccessor = new DiamondNode<>(new TrueNode<>()); + BoxNode allSuccessorsSatisfyX = new BoxNode<>(new VariableNode<>(fixedPointVar)); + AndNode innerAnd = new AndNode<>(hasSuccessor, allSuccessorsSatisfyX); + AndNode outerAnd = new AndNode<>(p, innerAnd); + OrNode or = new OrNode<>(q, outerAnd); + return new LfpNode<>(fixedPointVar, or); + } + + @Override + public FormulaNode visit(AWUNode node) { + /* A[p WU q] = !E[!q U (!p & !q)] */ + FormulaNode p = visit(node.getLeftChild()); + FormulaNode q = visit(node.getRightChild()); + AndNode and = new AndNode<>(new NotNode<>(p), new NotNode<>(q)); + EUNode ewu = new EUNode<>(new NotNode<>(visit(node.getRightChild())), and); + return visit(new NotNode<>(ewu)); + } + + @Override + public FormulaNode visit(EFNode node) { + /* EF p = mu X.(toMu(p) | <>X) */ + String fixedPointVar = getFixedPointVar(); + FormulaNode p = visit(node.getChild()); + DiamondNode hasSuccessorSatisfyingX = new DiamondNode<>(new VariableNode<>(fixedPointVar)); + OrNode orNode = new OrNode<>(p, hasSuccessorSatisfyingX); + return new LfpNode<>(fixedPointVar, orNode); + } + + @Override + public FormulaNode visit(EGNode node) { + /* EG p = nu X.(toMu(p) & (<>X | [] false)) */ + String fixedPointVar = getFixedPointVar(); + FormulaNode childNode = visit(node.getChild()); + DiamondNode hasSuccessorSatisfyingX = new DiamondNode<>(new VariableNode<>(fixedPointVar)); + BoxNode hasNoSuccessor = new BoxNode<>(new FalseNode<>()); + OrNode or = new OrNode<>(hasSuccessorSatisfyingX, hasNoSuccessor); + AndNode and = new AndNode<>(childNode, or); + return new GfpNode<>(fixedPointVar, and); + } + + @Override + public FormulaNode visit(EUNode node) { + /* E[p U q] => mu X.(toMu(q) | (toMu(p) & <>X)) */ + String fixedPointVar = getFixedPointVar(); + FormulaNode p = visit(node.getLeftChild()); + FormulaNode q = visit(node.getRightChild()); + AndNode andNode = new AndNode<>(p, new DiamondNode<>(new VariableNode<>(fixedPointVar))); + OrNode orNode = new OrNode<>(q, andNode); + return new LfpNode<>(fixedPointVar, orNode); + } + + @Override + public FormulaNode visit(EWUNode node) { + /* E[p WU q] = E[p U q] | EG p */ + FormulaNode p = visit(node.getLeftChild()); + FormulaNode q = visit(node.getRightChild()); + EUNode until = new EUNode<>(p, q); + EGNode egNode = new EGNode<>(visit(node.getLeftChild())); + return visit(new OrNode<>(until, egNode)); + } + + @Override + public FormulaNode visit(AndNode node) { + FormulaNode leftChild = visit(node.getLeftChild()); + FormulaNode rightChild = visit(node.getRightChild()); + return new AndNode<>(leftChild, rightChild); + } + + @Override + public FormulaNode visit(AtomicNode node) { + return new AtomicNode<>(node.getProposition()); + } + + @Override + public FormulaNode visit(BoxNode node) { + FormulaNode childNode = visit(node.getChild()); + return new BoxNode<>(node.getAction(), childNode); + } + + @Override + public FormulaNode visit(DiamondNode node) { + FormulaNode childNode = visit(node.getChild()); + return new DiamondNode<>(node.getAction(), childNode); + } + + @Override + public FormulaNode visit(FalseNode node) { + return new FalseNode<>(); + } + + @Override + public FormulaNode visit(NotNode node) { + FormulaNode childNode = visit(node.getChild()); + return new NotNode<>(childNode); + } + + @Override + public FormulaNode visit(OrNode node) { + FormulaNode leftChild = visit(node.getLeftChild()); + FormulaNode rightChild = visit(node.getRightChild()); + return new OrNode<>(leftChild, rightChild); + } + + @Override + public FormulaNode visit(TrueNode node) { + return new TrueNode<>(); + } + + @Override + public FormulaNode visit(GfpNode node) { + return new GfpNode<>(node.getVariable(), visit(node.getChild())); + } + + @Override + public FormulaNode visit(LfpNode node) { + return new LfpNode<>(node.getVariable(), visit(node.getChild())); + } + + @Override + public FormulaNode visit(VariableNode node) { + return new VariableNode<>(node.getVariable()); + } + + private String getFixedPointVar() { + return "Z" + numFixedPointVars++; + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/FormulaNodeVisitor.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/FormulaNodeVisitor.java new file mode 100644 index 0000000000..d96d50238f --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/FormulaNodeVisitor.java @@ -0,0 +1,82 @@ +/* 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.modelcheckers.m3c.formula.visitor; + +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AFNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AGNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AWUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EFNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EGNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EWUNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.GfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.VariableNode; + +public interface FormulaNodeVisitor { + + T visit(FormulaNode node); + + T visit(AFNode node); + + T visit(AGNode node); + + T visit(AUNode node); + + T visit(AWUNode node); + + T visit(EFNode node); + + T visit(EGNode node); + + T visit(EUNode node); + + T visit(EWUNode node); + + T visit(AndNode node); + + T visit(AtomicNode node); + + T visit(BoxNode node); + + T visit(DiamondNode node); + + T visit(FalseNode node); + + T visit(NotNode node); + + T visit(OrNode node); + + T visit(TrueNode node); + + T visit(GfpNode node); + + T visit(LfpNode node); + + T visit(VariableNode node); + +} + diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/NNFVisitor.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/NNFVisitor.java new file mode 100644 index 0000000000..dc505d1db4 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/formula/visitor/NNFVisitor.java @@ -0,0 +1,159 @@ +/* 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.modelcheckers.m3c.formula.visitor; + +import java.util.HashSet; +import java.util.Set; + +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.GfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.VariableNode; + +/** + * A visitor that transforms a given mu-calculus or CTL formula to negation-normal-form. + * + * @param + * label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class NNFVisitor { + + private Set varsToNegate; + + public FormulaNode transformToNNF(FormulaNode node) { + this.varsToNegate = new HashSet<>(); + return visit(node, false); + } + + private FormulaNode visit(FormulaNode node, boolean negate) { + if (node instanceof GfpNode) { + return visitGFPNode((GfpNode) node, negate); + } else if (node instanceof LfpNode) { + return visitLFPNode((LfpNode) node, negate); + } else if (node instanceof AndNode) { + return visitAndNode((AndNode) node, negate); + } else if (node instanceof AtomicNode) { + return visitAtomicNode((AtomicNode) node, negate); + } else if (node instanceof BoxNode) { + return visitBoxNode((BoxNode) node, negate); + } else if (node instanceof DiamondNode) { + return visitDiamondNode((DiamondNode) node, negate); + } else if (node instanceof FalseNode) { + return visitFalseNode(negate); + } else if (node instanceof VariableNode) { + return visitVariableNode((VariableNode) node, negate); + } else if (node instanceof NotNode) { + return visitNotNode((NotNode) node, negate); + } else if (node instanceof OrNode) { + return visitOrNode((OrNode) node, negate); + } else if (node instanceof TrueNode) { + return visitTrueNode(negate); + } else { + throw new IllegalArgumentException("Node is not a ModalMuNode"); + } + } + + private FormulaNode visitGFPNode(GfpNode node, boolean negate) { + if (!negate) { + FormulaNode childNode = visit(node.getChild(), false); + return new GfpNode<>(node.getVariable(), childNode); + } + + varsToNegate.add(node.getVariable()); + FormulaNode childNode = visit(node.getChild(), true); + varsToNegate.remove(node.getVariable()); + + return new LfpNode<>(node.getVariable(), childNode); + } + + private FormulaNode visitLFPNode(LfpNode node, boolean negate) { + if (!negate) { + FormulaNode childNode = visit(node.getChild(), false); + return new LfpNode<>(node.getVariable(), childNode); + } + + varsToNegate.add(node.getVariable()); + FormulaNode childNode = visit(node.getChild(), true); + varsToNegate.remove(node.getVariable()); + + return new GfpNode<>(node.getVariable(), childNode); + } + + private FormulaNode visitAndNode(AndNode node, boolean negate) { + final FormulaNode leftChild = visit(node.getLeftChild(), negate); + final FormulaNode rightChild = visit(node.getRightChild(), negate); + + return negate ? new OrNode<>(leftChild, rightChild) : new AndNode<>(leftChild, rightChild); + } + + private FormulaNode visitAtomicNode(AtomicNode node, boolean negate) { + final FormulaNode newNode = new AtomicNode<>(node.getProposition()); + return negate ? new NotNode<>(newNode) : newNode; + } + + private FormulaNode visitBoxNode(BoxNode node, boolean negate) { + final FormulaNode childNode = visit(node.getChild(), negate); + final L action = node.getAction(); + + return negate ? new DiamondNode<>(action, childNode) : new BoxNode<>(action, childNode); + } + + private FormulaNode visitDiamondNode(DiamondNode node, boolean negate) { + final FormulaNode childNode = visit(node.getChild(), negate); + final L action = node.getAction(); + + return negate ? new BoxNode<>(action, childNode) : new DiamondNode<>(action, childNode); + } + + private FormulaNode visitFalseNode(boolean negate) { + return negate ? new TrueNode<>() : new FalseNode<>(); + } + + private FormulaNode visitVariableNode(VariableNode node, boolean negate) { + final FormulaNode newNode = new VariableNode<>(node.getVariable()); + boolean negateVariable = negate ^ varsToNegate.contains(node.getVariable()); + + return negateVariable ? new NotNode<>(newNode) : newNode; + } + + private FormulaNode visitNotNode(NotNode node, boolean negate) { + return visit(node.getChild(), !negate); + } + + private FormulaNode visitOrNode(OrNode node, boolean negate) { + final FormulaNode leftChild = visit(node.getLeftChild(), negate); + final FormulaNode rightChild = visit(node.getRightChild(), negate); + + return negate ? new AndNode<>(leftChild, rightChild) : new OrNode<>(leftChild, rightChild); + } + + private FormulaNode visitTrueNode(boolean negate) { + return negate ? new FalseNode<>() : new TrueNode<>(); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/package-info.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/package-info.java new file mode 100644 index 0000000000..cde53a71f3 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/package-info.java @@ -0,0 +1,26 @@ +/* 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. + */ + +/** + * This package provides the implementation of the model-checker presented in the paper
M3C: Modal Meta Model Checking by Bernhard Steffen and + * Alnis Murtovi. The paper is based on Model Checking + * for Context-Free Processes by Olaf Burkart and Bernhard Steffen. + * + * @author frohme + * @author murtovi + */ +package net.automatalib.modelcheckers.m3c; \ No newline at end of file diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/ADDSolver.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/ADDSolver.java new file mode 100644 index 0000000000..6d3a7b0f8e --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/ADDSolver.java @@ -0,0 +1,77 @@ +/* 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.modelcheckers.m3c.solver; + +import info.scce.addlib.dd.xdd.XDDManager; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVector; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVectorLogicDDManager; +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.DependencyGraph; +import net.automatalib.modelcheckers.m3c.transformer.ADDTransformer; +import net.automatalib.modelcheckers.m3c.transformer.ADDTransformerSerializer; +import net.automatalib.modelcheckers.m3c.transformer.TransformerSerializer; +import net.automatalib.ts.modal.transition.ModalEdgeProperty; + +/** + * Implementation based on property transformers being represented by ADDs (Algebraic Decision Diagrams). + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class ADDSolver extends AbstractDDSolver, L, AP> { + + private XDDManager ddManager; + + public ADDSolver(ContextFreeModalProcessSystem cfmps) { + super(cfmps); + } + + @Override + protected void initDDManager(DependencyGraph dependencyGraph) { + this.ddManager = new BooleanVectorLogicDDManager(dependencyGraph.getNumVariables()); + } + + @Override + protected ADDTransformer createInitTransformerEndNode(DependencyGraph dependencyGraph) { + return new ADDTransformer<>(ddManager); + } + + @Override + protected ADDTransformer createInitTransformerNode(DependencyGraph dependencyGraph) { + return new ADDTransformer<>(ddManager, dependencyGraph); + } + + @Override + protected ADDTransformer createInitTransformerEdge(DependencyGraph dependencyGraph, + L edgeLabel, + TP edgeProperty) { + return new ADDTransformer<>(ddManager, edgeLabel, edgeProperty, dependencyGraph); + } + + @Override + protected void shutdownDDManager() { + this.ddManager.quit(); + } + + @Override + protected TransformerSerializer, L, AP> getSerializer() { + return new ADDTransformerSerializer<>(ddManager); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/AbstractDDSolver.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/AbstractDDSolver.java new file mode 100644 index 0000000000..ebd6540dea --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/AbstractDDSolver.java @@ -0,0 +1,557 @@ +/* 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.modelcheckers.m3c.solver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.commons.util.mappings.MutableMapping; +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.graphs.ProceduralModalProcessGraph; +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DependencyGraph; +import net.automatalib.modelcheckers.m3c.formula.EquationalBlock; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.visitor.CTLToMuCalc; +import net.automatalib.modelcheckers.m3c.transformer.AbstractPropertyTransformer; +import net.automatalib.modelcheckers.m3c.transformer.TransformerSerializer; +import net.automatalib.ts.modal.transition.ModalEdgeProperty; +import net.automatalib.ts.modal.transition.ProceduralModalEdgeProperty; +import org.checkerframework.checker.initialization.qual.UnderInitialization; +import org.checkerframework.checker.nullness.qual.KeyFor; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Base implementation of the model checker which supports different types of property transformers. + * + * @param + * property transformer type + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +abstract class AbstractDDSolver, L, AP> { + + // Attributes that are constant for a given CFMPS + private final @KeyFor("workUnits") L mainProcess; + + // Attributes that change for each formula + private TransformerSerializer serializer; + private DependencyGraph dependencyGraph; + private int currentBlockIndex; + // Per-procedure attributes + private final Map> workUnits; + // Per-action attributes + private Map mustTransformers; + private Map mayTransformers; + + AbstractDDSolver(ContextFreeModalProcessSystem cfmps) { + final Map> pmpgs = cfmps.getPMPGs(); + + this.workUnits = Maps.newHashMapWithExpectedSize(pmpgs.size()); + for (Map.Entry> e : pmpgs.entrySet()) { + final L label = e.getKey(); + final ProceduralModalProcessGraph pmpg = e.getValue(); + + Preconditions.checkNotNull(pmpg.getInitialNode(), "PMPG '%s' has no start node", label); + Preconditions.checkNotNull(pmpg.getFinalNode(), "PMPG '%s' has no end node", label); + + workUnits.put(label, initializeWorkUnits(label, pmpg)); + } + + // TODO handle empty CFMPSs + final L mainProcess = cfmps.getMainProcess(); + if (mainProcess == null || !workUnits.containsKey(mainProcess)) { + throw new IllegalArgumentException("The main process is undefined or has no corresponding MPG."); + } + + this.mainProcess = mainProcess; + } + + private WorkUnit initializeWorkUnits(@UnderInitialization AbstractDDSolver this, + L label, + ProceduralModalProcessGraph pmpg) { + return new WorkUnit<>(label, pmpg, initPredecessorsMapping(pmpg)); + } + + private static Mapping> initPredecessorsMapping(ProceduralModalProcessGraph pmpg) { + + final MutableMapping> nodeToPredecessors = pmpg.createStaticNodeMapping(); + + for (N sourceNode : pmpg.getNodes()) { + for (E outgoingEdge : pmpg.getOutgoingEdges(sourceNode)) { + final N targetNode = pmpg.getTarget(outgoingEdge); + Set nodePredecessors = nodeToPredecessors.get(targetNode); + + if (nodePredecessors == null) { + nodePredecessors = new HashSet<>(); + nodeToPredecessors.put(targetNode, nodePredecessors); + } + + nodePredecessors.add(sourceNode); + } + } + + return nodeToPredecessors; + } + + public boolean solve(FormulaNode formula) { + final FormulaNode ast = ctlToMuCalc(formula).toNNF(); + + initialize(ast); + this.solveInternal(false, Collections.emptyList()); + + final boolean sat = isSat(); + shutdownDDManager(); + return sat; + } + + public SolverHistory solveAndRecordHistory(FormulaNode formula) { + final List> history = new ArrayList<>(); + final FormulaNode ast = ctlToMuCalc(formula).toNNF(); + + initialize(ast); + + final Map> data = Maps.newHashMapWithExpectedSize(this.workUnits.size()); + for (Entry> e : this.workUnits.entrySet()) { + data.put(e.getKey(), createProcessData(e.getValue())); + } + + this.solveInternal(true, history); + + final Map> serializedMustTransformers = serializePropertyTransformerMap(mustTransformers); + final Map> serializedMayTransformers = serializePropertyTransformerMap(mayTransformers); + final boolean isSat = isSat(); + + shutdownDDManager(); + + return new SolverHistory<>(data, serializedMustTransformers, serializedMayTransformers, history, isSat); + } + + private SolverData createProcessData(WorkUnit unit) { + return new SolverData<>(unit.pmpg, serializePropertyTransformers(unit), computeSatisfiedSubformulas(unit)); + } + + private Map> serializePropertyTransformerMap(Map transformers) { + final Map> serializedTransformers = Maps.newHashMapWithExpectedSize(transformers.size()); + for (Map.Entry entry : transformers.entrySet()) { + serializedTransformers.put(entry.getKey(), serializer.serialize(entry.getValue())); + } + return serializedTransformers; + } + + private void solveInternal(boolean recordHistory, List> history) { + boolean workSetIsEmpty = false; + while (!workSetIsEmpty) { + workSetIsEmpty = true; + for (Entry> entry : workUnits.entrySet()) { + workSetIsEmpty &= solveInternal(entry.getValue(), recordHistory, history); + } + } + } + + private boolean solveInternal(WorkUnit unit, + boolean recordHistory, + List> history) { + if (!unit.workSet.isEmpty()) { + final Iterator iter = unit.workSet.iterator(); + final N node = iter.next(); + iter.remove(); + + final L label = unit.label; + final List compositions = updateNodeAndGetCompositions(unit, node); + + if (recordHistory) { + final List> serializedCompositions = new ArrayList<>(compositions.size()); + for (T composition : compositions) { + serializedCompositions.add(serializer.serialize(composition)); + } + history.add(new SolverState<>(serializer.serialize(unit.propTransformers.get(node)), + serializedCompositions, + node, + label, + copyWorkSet(), + getSatisfiedSubformulas(unit, node))); + } + + return false; + } + + return true; + } + + private List updateNodeAndGetCompositions(WorkUnit unit, N node) { + initUpdate(unit, node); + final T nodeTransformer = getTransformer(unit, node); + final List compositions = createCompositions(unit, node); + final T updatedTransformer = getUpdatedPropertyTransformer(unit, node, nodeTransformer, compositions); + updateTransformerAndWorkSet(unit, node, nodeTransformer, updatedTransformer); + return compositions; + } + + private Map> copyWorkSet() { + final Map> copy = Maps.newHashMapWithExpectedSize(workUnits.size()); + for (Map.Entry> e : workUnits.entrySet()) { + copy.put(e.getKey(), copyWorkSet(e.getValue())); + } + return copy; + } + + private Set copyWorkSet(WorkUnit unit) { + return new HashSet<>(unit.workSet); + } + + private Mapping>> computeSatisfiedSubformulas(WorkUnit unit) { + final MutableMapping>> result = unit.pmpg.createStaticNodeMapping(); + for (N node : unit.pmpg.getNodes()) { + result.put(node, getSatisfiedSubformulas(unit, node)); + } + + // we put a transformer for every node, so it's no longer null + return (MutableMapping>>) result; + } + + private List> getSatisfiedSubformulas(WorkUnit unit, N node) { + final Set output = unit.propTransformers.get(node).evaluate(toBoolArray(getAllAPDeadlockedNode())); + final List> satisfiedSubFormulas = new ArrayList<>(); + for (FormulaNode n : dependencyGraph.getFormulaNodes()) { + if (output.contains(n.getVarNumber())) { + satisfiedSubFormulas.add(n); + } + } + return satisfiedSubFormulas; + } + + private boolean[] toBoolArray(Set satisfiedVars) { + final boolean[] arr = new boolean[dependencyGraph.getNumVariables()]; + for (Integer satisfiedVar : satisfiedVars) { + arr[satisfiedVar] = true; + } + return arr; + } + + private Set getAllAPDeadlockedNode() { + return getAllAPDeadlockedNode(workUnits.get(mainProcess).pmpg); + } + + private Set getAllAPDeadlockedNode( + ProceduralModalProcessGraph mainMpg) { + final Set satisfiedVariables = new HashSet<>(); + @SuppressWarnings("nullness") // we have checked non-nullness of final nodes in the constructor + final @NonNull N finalNode = mainMpg.getFinalNode(); + for (int blockIdx = dependencyGraph.getBlocks().size() - 1; blockIdx >= 0; blockIdx--) { + final EquationalBlock block = dependencyGraph.getBlock(blockIdx); + for (FormulaNode node : block.getNodes()) { + if (node instanceof TrueNode) { + satisfiedVariables.add(node.getVarNumber()); + } else if (node instanceof AtomicNode) { + final AP atomicProposition = ((AtomicNode) node).getProposition(); + final Set finalNodeAPs = mainMpg.getAtomicPropositions(finalNode); + if (finalNodeAPs.contains(atomicProposition)) { + satisfiedVariables.add(node.getVarNumber()); + } + } else if (node instanceof BoxNode) { + /* End node has no outgoing edges */ + satisfiedVariables.add(node.getVarNumber()); + } else if (node instanceof AndNode) { + final AndNode andNode = (AndNode) node; + if (satisfiedVariables.contains(andNode.getVarNumberLeft()) && + satisfiedVariables.contains(andNode.getVarNumberRight())) { + satisfiedVariables.add(andNode.getVarNumber()); + } + } else if (node instanceof OrNode) { + final OrNode orNode = (OrNode) node; + if (satisfiedVariables.contains(orNode.getVarNumberLeft()) || + satisfiedVariables.contains(orNode.getVarNumberRight())) { + satisfiedVariables.add(orNode.getVarNumber()); + } + } else if (node instanceof NotNode) { + final NotNode notNode = (NotNode) node; + if (!satisfiedVariables.contains(notNode.getVarNumberChild())) { + satisfiedVariables.add(notNode.getVarNumber()); + } + } + } + } + return satisfiedVariables; + } + + private void initUpdate(WorkUnit unit, N node) { + assert !Objects.equals(node, unit.pmpg.getFinalNode()) : "End node must not be updated!"; + unit.workSet.remove(node); + } + + private T getTransformer(WorkUnit unit, N node) { + return unit.propTransformers.get(node); + } + + private List createCompositions(WorkUnit unit, N node) { + final ProceduralModalProcessGraph pmpg = unit.pmpg; + final List compositions = new ArrayList<>(); + for (E edge : pmpg.getOutgoingEdges(node)) { + final N targetNode = pmpg.getTarget(edge); + final T edgeTransformer = getEdgeTransformer(unit, edge); + final T succTransformer = getTransformer(unit, targetNode); + final T composition = edgeTransformer.compose(succTransformer); + compositions.add(composition); + } + return compositions; + } + + private T getUpdatedPropertyTransformer(WorkUnit unit, N node, T nodeTransformer, List compositions) { + final EquationalBlock currentBlock = dependencyGraph.getBlock(currentBlockIndex); + final Set atomicPropositions = unit.pmpg.getAtomicPropositions(node); + return nodeTransformer.createUpdate(atomicPropositions, compositions, currentBlock); + } + + private void updateTransformerAndWorkSet(WorkUnit unit, + N node, + T nodeTransformer, + T updatedTransformer) { + if (!nodeTransformer.equals(updatedTransformer)) { + unit.propTransformers.put(node, updatedTransformer); + updateWorkSet(unit, node); + } + if (workSetIsEmpty() && currentBlockIndex > 0) { + currentBlockIndex--; + resetWorkSet(); + } + } + + private T getEdgeTransformer(WorkUnit unit, E edge) { + final T edgeTransformer; + final ProceduralModalProcessGraph pmpg = unit.pmpg; + final L label = pmpg.getEdgeLabel(edge); + if (isProcessEdge(pmpg, edge)) { + final WorkUnit edgeUnit = workUnits.get(label); + assert edgeUnit != null; + edgeTransformer = getInitialEdgeTransformer(edgeUnit); + } else { + if (isMustEdge(pmpg, edge)) { + if (mustTransformers.containsKey(label)) { + edgeTransformer = mustTransformers.get(label); + } else { + edgeTransformer = createInitTransformerEdge(dependencyGraph, label, pmpg.getEdgeProperty(edge)); + mustTransformers.put(label, edgeTransformer); + } + } else { + if (mayTransformers.containsKey(label)) { + edgeTransformer = mayTransformers.get(label); + } else { + edgeTransformer = createInitTransformerEdge(dependencyGraph, label, pmpg.getEdgeProperty(edge)); + mayTransformers.put(label, edgeTransformer); + } + } + } + return edgeTransformer; + } + + private boolean isMustEdge(ProceduralModalProcessGraph pmpg, E edge) { + return pmpg.getEdgeProperty(edge).isMust(); + } + + private void updateWorkSet(WorkUnit unit, N node) { + if (Objects.equals(unit.pmpg.getInitialNode(), node)) { + updateWorkSetStartNode(unit.label); + } + addPredecessorsToWorkSet(unit, node); + } + + private boolean workSetIsEmpty() { + for (WorkUnit unit : workUnits.values()) { + if (!unit.workSet.isEmpty()) { + return false; + } + } + return true; + } + + private void resetWorkSet() { + for (WorkUnit value : this.workUnits.values()) { + resetWorkSet(value); + } + } + + private void resetWorkSet(WorkUnit unit) { + unit.workSet = newWorkSet(unit.pmpg); + } + + private boolean isProcessEdge(ProceduralModalProcessGraph pmpg, E edge) { + return pmpg.getEdgeProperty(edge).isProcess(); + } + + private T getInitialEdgeTransformer(WorkUnit unit) { + @SuppressWarnings("nullness") // we have checked non-nullness of initial nodes in the constructor + final @NonNull N initialNode = unit.pmpg.getInitialNode(); + return unit.propTransformers.get(initialNode); + } + + private void updateWorkSetStartNode(L label) { + for (WorkUnit unit : workUnits.values()) { + updateWorkSetStartNode(unit, label); + } + } + + private void updateWorkSetStartNode(WorkUnit unit, L labelOfUpdatedProcess) { + final ProceduralModalProcessGraph pmpg = unit.pmpg; + for (N node : pmpg) { + for (E outgoingEdge : pmpg.getOutgoingEdges(node)) { + if (Objects.equals(pmpg.getEdgeLabel(outgoingEdge), labelOfUpdatedProcess)) { + addToWorkSet(unit, node); + } + } + } + } + + private void addPredecessorsToWorkSet(WorkUnit unit, N node) { + final Set preds = unit.predecessors.get(node); + if (preds != null) { + for (N pred : preds) { + addToWorkSet(unit, pred); + } + } + } + + private void addToWorkSet(WorkUnit unit, N node) { + unit.workSet.add(node); + } + + private Set newWorkSet(ProceduralModalProcessGraph pmpg) { + // Add all nodes to work set except final node, which is never updated + final Set workset = new HashSet<>(pmpg.getNodes()); + workset.remove(pmpg.getFinalNode()); + + return workset; + } + + private FormulaNode ctlToMuCalc(FormulaNode ctlFormula) { + CTLToMuCalc transformation = new CTLToMuCalc<>(); + return transformation.toMuCalc(ctlFormula); + } + + private Mapping> serializePropertyTransformers(WorkUnit unit) { + final MutableMapping> result = unit.pmpg.createStaticNodeMapping(); + for (N node : unit.pmpg.getNodes()) { + result.put(node, serializer.serialize(unit.propTransformers.get(node))); + } + // we put a transformer for every node, so it's no longer null + return (MutableMapping>) result; + } + + private void initialize(FormulaNode ast) { + this.dependencyGraph = new DependencyGraph<>(ast); + this.currentBlockIndex = dependencyGraph.getBlocks().size() - 1; + + initDDManager(this.dependencyGraph); + + this.serializer = getSerializer(); + this.mustTransformers = new HashMap<>(); + this.mayTransformers = new HashMap<>(); + + for (WorkUnit unit : workUnits.values()) { + initialize(unit); + } + } + + private void initialize(WorkUnit unit) { + unit.workSet = newWorkSet(unit.pmpg); + unit.propTransformers = initTransformers(unit.pmpg); + } + + private MutableMapping initTransformers(ProceduralModalProcessGraph pmpg) { + final MutableMapping transformers = pmpg.createStaticNodeMapping(); + final N finalNode = pmpg.getFinalNode(); + + for (N n : pmpg) { + if (Objects.equals(n, finalNode)) { + transformers.put(n, createInitTransformerEndNode(dependencyGraph)); + } else { + transformers.put(n, createInitTransformerNode(dependencyGraph)); + } + } + return (MutableMapping) transformers; // we put a transformer for every node, so it's no longer null + } + + private boolean isSat() { + return isSat(workUnits.get(mainProcess)); + } + + private boolean isSat(WorkUnit unit) { + @SuppressWarnings("nullness") // we have checked non-nullness of initial nodes in the constructor + final @NonNull N initialNode = unit.pmpg.getInitialNode(); + return isSat(unit, initialNode); + } + + private boolean isSat(WorkUnit unit, N initialNode) { + final List> satisfiedFormulas = getSatisfiedSubformulas(unit, initialNode); + for (FormulaNode node : satisfiedFormulas) { + if (node.getVarNumber() == 0) { + return true; + } + } + return false; + } + + protected abstract void initDDManager(DependencyGraph dependencyGraph); + + protected abstract T createInitTransformerEdge(DependencyGraph dependencyGraph, + L edgeLabel, + TP edgeProperty); + + protected abstract T createInitTransformerEndNode(DependencyGraph dependencyGraph); + + protected abstract T createInitTransformerNode(DependencyGraph dependencyGraph); + + protected abstract void shutdownDDManager(); + + protected abstract TransformerSerializer getSerializer(); + + private class WorkUnit { + + private final L label; + private final ProceduralModalProcessGraph pmpg; + private final Mapping> predecessors; + private MutableMapping propTransformers; + private Set workSet; // Keeps track of which node's property transformers have to be updated. + + WorkUnit(L label, ProceduralModalProcessGraph pmpg, Mapping> predecessors) { + this.label = label; + this.pmpg = pmpg; + this.predecessors = predecessors; + } + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/BDDSolver.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/BDDSolver.java new file mode 100644 index 0000000000..3350249756 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/BDDSolver.java @@ -0,0 +1,75 @@ +/* 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.modelcheckers.m3c.solver; + +import info.scce.addlib.dd.bdd.BDDManager; +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.DependencyGraph; +import net.automatalib.modelcheckers.m3c.transformer.BDDTransformer; +import net.automatalib.modelcheckers.m3c.transformer.BDDTransformerSerializer; +import net.automatalib.modelcheckers.m3c.transformer.TransformerSerializer; +import net.automatalib.ts.modal.transition.ModalEdgeProperty; + +/** + * Implementation based on property transformers being represented by BDDs (Binary Decision Diagrams). + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class BDDSolver extends AbstractDDSolver, L, AP> { + + private BDDManager bddManager; + + public BDDSolver(ContextFreeModalProcessSystem cfmps) { + super(cfmps); + } + + @Override + protected void initDDManager(DependencyGraph dependencyGraph) { + this.bddManager = new BDDManager(); + } + + @Override + protected BDDTransformer createInitTransformerEndNode(DependencyGraph dependencyGraph) { + return new BDDTransformer<>(bddManager, dependencyGraph.getNumVariables()); + } + + @Override + protected BDDTransformer createInitTransformerNode(DependencyGraph dependencyGraph) { + return new BDDTransformer<>(bddManager, dependencyGraph); + } + + @Override + protected BDDTransformer createInitTransformerEdge(DependencyGraph dependencyGraph, + L edgeLabel, + TP edgeProperty) { + return new BDDTransformer<>(bddManager, edgeLabel, edgeProperty, dependencyGraph); + } + + @Override + protected void shutdownDDManager() { + this.bddManager.quit(); + } + + @Override + protected TransformerSerializer, L, AP> getSerializer() { + return new BDDTransformerSerializer<>(this.bddManager); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/M3CSolver.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/M3CSolver.java new file mode 100644 index 0000000000..1a3b8c9e19 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/M3CSolver.java @@ -0,0 +1,66 @@ +/* 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.modelcheckers.m3c.solver; + +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; + +/** + * An interface for a generic M3C solver which may need to parse the given formula and thus may throw an exception when + * doing so. + * + * @param + * formula type + * + * @author frohme + */ +public interface M3CSolver { + + /** + * Checks whether the given formula is satisfied. + * + * @param formula + * the formula whose satisfiability should be checked + * + * @return {@code true} if the formula is satisfied, {@code false} otherwise. + * + * @throws ParseException + * when the given formula object cannot be parsed + */ + boolean solve(F formula) throws ParseException; + + /** + * A specialized {@link M3CSolver} which no longer throws a {@link ParseException} when solving a formula, but + * requires an type-safe formula object. + * + * @param + * formula type + * + * @author frohme + */ + interface TypedM3CSolver extends M3CSolver { + + /** + * Checks whether the given formula is satisfied. + * + * @param formula + * the formula whose satisfiability should be checked + * + * @return {@code true} if the formula is satisfied, {@code false} otherwise. + */ + @Override + boolean solve(F formula); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/M3CSolvers.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/M3CSolvers.java new file mode 100644 index 0000000000..fe4f44136f --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/M3CSolvers.java @@ -0,0 +1,110 @@ +/* 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.modelcheckers.m3c.solver; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.solver.M3CSolver.TypedM3CSolver; + +/** + * A factory for constructing {@link M3CSolver}s depending on the given {@link ContextFreeModalProcessSystem}. + * + * @author frohme + */ +public final class M3CSolvers { + + private M3CSolvers() { + // prevent instantiation + } + + /** + * Returns a default {@link M3CSolver} solver for string-based modal context-free process systems. This method + * currently delegates solver construction to {@link #bddSolver(ContextFreeModalProcessSystem)}. + * + * @param cfmps + * the system to evaluate formulas on + * + * @return a default {@link M3CSolver} solver for string-based modal context-free process systems + * + * @see #bddSolver(ContextFreeModalProcessSystem) + */ + public static M3CSolver solver(ContextFreeModalProcessSystem cfmps) { + return bddSolver(cfmps); + } + + /** + * Returns a default {@link TypedM3CSolver} solver for strongly-typed modal context-free process systems. This + * method currently delegates solver construction to {@link #typedBDDSolver(ContextFreeModalProcessSystem)}. + * + * @param cfmps + * the system to evaluate formulas on + * + * @return a default {@link TypedM3CSolver} solver for strongly-typed modal context-free process systems + * + * @see #typedBDDSolver(ContextFreeModalProcessSystem) + */ + public static TypedM3CSolver> typedSolver(ContextFreeModalProcessSystem cfmps) { + return typedBDDSolver(cfmps); + } + + /** + * Returns an ADD-backed {@link M3CSolver} solver for string-based modal context-free process systems. + * + * @param cfmps + * the system to evaluate formulas on + * + * @return an ADD-backed {@link M3CSolver} solver for string-based modal context-free process systems + */ + public static M3CSolver addSolver(ContextFreeModalProcessSystem cfmps) { + return new StringADDSolver(cfmps); + } + + /** + * Returns an ADD-backed {@link TypedM3CSolver} solver for strongly-typed modal context-free process systems. + * + * @param cfmps + * the system to evaluate formulas on + * + * @return an ADD-backed {@link TypedM3CSolver} solver for strongly-typed modal context-free process systems + */ + public static TypedM3CSolver> typedADDSolver(ContextFreeModalProcessSystem cfmps) { + return new TypedADDSolver<>(cfmps); + } + + /** + * Returns a BDD-backed {@link M3CSolver} solver for string-based {@link ContextFreeModalProcessSystem}. + * + * @param cfmps + * the system to evaluate formulas on + * + * @return an ADD-backed {@link M3CSolver} for string-based systems + */ + public static M3CSolver bddSolver(ContextFreeModalProcessSystem cfmps) { + return new StringBDDSolver(cfmps); + } + + /** + * Returns a BDD-backed {@link TypedM3CSolver} solver for strongly-typed {@link ContextFreeModalProcessSystem}. + * + * @param cfmps + * the system to evaluate formulas on + * + * @return a BDD-backed {@link TypedM3CSolver} for strongly-typed systems + */ + public static TypedM3CSolver> typedBDDSolver(ContextFreeModalProcessSystem cfmps) { + return new TypedBDDSolver<>(cfmps); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverData.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverData.java new file mode 100644 index 0000000000..3dc92c3432 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverData.java @@ -0,0 +1,108 @@ +/* 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.modelcheckers.m3c.solver; + +import java.util.List; +import java.util.Map; + +import com.google.common.collect.Maps; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.commons.util.mappings.Mappings; +import net.automatalib.graphs.ProceduralModalProcessGraph; +import net.automatalib.graphs.concepts.NodeIDs; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.transformer.AbstractPropertyTransformer; +import net.automatalib.modelcheckers.m3c.transformer.TransformerSerializer; + +/** + * A class used to store {@link ProceduralModalProcessGraph}-specific data for the {@link SolverHistory}. + * + * @param + * node type + * @param + * property transformer type + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public final class SolverData, L, AP> { + + private final ProceduralModalProcessGraph pmpg; + private final NodeIDs nodeIDs; + private final Mapping> initialPropertyTransformers; + private final Mapping>> initialSatisfiedSubformulas; + + SolverData(ProceduralModalProcessGraph pmpg, + Mapping> initialPropertyTransformers, + Mapping>> initialSatisfiedSubformulas) { + this.pmpg = pmpg; + this.nodeIDs = pmpg.nodeIDs(); + this.initialPropertyTransformers = initialPropertyTransformers; + this.initialSatisfiedSubformulas = initialSatisfiedSubformulas; + } + + /** + * Returns the {@link ProceduralModalProcessGraph} whose data is stored in an instance of this class. + * + * @return the {@link ProceduralModalProcessGraph} whose data is stored in an instance of this class + */ + public ProceduralModalProcessGraph getPmpg() { + return pmpg; + } + + /** + * Returns the {@link NodeIDs} of the {@link ProceduralModalProcessGraph} returned by {@link #getPmpg()}. The + * nodeIDs have already been computed and cached. + * + * @return the nodeIDs + */ + public NodeIDs getNodeIDs() { + return nodeIDs; + } + + /** + * Returns a {@link Mapping} which maps nodes to their initial property transformer. This methods requires a {@link + * TransformerSerializer} as all property transform are stored as {@link String}s in this class. The returned map is + * not cached and will be re-computed on each call. + * + * @param serializer + * used to deserialize each property transformer from a {@link String}. + * + * @return a {@link Mapping} which maps nodes to their initial property transformer + */ + public Mapping getInitialPropertyTransformers(TransformerSerializer serializer) { + final Map result = Maps.newHashMapWithExpectedSize(this.pmpg.size()); + + for (N n : this.pmpg) { + result.put(n, serializer.deserialize(this.initialPropertyTransformers.get(n))); + } + + return Mappings.fromMap(result); + } + + /** + * Returns a {@link Mapping} which contains the list of the initial satisfied subformulas for each node of the + * {@link ProceduralModalProcessGraph} whose data is stored in an instance of this class. + * + * @return a {@link Mapping} which contains the list of the initial satisfied subformulas + */ + public Mapping>> getInitialSatisfiedSubformulas() { + return initialSatisfiedSubformulas; + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverHistory.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverHistory.java new file mode 100644 index 0000000000..261cc69773 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverHistory.java @@ -0,0 +1,126 @@ +/* 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.modelcheckers.m3c.solver; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.google.common.collect.Maps; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.transformer.AbstractPropertyTransformer; +import net.automatalib.modelcheckers.m3c.transformer.TransformerSerializer; + +/** + * A class used to store internal information produced by {@link AbstractDDSolver#solveAndRecordHistory} while checking + * the satisfiability of a formula. The internal information can be used for debugging or visualization purposes. + * + * @param + * property transformer type + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public final class SolverHistory, L, AP> { + + private final Map> data; + private final Map> mustTransformers; + private final Map> mayTransformers; + private final List> solverStates; + private final boolean isSat; + + SolverHistory(Map> data, + Map> mustTransformers, + Map> mayTransformers, + List> solverStates, + boolean isSat) { + this.data = data; + this.mustTransformers = mustTransformers; + this.mayTransformers = mayTransformers; + this.solverStates = solverStates; + this.isSat = isSat; + } + + /** + * Returns a {@link Map} containing information per procedure name. + * + * @return a {@link Map} containing information per procedure name + */ + public Map> getData() { + return data; + } + + /** + * Returns a {@link Map} which maps the edge label of must edges to their property transformer. This method requires + * a {@link TransformerSerializer} as all property transform are stored as {@link String}s in this class. The + * returned map is not cached and will be computed on each call. The property transformer of an edge is initialized + * once and will not be modified which is why this map is only stored once and not in each {@link SolverState}. + * + * @param serializer + * used to deserialize each property transformer from a {@link String} + * + * @return a {@link Map} which maps the edge label of must edges to their property transformer + */ + public Map getMustTransformers(TransformerSerializer serializer) { + return transform(this.mustTransformers, serializer); + } + + /** + * Returns a {@link Map} which maps the edge label of may edges to their property transformer. This method requires + * a {@link TransformerSerializer} as all property transform are stored as {@link String}s in this class. The + * returned map is not cached and will be computed on each call. The property transformer of an edge is initialized + * once and will not be modified which is why this map is only stored once and not in each {@link SolverState}. + * + * @param serializer + * used to deserialize each property transformer from a {@link String} + * + * @return a {@link Map} which maps the edge label of may edges to their property transformer + */ + public Map getMayTransformers(TransformerSerializer serializer) { + return transform(this.mayTransformers, serializer); + } + + /** + * Returns the list of {@link SolverState}s, one per update of a node. + * + * @return the list of {@link SolverState}s + */ + public List> getSolverStates() { + return solverStates; + } + + /** + * Returns whether the formula put into {@link AbstractDDSolver#solveAndRecordHistory(FormulaNode)} is satisfied. + * + * @return {@code true} if formula is satisfied, {@code false} otherwise + */ + public boolean isSat() { + return isSat; + } + + private Map transform(Map> input, TransformerSerializer serializer) { + final Map result = Maps.newHashMapWithExpectedSize(input.size()); + + for (Entry> e : input.entrySet()) { + result.put(e.getKey(), serializer.deserialize(e.getValue())); + } + + return result; + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverState.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverState.java new file mode 100644 index 0000000000..3aedcb5aed --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/SolverState.java @@ -0,0 +1,137 @@ +/* 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.modelcheckers.m3c.solver; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.automatalib.graphs.ProceduralModalProcessGraph; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.transformer.AbstractPropertyTransformer; +import net.automatalib.modelcheckers.m3c.transformer.TransformerSerializer; + +/** + * Stores internal information produced during the update of a node in {@link AbstractDDSolver}. + * + * @param + * node type + * @param + * property transformer type + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public final class SolverState, L, AP> { + + private final List updatedPropTransformer; + private final List> compositions; + private final List> updatedNodeSatisfiedSubformula; + private final N updatedNode; + private final L updatedNodePMPG; + private final Map> workSet; + + SolverState(List updatedPropTransformer, + List> compositions, + N updatedNode, + L updatedNodePMPG, + Map> workSet, + List> updatedNodeSatisfiedSubformula) { + this.updatedPropTransformer = updatedPropTransformer; + this.compositions = compositions; + this.updatedNode = updatedNode; + this.updatedNodePMPG = updatedNodePMPG; + this.workSet = workSet; + this.updatedNodeSatisfiedSubformula = updatedNodeSatisfiedSubformula; + } + + /** + * Returns the updated property transformer. This method requires a {@link TransformerSerializer} as all property + * transform are stored as {@link String}s in this class. + * + * @param serializer + * used to deserialize a property transformer from a {@link String}. + * + * @return the updated property transformer + */ + public T getUpdatedPropTransformer(TransformerSerializer serializer) { + return serializer.deserialize(this.updatedPropTransformer); + } + + /** + * Returns a {@link List} of the property transformers representing the compositions of the property transformer of + * the outgoing edges and their target nodes. This method requires a {@link TransformerSerializer} as all property + * transform are stored as {@link String}s in this class. + * + * @param serializer + * used to deserialize a property transformer from a {@link String}. + * + * @return the property transformers representing the compositions of the property transformer of the outgoing edges + * and their target nodes. + */ + public List getCompositions(TransformerSerializer serializer) { + final List result = new ArrayList<>(this.compositions.size()); + + for (List c : this.compositions) { + result.add(serializer.deserialize(c)); + } + + return result; + } + + /** + * Returns the list of satisfied subformulas the node updated in this step satisfies after the update. + * + * @return the list of satisfied subformulas + */ + public List> getUpdatedNodeSatisfiedSubformula() { + return updatedNodeSatisfiedSubformula; + } + + /** + * Returns the node updated in this step. + * + * @return the node updated in this step + */ + public N getUpdatedNode() { + return updatedNode; + } + + /** + * Returns the name of the {@link ProceduralModalProcessGraph} which contains the node updated in this step. + * + * @return the name of the {@link ProceduralModalProcessGraph} which contains the node updated in this step + */ + public L getUpdatedNodePMPG() { + return updatedNodePMPG; + } + + /** + * Returns a {@link Map} which returns the set of nodes which are in the work set for each procedure after the + * update. + * + * @return a {@link Map} which returns the set of nodes which are in the work set for each procedure after the + * update + */ + public Map> getWorkSet() { + return workSet; + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/StringADDSolver.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/StringADDSolver.java new file mode 100644 index 0000000000..ec8bb9af0d --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/StringADDSolver.java @@ -0,0 +1,38 @@ +/* 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.modelcheckers.m3c.solver; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; + +/** + * An {@link ADDSolver ADD solver} for generic, string-based formulas. + * + * @author frohme + */ +public class StringADDSolver extends ADDSolver implements M3CSolver { + + StringADDSolver(ContextFreeModalProcessSystem cfmps) { + super(cfmps); + } + + @Override + public boolean solve(String formula) throws ParseException { + return super.solve(M3CParser.parse(formula)); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/StringBDDSolver.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/StringBDDSolver.java new file mode 100644 index 0000000000..e168116762 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/StringBDDSolver.java @@ -0,0 +1,38 @@ +/* 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.modelcheckers.m3c.solver; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; + +/** + * A {@link BDDSolver BDD solver} for generic, string-based formulas. + * + * @author frohme + */ +public class StringBDDSolver extends BDDSolver implements M3CSolver { + + StringBDDSolver(ContextFreeModalProcessSystem cfmps) { + super(cfmps); + } + + @Override + public boolean solve(String formula) throws ParseException { + return super.solve(M3CParser.parse(formula)); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/TypedADDSolver.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/TypedADDSolver.java new file mode 100644 index 0000000000..8d0454b9b9 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/TypedADDSolver.java @@ -0,0 +1,33 @@ +/* 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.modelcheckers.m3c.solver; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.solver.M3CSolver.TypedM3CSolver; + +/** + * An {@link ADDSolver ADD solver} for strongly-typed formulas. + * + * @author frohme + */ +public class TypedADDSolver extends ADDSolver implements TypedM3CSolver> { + + TypedADDSolver(ContextFreeModalProcessSystem cfmps) { + super(cfmps); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/TypedBDDSolver.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/TypedBDDSolver.java new file mode 100644 index 0000000000..1bec665b04 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/solver/TypedBDDSolver.java @@ -0,0 +1,33 @@ +/* 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.modelcheckers.m3c.solver; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.solver.M3CSolver.TypedM3CSolver; + +/** + * A {@link BDDSolver BDD solver} for strongly-typed formulas. + * + * @author frohme + */ +public class TypedBDDSolver extends BDDSolver implements TypedM3CSolver> { + + TypedBDDSolver(ContextFreeModalProcessSystem cfmps) { + super(cfmps); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformer.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformer.java new file mode 100644 index 0000000000..4b2fcf6ab4 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformer.java @@ -0,0 +1,264 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import info.scce.addlib.dd.xdd.XDD; +import info.scce.addlib.dd.xdd.XDDManager; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVector; +import net.automatalib.modelcheckers.m3c.formula.AbstractModalFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DependencyGraph; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.EquationalBlock; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.ts.modal.transition.ModalEdgeProperty; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * An ADDTransformer represents a property transformer for a single ADD (Algebraic Decision Diagram). + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class ADDTransformer extends AbstractPropertyTransformer, L, AP> { + + private final XDDManager xddManager; + private final @MonotonicNonNull XDD add; + + ADDTransformer(XDDManager xddManager, XDD add) { + this.xddManager = xddManager; + this.add = add; + } + + ADDTransformer(XDDManager xddManager, XDD add, boolean isMust) { + super(isMust); + this.xddManager = xddManager; + this.add = add; + } + + /** + * Constructor used to initialize the property transformer of a node. + * + * @param xddManager + * used to create the ADD + * @param dependGraph + * of the formula that is currently being solved + */ + public ADDTransformer(XDDManager xddManager, DependencyGraph dependGraph) { + this.xddManager = xddManager; + final boolean[] terminal = new boolean[dependGraph.getNumVariables()]; + for (EquationalBlock block : dependGraph.getBlocks()) { + if (block.isMaxBlock()) { + for (FormulaNode node : block.getNodes()) { + terminal[node.getVarNumber()] = true; + } + } + } + add = xddManager.constant(new BooleanVector(terminal)); + } + + /** + * Creates the identity function. This sets the internal {@link XDD ADD} to {@code null} to avoid the construction + * of the ADD, which is very expensive. To prevent null-pointer exceptions when using {@link #getAdd()}, it can be + * checked with {@link #isIdentity()}. + * + * @param ddManager + * used to create the ADD + */ + // false-positive, see https://github.com/typetools/checker-framework/issues/2215 + @SuppressWarnings("assignment.type.incompatible") + public ADDTransformer(XDDManager ddManager) { + this.xddManager = ddManager; + this.add = null; + } + + /** + * Constructor used to create the property transformer for an edge. + * + * @param xddManager + * used to create the ADD + * @param edgeLabel + * of the edge + * @param edgeProperty + * of the edge + * @param dependGraph + * of the formula that is currently being solved + * @param + * edge property type + */ + public ADDTransformer(XDDManager xddManager, + L edgeLabel, + TP edgeProperty, + DependencyGraph dependGraph) { + this.xddManager = xddManager; + final List> list = new ArrayList<>(); + for (FormulaNode node : dependGraph.getFormulaNodes()) { + final boolean[] terminal = new boolean[dependGraph.getNumVariables()]; + final XDD falseDD = xddManager.constant(new BooleanVector(terminal)); + if (node instanceof AbstractModalFormulaNode) { + final AbstractModalFormulaNode modalNode = (AbstractModalFormulaNode) node; + final L action = modalNode.getAction(); + if ((action == null || action.equals(edgeLabel)) && + (!(modalNode instanceof DiamondNode) || edgeProperty.isMust())) { + int xj = modalNode.getVarNumberChild(); + terminal[modalNode.getVarNumber()] = true; + final XDD thenDD = xddManager.constant(new BooleanVector(terminal)); + final XDD id = xddManager.ithVar(xj, thenDD, falseDD); + list.add(id); + } else if (modalNode instanceof BoxNode) { + terminal[modalNode.getVarNumber()] = true; + list.add(xddManager.constant(new BooleanVector(terminal))); + } + } + } + + XDD tmpADD; + if (list.isEmpty()) { + tmpADD = xddManager.constant(new BooleanVector(new boolean[dependGraph.getNumVariables()])); + } else { + tmpADD = list.get(0); + for (int i = 1; i < list.size(); i++) { + tmpADD = tmpADD.apply(BooleanVector::or, list.get(i)); + } + } + + this.add = tmpADD; + } + + @Override + public Set evaluate(boolean[] input) { + final boolean[] leafData = this.add == null ? input : this.add.eval(input).v().data(); + final Set satisfiedVars = new HashSet<>(); + for (int i = 0; i < leafData.length; i++) { + if (leafData[i]) { + satisfiedVars.add(i); + } + } + return satisfiedVars; + } + + @Override + // false-positive, see https://github.com/typetools/checker-framework/issues/4872 + @SuppressWarnings("dereference.of.nullable") + public ADDTransformer compose(ADDTransformer other) { + final XDD compAdd; + + if (this.isIdentity() && other.isIdentity()) { + throw new IllegalStateException("Two identity functions should never be composed"); + } else if (this.isIdentity()) { + compAdd = new XDD<>(other.add.ptr(), xddManager); + } else if (other.isIdentity()) { + compAdd = new XDD<>(this.add.ptr(), xddManager); + } else { + compAdd = other.add.monadicApply(arg -> { + boolean[] terminal = arg.data().clone(); + return this.add.eval(terminal).v(); + }); + } + + return new ADDTransformer<>(xddManager, compAdd, this.isMust()); + } + + @Override + public ADDTransformer createUpdate(Set atomicPropositions, + List> compositions, + EquationalBlock currentBlock) { + XDD updatedADD; + final DiamondOperation diamondOp = new DiamondOperation<>(atomicPropositions, currentBlock); + if (compositions.isEmpty()) { + assert this.add != null : "The identity function should never be updated"; + updatedADD = this.add.monadicApply(new DiamondOperationDeadlock<>(atomicPropositions, currentBlock)); + } else { + final XDD firstAdd = compositions.get(0).add; + assert firstAdd != null : "The identity function should never be updated"; + updatedADD = preserveUpdatedTransformer(firstAdd, currentBlock); + + for (ADDTransformer composition : compositions) { + assert composition.add != null : "The identity function should never be updated"; + updatedADD = updatedADD.apply(diamondOp, composition.add); + } + } + + return new ADDTransformer<>(xddManager, updatedADD); + } + + private XDD preserveUpdatedTransformer(XDD rightDD, + EquationalBlock currentBlock) { + assert this.add != null : "The identity function should never be updated"; + /* We create a new XDD where the information of this.add (the add before the update) is 'injected' + into rightDD, the first composition DD, such that the bits corresponding to subformulas outside of the current + block are preserved */ + return this.add.apply((booleanVectorBeforeUpdate, booleanVectorRight) -> { + boolean[] result = booleanVectorBeforeUpdate.data().clone(); + for (FormulaNode node : currentBlock.getNodes()) { + result[node.getVarNumber()] = booleanVectorRight.data()[node.getVarNumber()]; + } + return new BooleanVector(result); + }, rightDD); + } + + /** + * Returns the ADD which represents the property transformer. + * + * @return the ADD which represents the property transformer or {@code null} if the property transformer is the + * identity function + */ + public @Nullable XDD getAdd() { + return this.add; + } + + /** + * Returns whether the property transformer is the identity function. + * + * @return {@code true} if the property transformer is the identity function, {@code false} otherwise + */ + @EnsuresNonNullIf(result = false, expression = {"add", "getAdd()"}) + @SuppressWarnings("contracts.conditional.postcondition.not.satisfied") // getAdd() is pure + public boolean isIdentity() { + return this.add == null; + } + + @Override + public int hashCode() { + return Objects.hashCode(add); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final ADDTransformer that = (ADDTransformer) o; + + return Objects.equals(this.add, that.add); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformerSerializer.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformerSerializer.java new file mode 100644 index 0000000000..79ea95e7d7 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformerSerializer.java @@ -0,0 +1,65 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.Collections; +import java.util.List; + +import info.scce.addlib.dd.xdd.XDD; +import info.scce.addlib.dd.xdd.XDDManager; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVector; +import info.scce.addlib.serializer.DDProperty; +import info.scce.addlib.serializer.XDDSerializer; + +/** + * This class can be used to serialize and deserialize {@link ADDTransformer}s. + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class ADDTransformerSerializer implements TransformerSerializer, L, AP> { + + private final XDDManager xddManager; + + public ADDTransformerSerializer(XDDManager xddManager) { + this.xddManager = xddManager; + } + + @Override + public List serialize(ADDTransformer transformer) { + if (transformer.isIdentity()) { + return Collections.emptyList(); + } + + final XDDSerializer xddSerializer = new XDDSerializer<>(); + return Collections.singletonList(xddSerializer.serialize(transformer.getAdd())); + } + + @Override + public ADDTransformer deserialize(List data) { + if (data.isEmpty()) { + return new ADDTransformer<>(xddManager); + } + + final XDDSerializer xddSerializer = new XDDSerializer<>(); + final XDD transformer = xddSerializer.deserialize(xddManager, data.get(0), DDProperty.VARINDEX); + return new ADDTransformer<>(xddManager, transformer); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/AbstractPropertyTransformer.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/AbstractPropertyTransformer.java new file mode 100644 index 0000000000..6891a6a254 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/AbstractPropertyTransformer.java @@ -0,0 +1,95 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.List; +import java.util.Set; + +import net.automatalib.modelcheckers.m3c.formula.EquationalBlock; + +/** + * Base class used to represent a property transformer, i.e., a function which maps a subset of formulas to a subset of + * formulas. Can also be seen as a function which maps bit vectors of length n to bit vectors of length n. + * + * @param + * property transformer type + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public abstract class AbstractPropertyTransformer, L, AP> { + + private final boolean isMust; + + AbstractPropertyTransformer() { + this(true); + } + + AbstractPropertyTransformer(boolean isMust) { + this.isMust = isMust; + } + + /** + * Returns the set of variable numbers of subformulas y with f(input)=y, where f is the property transformer + * represented by {@code this}. + * + * @param input + * a boolean array representing a set of subformulas + * + * @return the set of variable numbers of subformulas + */ + public abstract Set evaluate(boolean[] input); + + /** + * Returns the composition {@code h} of {@code this} and {@code other} such that {@code h(x) = this(other(x))}. The + * {@code isMust} attribute of the composition is set to the {@code isMust} attribute of {@code this}. + * + * @param other + * function which is first applied to an input + * + * @return the composition of {@code this} and {@code other} + */ + public abstract T compose(T other); + + /** + * Returns the updated property transformer of a node. + * + * @param atomicPropositions + * of the node + * @param compositions + * of the property transformers belonging to the outgoing edges and their target nodes + * @param currentBlock + * the block which is considered during this update + * + * @return the updated property transformer of a node + */ + public abstract T createUpdate(Set atomicPropositions, + List compositions, + EquationalBlock currentBlock); + + /** + * Returns whether the property transformer belongs to a node or to a must edge. + * + * @return {@code true} if the property transformer belongs to a node or to a must edge, {@code false} otherwise + */ + public boolean isMust() { + return isMust; + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformer.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformer.java new file mode 100644 index 0000000000..9d32b24ea5 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformer.java @@ -0,0 +1,268 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import info.scce.addlib.dd.bdd.BDD; +import info.scce.addlib.dd.bdd.BDDManager; +import net.automatalib.modelcheckers.m3c.formula.AbstractModalFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DependencyGraph; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.EquationalBlock; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.ts.modal.transition.ModalEdgeProperty; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A BDDTransformer represents a property transformer for a list of BDDs (Binary Decision Diagrams), one per subformula. + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class BDDTransformer extends AbstractPropertyTransformer, L, AP> { + + private final BDDManager bddManager; + /* One BDD for each lhs of equation system */ + private final BDD[] bdds; + + BDDTransformer(BDDManager bddManager, BDD[] bdds) { + this.bddManager = bddManager; + this.bdds = bdds; + } + + BDDTransformer(BDDManager bddManager, BDD[] bdds, boolean isMust) { + super(isMust); + this.bddManager = bddManager; + this.bdds = bdds; + } + + /** + * Constructor used to initialize the property transformer of a node. + * + * @param bddManager + * used to create the BDDs + * @param dependencyGraph + * of the formula that is currently being solved + */ + public BDDTransformer(BDDManager bddManager, DependencyGraph dependencyGraph) { + this(bddManager, new BDD[dependencyGraph.getNumVariables()]); + for (EquationalBlock block : dependencyGraph.getBlocks()) { + if (block.isMaxBlock()) { + for (FormulaNode node : block.getNodes()) { + bdds[node.getVarNumber()] = bddManager.readOne(); + } + } else { + for (FormulaNode node : block.getNodes()) { + bdds[node.getVarNumber()] = bddManager.readLogicZero(); + } + } + } + } + + /** + * Constructor used to create the property transformer for an edge. + * + * @param bddManager + * used to create the BDDs + * @param edgeLabel + * of the edge + * @param edgeProperty + * of the edge + * @param dependencyGraph + * of the formula that is currently being solved + * @param + * edge property type + */ + public BDDTransformer(BDDManager bddManager, + L edgeLabel, + TP edgeProperty, + DependencyGraph dependencyGraph) { + this(bddManager, new BDD[dependencyGraph.getNumVariables()], edgeProperty.isMust()); + for (FormulaNode node : dependencyGraph.getFormulaNodes()) { + int xi = node.getVarNumber(); + if (node instanceof AbstractModalFormulaNode) { + final AbstractModalFormulaNode modalNode = (AbstractModalFormulaNode) node; + final L action = modalNode.getAction(); + /* action matches edgeLabel AND (node instanceof DiamondNode => edge.isMust) */ + if ((action == null || action.equals(edgeLabel)) && + (!(modalNode instanceof DiamondNode) || edgeProperty.isMust())) { + int xj = modalNode.getVarNumberChild(); + bdds[xi] = bddManager.ithVar(xj); + } else if (modalNode instanceof DiamondNode) { + bdds[xi] = bddManager.readLogicZero(); + } else if (modalNode instanceof BoxNode) { + bdds[xi] = bddManager.readOne(); + } + } else { + bdds[xi] = bddManager.readLogicZero(); + } + } + } + + /** + * The Property Transformer representing the identity function. + * + * @param bddManager + * used to create the BDDs + * @param numberOfVars + * the number of subformulas + */ + public BDDTransformer(BDDManager bddManager, int numberOfVars) { + this(bddManager, new BDD[numberOfVars]); + for (int var = 0; var < numberOfVars; var++) { + bdds[var] = bddManager.ithVar(var); + } + } + + @Override + public Set evaluate(boolean[] input) { + final Set output = new HashSet<>(); + for (int i = 0; i < bdds.length; i++) { + if (bdds[i].eval(input).equals(bddManager.readOne())) { + output.add(i); + } + } + return output; + } + + @Override + public BDDTransformer compose(BDDTransformer other) { + final BDD[] composedBDDs = new BDD[bdds.length]; + for (int var = 0; var < bdds.length; var++) { + final BDD composedBDD = bdds[var].vectorCompose(other.bdds); + composedBDDs[var] = composedBDD; + } + return new BDDTransformer<>(bddManager, composedBDDs, this.isMust()); + } + + @Override + public BDDTransformer createUpdate(Set atomicPropositions, + List> compositions, + EquationalBlock currentBlock) { + /* Set BDDs of updated transformer to initial bdds as we do not update all bdds + * but only those for the current block */ + final BDD[] updatedBDDs = bdds.clone(); + for (FormulaNode node : currentBlock.getNodes()) { + updateFormulaNode(atomicPropositions, compositions, updatedBDDs, node); + } + return new BDDTransformer<>(bddManager, updatedBDDs); + } + + private void updateFormulaNode(Set atomicPropositions, + List> compositions, + BDD[] updatedBDDs, + FormulaNode node) { + final int varIdx = node.getVarNumber(); + final BDD result; + if (node instanceof BoxNode) { + result = andBddList(compositions, varIdx); + } else if (node instanceof DiamondNode) { + result = orBddList(compositions, varIdx); + } else if (node instanceof AndNode) { + final AndNode andNode = (AndNode) node; + result = updatedBDDs[andNode.getVarNumberLeft()].and(updatedBDDs[andNode.getVarNumberRight()]); + } else if (node instanceof OrNode) { + final OrNode orNode = (OrNode) node; + result = updatedBDDs[orNode.getVarNumberLeft()].or(updatedBDDs[orNode.getVarNumberRight()]); + } else if (node instanceof TrueNode) { + result = bddManager.readOne(); + } else if (node instanceof FalseNode) { + result = bddManager.readLogicZero(); + } else if (node instanceof NotNode) { + final NotNode notNode = (NotNode) node; + result = bdds[notNode.getVarNumberChild()].not(); + } else if (node instanceof AtomicNode) { + final AP atomicProp = ((AtomicNode) node).getProposition(); + if (atomicPropositions.contains(atomicProp)) { + result = bddManager.readOne(); + } else { + result = bddManager.readLogicZero(); + } + } else { + throw new IllegalArgumentException(); + } + updatedBDDs[varIdx] = result; + } + + BDD andBddList(List> compositions, int var) { + /* Conjunction over the var-th BDDs of compositions */ + final Optional result = compositions.stream().map(comp -> comp.getBDD(var)).reduce(BDD::and); + return result.orElseGet(bddManager::readOne); + } + + BDD orBddList(List> compositions, int var) { + /* Disjunction over the var-th BDDs of compositions */ + final Optional result = + compositions.stream().filter(BDDTransformer::isMust).map(comp -> comp.getBDD(var)).reduce(BDD::or); + return result.orElseGet(bddManager::readLogicZero); + } + + /** + * Returns the {@link BDD} used to compute the satisfiability of subformula with variable number {@code var}. + * + * @param var + * index of the BDD to return + * + * @return the {@link BDD} used to compute the satisfiability of subformula with variable number {@code var} + */ + public BDD getBDD(int var) { + return bdds[var]; + } + + /** + * Returns the number of subformulas. + * + * @return the number of subformulas + */ + public int getNumberOfVars() { + return bdds.length; + } + + @Override + public int hashCode() { + return Arrays.hashCode(bdds); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final BDDTransformer that = (BDDTransformer) o; + + return Arrays.equals(this.bdds, that.bdds); + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformerSerializer.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformerSerializer.java new file mode 100644 index 0000000000..daf26e98d2 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformerSerializer.java @@ -0,0 +1,103 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import info.scce.addlib.dd.bdd.BDD; +import info.scce.addlib.dd.bdd.BDDManager; +import info.scce.addlib.dd.xdd.XDD; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanLogicDDManager; +import info.scce.addlib.serializer.DDProperty; +import info.scce.addlib.serializer.XDDSerializer; + +/** + * This class can be used to serialize and deserialize {@link BDDTransformer}s. + * + * @param + * edge label type + * @param + * atomic proposition type + * + * @author murtovi + */ +public class BDDTransformerSerializer implements TransformerSerializer, L, AP> { + + private final BDDManager bddManager; + + public BDDTransformerSerializer(BDDManager bddManager) { + this.bddManager = bddManager; + } + + @Override + public List serialize(BDDTransformer transformer) { + final XDDSerializer xddSerializer = new XDDSerializer<>(); + final List serializedBDDs = new ArrayList<>(); + final BooleanLogicDDManager ddManager = new BooleanLogicDDManager(); + + for (int i = 0; i < transformer.getNumberOfVars(); i++) { + final XDD bddAsXDD = transformer.getBDD(i).toXDD(ddManager); + serializedBDDs.add(xddSerializer.serialize(bddAsXDD)); + } + + ddManager.quit(); + return serializedBDDs; + } + + @Override + public BDDTransformer deserialize(List data) { + final BooleanLogicDDManager ddManager = new BooleanLogicDDManager(); + final XDDSerializer serializer = new XDDSerializer<>(); + final List> xdds = new ArrayList<>(); + + for (String serializedDD : data) { + xdds.add(serializer.deserialize(ddManager, serializedDD, DDProperty.VARINDEX)); + } + + final BDD[] bdds = new BDD[xdds.size()]; + + for (int i = 0; i < bdds.length; i++) { + bdds[i] = toBDD(xdds.get(i), bddManager, new HashMap<>()); + } + + ddManager.quit(); + return new BDDTransformer<>(bddManager, bdds); + } + + private BDD toBDD(XDD xdd, BDDManager bddManager, Map, BDD> xdd2bdd) { + BDD bdd = xdd2bdd.get(xdd); + if (bdd == null) { + if (xdd.isConstant()) { + if (xdd.v()) { + bdd = bddManager.readOne(); + } else { + bdd = bddManager.readLogicZero(); + } + } else { + final BDD falseSucc = toBDD(xdd.e(), bddManager, xdd2bdd); + final BDD trueSucc = toBDD(xdd.t(), bddManager, xdd2bdd); + final BDD ithBDD = bddManager.ithVar(bddManager.varIdx(xdd.readName())); + bdd = ithBDD.ite(trueSucc, falseSucc); + } + xdd2bdd.put(xdd, bdd); + } + + return bdd; + } +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/DiamondOperation.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/DiamondOperation.java new file mode 100644 index 0000000000..4d515bffc4 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/DiamondOperation.java @@ -0,0 +1,87 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.Set; +import java.util.function.BinaryOperator; + +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVector; +import net.automatalib.modelcheckers.m3c.formula.AbstractBinaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.EquationalBlock; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; + +/** + * Implementation of the diamond function. + * + * @param + * atomic proposition type + * + * @author murtovi + */ +public class DiamondOperation implements BinaryOperator { + + private final EquationalBlock block; + private final Set atomicPropositions; + + public DiamondOperation(Set atomicPropositions, EquationalBlock block) { + this.atomicPropositions = atomicPropositions; + this.block = block; + } + + @Override + public BooleanVector apply(BooleanVector left, BooleanVector right) { + final boolean[] result = left.data().clone(); + for (FormulaNode node : block.getNodes()) { + final int currentVar = node.getVarNumber(); + if (node instanceof BoxNode) { + result[currentVar] = result[currentVar] && right.data()[currentVar]; + } else if (node instanceof DiamondNode) { + result[currentVar] = result[currentVar] || right.data()[currentVar]; + } else if (node instanceof AbstractBinaryFormulaNode) { + final AbstractBinaryFormulaNode binaryNode = (AbstractBinaryFormulaNode) node; + final int xj1 = binaryNode.getVarNumberLeft(); + final int xj2 = binaryNode.getVarNumberRight(); + if (binaryNode instanceof AndNode) { + result[currentVar] = result[xj1] && result[xj2]; + } else { + result[currentVar] = result[xj1] || result[xj2]; + } + } else if (node instanceof TrueNode) { + result[currentVar] = true; + } else if (node instanceof FalseNode) { + result[currentVar] = false; + } else if (node instanceof NotNode) { + final NotNode notNode = (NotNode) node; + result[currentVar] = !result[notNode.getVarNumberChild()]; + } else if (node instanceof AtomicNode) { + @SuppressWarnings("unchecked") + final AP prop = ((AtomicNode) node).getProposition(); + result[currentVar] = atomicPropositions.contains(prop); + } else { + throw new IllegalArgumentException("The current equational block contains an unsupported formula type."); + } + } + return new BooleanVector(result); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/DiamondOperationDeadlock.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/DiamondOperationDeadlock.java new file mode 100644 index 0000000000..7e2a76780d --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/DiamondOperationDeadlock.java @@ -0,0 +1,87 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.Set; +import java.util.function.UnaryOperator; + +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVector; +import net.automatalib.modelcheckers.m3c.formula.AbstractBinaryFormulaNode; +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.EquationalBlock; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; + +/** + * Implementation of the diamond function when the node has exactly one successor. + * + * @param + * atomic proposition type + * + * @author murtovi + */ +public class DiamondOperationDeadlock implements UnaryOperator { + + private final EquationalBlock block; + private final Set atomicPropositions; + + public DiamondOperationDeadlock(Set atomicPropositions, EquationalBlock block) { + this.atomicPropositions = atomicPropositions; + this.block = block; + } + + @Override + public BooleanVector apply(BooleanVector vector) { + final boolean[] result = vector.data().clone(); + for (FormulaNode node : block.getNodes()) { + final int currentVar = node.getVarNumber(); + if (node instanceof BoxNode) { + result[currentVar] = true; + } else if (node instanceof DiamondNode) { + result[currentVar] = false; + } else if (node instanceof AbstractBinaryFormulaNode) { + final AbstractBinaryFormulaNode binaryNode = (AbstractBinaryFormulaNode) node; + final int xj1 = binaryNode.getVarNumberLeft(); + final int xj2 = binaryNode.getVarNumberRight(); + if (binaryNode instanceof AndNode) { + result[currentVar] = result[xj1] && result[xj2]; + } else { + result[currentVar] = result[xj1] || result[xj2]; + } + } else if (node instanceof TrueNode) { + result[currentVar] = true; + } else if (node instanceof FalseNode) { + result[currentVar] = false; + } else if (node instanceof NotNode) { + final NotNode notNode = (NotNode) node; + result[currentVar] = !result[notNode.getVarNumberChild()]; + } else if (node instanceof AtomicNode) { + @SuppressWarnings("unchecked") + final AP prop = ((AtomicNode) node).getProposition(); + result[currentVar] = atomicPropositions.contains(prop); + } else { + throw new IllegalArgumentException("The current equational block contains an unsupported formula type."); + } + } + return new BooleanVector(result); + } + +} diff --git a/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/TransformerSerializer.java b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/TransformerSerializer.java new file mode 100644 index 0000000000..3fe4088f37 --- /dev/null +++ b/modelchecking/m3c/src/main/java/net/automatalib/modelcheckers/m3c/transformer/TransformerSerializer.java @@ -0,0 +1,54 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.List; + +/** + * Utility interface for serializing {@link AbstractPropertyTransformer} implementations. + * + * @param + * the concrete transformer class + * @param + * the label class + * @param + * the atomic proposition class + * + * @author frohme + */ +public interface TransformerSerializer, L, AP> { + + /** + * Serializes a given transformer to {@link List}-based {@link String} representation. + * + * @param transformer + * the property transformer to be serialized. + * + * @return the serialized property transformer. + */ + List serialize(T transformer); + + /** + * Deserializes a given transformer from its {@link List}-based {@link String} representation. + * + * @param data + * a serialized property transformer. + * + * @return the deserialized property transformer. + */ + T deserialize(List data); + +} diff --git a/modelchecking/m3c/src/main/javacc/M3C.jj b/modelchecking/m3c/src/main/javacc/M3C.jj new file mode 100644 index 0000000000..9b6c7c6bca --- /dev/null +++ b/modelchecking/m3c/src/main/javacc/M3C.jj @@ -0,0 +1,262 @@ +/* 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. + */ + +options { + LOOKAHEAD = 1; + STATIC = false; + SUPPORT_CLASS_VISIBILITY_PUBLIC = false; + UNICODE_INPUT = true; +} + +PARSER_BEGIN(InternalM3CParser) + +package net.automatalib.modelcheckers.m3c.formula.parser; + +import net.automatalib.modelcheckers.m3c.formula.*; +import net.automatalib.modelcheckers.m3c.formula.ctl.*; +import net.automatalib.modelcheckers.m3c.formula.modalmu.*; + +import java.util.Set; +import java.util.HashSet; +import java.util.function.Function; + +class InternalM3CParser { + private Set fixedPointVars; + private Function labelParser; + private Function apParser; + + private void addFixedPointVar(String fixedPointVar) throws ParseException { + if (fixedPointVars.contains(fixedPointVar)) { + throw new ParseException("Input formula is not valid. The variable " + fixedPointVar + " is defined multiple times."); + } + fixedPointVars.add(fixedPointVar); + } +} + +PARSER_END(InternalM3CParser) + +<*> SKIP: +{ + " " +| "\r" +| "\t" +| "\n" +} + +<*> TOKEN [IGNORE_CASE]: +{ + < TRUE: "true" > +| < FALSE: "false" > +} + + TOKEN: +{ + < ALL: "A" > : CTL +| < EXISTS: "E" > : CTL +| < AF: "AF" > : CTL +| < AG: "AG" > : CTL +| < EF: "EF" > : CTL +| < EG: "EG" > : CTL +| < UNTIL: "U" > : CTL +| < WUNTIL: "W" > : CTL +} + + TOKEN: +{ + < NU: "nu" > : MUCALC +| < MU: "mu" > : MUCALC +} + +<*> TOKEN: +{ +// atoms + < LPAREN: "(" > +| < RPAREN: ")" > +| < LBRACKET: "[" > +| < RBRACKET: "]" > +| < LABRACKET: "<" > +| < RABRACKET: ">" > +// junctors +| < NEGATION: "!" > +| < DOT: "." > +| < AND: "&&" > +| < OR: "||" > +| < EQUIVALENCE: "<->" > +| < IMPLICATION: "->" > +| < ID: ["a"-"z","A"-"Z"] (["a"-"z","A"-"Z"] | ["0"-"9"] | "_")* > +| < STRING_LITERAL: ("'" (~["'", "\\"])* (("\\\'" | "\\\\") (~["'", "\\"])*)* "'") +| ("\"" (~["\"", "\\"])* (("\\\"" | "\\\\") (~["\"", "\\"])*)* "\"")> +} + +FormulaNode parse(Function labelParser, Function apParser): +{ + this.fixedPointVars = new HashSet(); + this.labelParser = labelParser; + this.apParser = apParser; + FormulaNode node; +} +{ + node=formula() {return node;} +} + +private FormulaNode formula(): +{ + FormulaNode node; +} +{ + (node=untilFormula() +| node=equivFormula() ) {return node;} +} + +private FormulaNode untilFormula(): +{ + FormulaNode l, r; + boolean isAll = false, isStrongUntil = false; +} +{ + ( {isAll=true;} | ) l=formula() ( {isStrongUntil=true;} | ) r=formula() + { + if(isAll) { + if(isStrongUntil) { + return new AUNode(l, r); + } + return new AWUNode(l, r); + } + if(isStrongUntil) { + return new EUNode(l, r); + } + return new EWUNode(l, r); + } +} + +private FormulaNode equivFormula(): +{ + FormulaNode l; + FormulaNode r = null; +} +{ + l=implFormula() ( r=equivFormula())? + { + if(r == null) { + return l; + } + return new AndNode(new OrNode(new NotNode(l), r), new OrNode(new NotNode(r), l)); + } +} + +private FormulaNode implFormula(): +{ + FormulaNode l; + FormulaNode r = null; +} +{ + l=orFormula() ( r=implFormula())? + { + if(r == null) { + return l; + } + return new OrNode(new NotNode(l), r); + } +} + +private FormulaNode orFormula(): +{ + FormulaNode l; + FormulaNode r = null; +} +{ + l=andFormula() ( r=orFormula())? + { + if(r == null) { + return l; + } + return new OrNode(l, r); + } +} + +private FormulaNode andFormula(): +{ + FormulaNode l; + FormulaNode r = null;} +{ + l=unary() ( r=andFormula())? + { + if(r == null) { + return l; + } + return new AndNode(l, r); + } +} + +private FormulaNode unary(): +{ + FormulaNode child; + Token action = null; +} +{ + child=fixedPointFormula() {return child;} +| child=unary() {return new NotNode(child);} +| child=unary() {return new AFNode(child);} +| child=unary() {return new AGNode(child);} +| child=unary() {return new EFNode(child);} +| child=unary() {return new EGNode(child);} +| (action=)? child=unary() {return new DiamondNode(action==null ? null : this.labelParser.apply(action.toString()), child);} +| (action=)? child=unary() {return new BoxNode(action==null ? null : this.labelParser.apply(action.toString()), child);} +| child=element() {return child;} +} + +private FormulaNode fixedPointFormula(): +{ + FormulaNode child; + Token var; + boolean isGFP = false; +} +{ + ( {isGFP=true;}| ) var= {addFixedPointVar(var.toString());} child=formula() + { + String fixedPointVar = var.toString(); + fixedPointVars.remove(fixedPointVar); + if(isGFP) { + return new GfpNode(fixedPointVar, child); + } + return new LfpNode(fixedPointVar, child); + } +} + +private FormulaNode element(): +{ + FormulaNode node; + Token ap, var; +} +{ + ap= + { + String apString = ap.toString(); + String apWithoutQuotMarks = apString.substring(1, apString.length()-1); + return new AtomicNode(this.apParser.apply(apWithoutQuotMarks)); + } +| var= + { + String fixedPointVar = var.toString(); + if (!fixedPointVars.contains(fixedPointVar)) { + throw new ParseException("Referenced variable " + fixedPointVar + " is not in scope."); + } + return new VariableNode(fixedPointVar); + } +| {return new TrueNode();} +| {return new FalseNode();} +| node=formula() {return node;} +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/DependencyGraphTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/DependencyGraphTest.java new file mode 100644 index 0000000000..e049e96da0 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/DependencyGraphTest.java @@ -0,0 +1,68 @@ +/* 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.modelcheckers.m3c.formula; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DependencyGraphTest { + + @Test + void testDependencyGraph() throws ParseException { + String formula = "mu X.(true || <>X)"; + FormulaNode ast = M3CParser.parse(formula); + DependencyGraph dg = new DependencyGraph<>(ast); + + /* Assert that number of variables are correct */ + Assert.assertEquals(5, dg.getFormulaNodes().size()); + Assert.assertEquals(dg.getFormulaNodes().size(), dg.getNumVariables()); + Assert.assertTrue(checkVarNumbering(dg.getFormulaNodes())); + + /* Assert that blocks are created correctly*/ + Assert.assertEquals(1, dg.getBlocks().size()); + Assert.assertEquals(5, dg.getBlocks().get(0).getNodes().size()); + Assert.assertTrue(isMonotonicallyDecreasing(dg.getBlocks().get(0).getNodes())); + + } + + private boolean checkVarNumbering(List> nodes) { + int numVars = nodes.size(); + Set vars = new HashSet<>(); + for (int i = 0; i < numVars; i++) { + vars.add(i); + } + for (FormulaNode node : nodes) { + vars.remove(node.getVarNumber()); + } + return vars.isEmpty(); + } + + private boolean isMonotonicallyDecreasing(List> nodes) { + /* Checks if nodes are sorted such that dependencies between nodes are respected */ + for (int i = 0; i < nodes.size() - 1; i++) { + if (nodes.get(i).getVarNumber() < nodes.get(i + 1).getVarNumber()) { + return false; + } + } + return true; + } +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/parser/ParserCTLTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/parser/ParserCTLTest.java new file mode 100644 index 0000000000..8c4bd973a3 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/parser/ParserCTLTest.java @@ -0,0 +1,114 @@ +/* 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.modelcheckers.m3c.formula.parser; + +import java.util.ArrayList; +import java.util.List; + +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AFNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AGNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AWUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EFNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EGNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EUNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.EWUNode; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author murtovi + */ +public class ParserCTLTest { + + private final List> formulas = new ArrayList<>(); + + @Test + public void baseCasesTest() throws ParseException { + assertEquals("false", new FalseNode<>()); + assertEquals("true", new TrueNode<>()); + assertEquals("true && true", new AndNode<>(new TrueNode<>(), new TrueNode<>())); + assertEquals("true || false", new OrNode<>(new TrueNode<>(), new FalseNode<>())); + assertEquals("'a'", new AtomicNode<>("a")); + assertEquals("\"b\"", new AtomicNode<>("b")); + assertEquals("\"a\" && \"b\" && \"c\"", + new AndNode<>(new AtomicNode<>("a"), new AndNode<>(new AtomicNode<>("b"), new AtomicNode<>("c")))); + assertEquals("AG true", new AGNode<>(new TrueNode<>())); + assertEquals("AF true", new AFNode<>(new TrueNode<>())); + assertEquals("A(true U false)", new AUNode<>(new TrueNode<>(), new FalseNode<>())); + assertEquals("A(true W true)", new AWUNode<>(new TrueNode<>(), new TrueNode<>())); + assertEquals("EG true", new EGNode<>(new TrueNode<>())); + assertEquals("EF true", new EFNode<>(new TrueNode<>())); + assertEquals("E(false U false)", new EUNode<>(new FalseNode<>(), new FalseNode<>())); + assertEquals("E(true W false)", new EWUNode<>(new TrueNode<>(), new FalseNode<>())); + assertEquals("true -> false", new OrNode<>(new NotNode<>(new TrueNode<>()), new FalseNode<>())); + assertEquals("true <-> false", + new AndNode<>(new OrNode<>(new NotNode<>(new TrueNode<>()), new FalseNode<>()), + new OrNode<>(new NotNode<>(new FalseNode<>()), new TrueNode<>()))); + assertEquals("!false", new NotNode<>(new FalseNode<>())); + assertEquals("[]true", new BoxNode<>(new TrueNode<>())); + assertEquals("<>false", new DiamondNode<>(new FalseNode<>())); + assertEquals("false", new DiamondNode<>("a", new FalseNode<>())); + assertEquals("[c]true", new BoxNode<>("c", new TrueNode<>())); + } + + private void assertEquals(String ctlFormula, FormulaNode expectedAST) throws ParseException { + FormulaNode actualAST = M3CParser.parse(ctlFormula); + Assert.assertEquals(actualAST, expectedAST); + Assert.assertEquals(actualAST.hashCode(), expectedAST.hashCode()); + + this.formulas.add(actualAST); + } + + @Test + public void nestedFormulasTest() throws ParseException { + assertEquals("(true && true) || (false && false)", + new OrNode<>(new AndNode<>(new TrueNode<>(), new TrueNode<>()), + new AndNode<>(new FalseNode<>(), new FalseNode<>()))); + } + + @Test(dependsOnMethods = {"baseCasesTest", "nestedFormulasTest"}) + public void testEqualities() { + for (FormulaNode n1 : formulas) { + for (FormulaNode n2 : formulas) { + Assert.assertEquals(n1.equals(n2), n1 == n2, "n1: " + n1 + ", n2: " + n2); + } + } + } + + @Test + public void testIllegalFormulas() { + assertIllegal("true <=> false -> true"); + assertIllegal("true <=> (false -> true)"); + assertIllegal("AG (mu X.(<>X))"); + assertIllegal("(AF true) && (mu X.( true || <>X)"); + assertIllegal("(mu X.( true || <>X) || (AF true)"); + } + + private void assertIllegal(String formula) { + Assert.assertThrows(ParseException.class, () -> M3CParser.parse(formula)); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/parser/ParserMuCalcTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/parser/ParserMuCalcTest.java new file mode 100644 index 0000000000..87841ebac6 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/parser/ParserMuCalcTest.java @@ -0,0 +1,122 @@ +/* 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.modelcheckers.m3c.formula.parser; + +import java.util.ArrayList; +import java.util.List; + +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.GfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.VariableNode; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class ParserMuCalcTest { + + private final List> formulas = new ArrayList<>(); + + @Test + public void testBaseCases() throws ParseException { + assertEquals("false", new FalseNode<>()); + assertEquals("true", new TrueNode<>()); + assertEquals("true && true", new AndNode<>(new TrueNode<>(), new TrueNode<>())); + assertEquals("true || false", new OrNode<>(new TrueNode<>(), new FalseNode<>())); + assertEquals("'a'", new AtomicNode<>("a")); + assertEquals("\"b\"", new AtomicNode<>("b")); + assertEquals("\"a\" && \"b\" && \"c\"", + new AndNode<>(new AtomicNode<>("a"), new AndNode<>(new AtomicNode<>("b"), new AtomicNode<>("c")))); + assertEquals("true -> false", new OrNode<>(new NotNode<>(new TrueNode<>()), new FalseNode<>())); + assertEquals("true <-> false", + new AndNode<>(new OrNode<>(new NotNode<>(new TrueNode<>()), new FalseNode<>()), + new OrNode<>(new NotNode<>(new FalseNode<>()), new TrueNode<>()))); + assertEquals("!false", new NotNode<>(new FalseNode<>())); + assertEquals("[]true", new BoxNode<>(new TrueNode<>())); + assertEquals("<>false", new DiamondNode<>(new FalseNode<>())); + assertEquals("false", new DiamondNode<>("ab", new FalseNode<>())); + assertEquals("[ab]true", new BoxNode<>("ab", new TrueNode<>())); + assertEquals("mu XY.(XY || false)", + new LfpNode<>("XY", new OrNode<>(new VariableNode<>("XY"), new FalseNode<>()))); + assertEquals("nu ZY.(ZY || false)", + new GfpNode<>("ZY", new OrNode<>(new VariableNode<>("ZY"), new FalseNode<>()))); + } + + @Test + public void testNestedFixPoints() throws ParseException { + assertEquals("nu X. ([]X && mu Y. (<>Y || (\"AP\" && [] false)))", + new GfpNode<>("X", + new AndNode<>(new BoxNode<>(new VariableNode<>("X")), + new LfpNode<>("Y", + new OrNode<>(new DiamondNode<>(new VariableNode<>("Y")), + new AndNode<>(new AtomicNode<>("AP"), + new BoxNode<>(new FalseNode<>()))))))); + assertEquals("nu X. ([]X && (true -> mu Y. (Y || true)))", + new GfpNode<>("X", + new AndNode<>(new BoxNode<>(new VariableNode<>("X")), + new OrNode<>(new NotNode<>(new DiamondNode<>("S", new TrueNode<>())), + new LfpNode<>("Y", + new OrNode<>(new DiamondNode<>("S", + new VariableNode<>( + "Y")), + new DiamondNode<>("R", + new TrueNode<>()))))))); + } + + @Test + public void testPrecedence() throws ParseException { + assertEquals("true || false && true", "true || (false && true)"); + assertEquals("true -> false || true", "true -> (false || true)"); + assertEquals("true <-> false -> true", "true <-> (false -> true)"); + assertEquals("!true && false", "(!true) && false"); + assertEquals("nu X.(X || true) && false", "(nu X.(X || true)) && false"); + assertEquals("mu X.(X || true) && false", "(mu X.(X || true)) && false"); + assertEquals("[]true && true", "([]true) && true"); + assertEquals("[b]true && true", "([b]true) && true"); + assertEquals("<>true && true", "(<>true) && true"); + assertEquals("true && true", "(true) && true"); + + } + + @Test(dependsOnMethods = {"testBaseCases", "testNestedFixPoints", "testPrecedence"}) + public void testEqualities() { + for (FormulaNode n1 : formulas) { + for (FormulaNode n2 : formulas) { + Assert.assertEquals(n1.equals(n2), n1 == n2, "n1: " + n1 + ", n2: " + n2); + } + } + } + + private void assertEquals(String actualMuCalcFormula, String expectedMuCalcFormula) throws ParseException { + assertEquals(actualMuCalcFormula, M3CParser.parse(expectedMuCalcFormula)); + } + + private void assertEquals(String muCalcFormula, FormulaNode expectedAST) throws ParseException { + FormulaNode actualAST = M3CParser.parse(muCalcFormula); + Assert.assertEquals(actualAST, expectedAST); + Assert.assertEquals(actualAST.hashCode(), expectedAST.hashCode()); + + this.formulas.add(actualAST); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/CTLToMuCalcTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/CTLToMuCalcTest.java new file mode 100644 index 0000000000..5702397b9f --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/CTLToMuCalcTest.java @@ -0,0 +1,156 @@ +/* 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.modelcheckers.m3c.formula.visitor; + +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.AtomicNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.GfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.VariableNode; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CTLToMuCalcTest { + + private final CTLToMuCalc transformer = new CTLToMuCalc<>(); + + @Test + void testTrue() throws ParseException { + equals("true", new TrueNode<>()); + } + + @Test + void testFalse() throws ParseException { + equals("false", new FalseNode<>()); + } + + @Test + void testAtomicProposition() throws ParseException { + equals("\"p\"", new AtomicNode<>("p")); + } + + @Test + void testNegation() throws ParseException { + equals("!\"p\"", new NotNode<>(new AtomicNode<>("p"))); + } + + @Test + void testBox() throws ParseException { + equals("[abc]true", new BoxNode<>("abc", new TrueNode<>())); + } + + @Test + void testDiamond() throws ParseException { + equals("<>false", new DiamondNode<>(new FalseNode<>())); + } + + @Test + void testOr() throws ParseException { + equals("\"p\" || \"q\"", new OrNode<>(new AtomicNode<>("p"), new AtomicNode<>("q"))); + } + + @Test + void testAnd() throws ParseException { + equals("\"p\" && \"q\"", new AndNode<>(new AtomicNode<>("p"), new AtomicNode<>("q"))); + } + + @Test + void testAF() throws ParseException { + DiamondNode diamond = new DiamondNode<>(new TrueNode<>()); + BoxNode box = new BoxNode<>(new VariableNode<>("Z0")); + AndNode and = new AndNode<>(diamond, box); + LfpNode expected = new LfpNode<>("Z0", new OrNode<>(new AtomicNode<>("p"), and)); + equals("AF \"p\"", expected); + } + + @Test + void testAG() throws ParseException { + AndNode and = new AndNode<>(new AtomicNode<>("p"), new BoxNode<>(new VariableNode<>("Z0"))); + GfpNode expected = new GfpNode<>("Z0", and); + equals("AG \"p\"", expected); + } + + @Test + void testAU() throws ParseException { + DiamondNode diamond = new DiamondNode<>(new TrueNode<>()); + BoxNode box = new BoxNode<>(new VariableNode<>("Z0")); + AndNode innerAnd = new AndNode<>(diamond, box); + AndNode outerAnd = new AndNode<>(new AtomicNode<>("p"), innerAnd); + OrNode or = new OrNode<>(new AtomicNode<>("q"), outerAnd); + LfpNode expected = new LfpNode<>("Z0", or); + equals("A(\"p\" U \"q\")", expected); + } + + @Test + void testAWU() throws ParseException { + /* A[p WU q] = !E[!q U (!p & !q)] */ + /* !E[!q U (!p & !q)] = !(mu X.((!p & !q) | (!q & <>X))) */ + NotNode notQ = new NotNode<>(new AtomicNode<>("q")); + NotNode notP = new NotNode<>(new AtomicNode<>("p")); + AndNode notPAndNotQ = new AndNode<>(notP, notQ); + AndNode innerAnd = new AndNode<>(notQ, new DiamondNode<>(new VariableNode<>("Z0"))); + OrNode or = new OrNode<>(notPAndNotQ, innerAnd); + LfpNode lfpNode = new LfpNode<>("Z0", or); + NotNode expected = new NotNode<>(lfpNode); + equals("A(\"p\" W \"q\")", expected); + } + + @Test + void testEF() throws ParseException { + OrNode or = new OrNode<>(new AtomicNode<>("p"), new DiamondNode<>(new VariableNode<>("Z0"))); + LfpNode expected = new LfpNode<>("Z0", or); + equals("EF \"p\"", expected); + } + + @Test + void testEG() throws ParseException { + OrNode or = + new OrNode<>(new DiamondNode<>(new VariableNode<>("Z0")), new BoxNode<>(new FalseNode<>())); + GfpNode expected = new GfpNode<>("Z0", new AndNode<>(new AtomicNode<>("p"), or)); + equals("EG \"p\"", expected); + } + + @Test + void testEU() throws ParseException { + AndNode and = new AndNode<>(new AtomicNode<>("p"), new DiamondNode<>(new VariableNode<>("Z0"))); + LfpNode expected = new LfpNode<>("Z0", new OrNode<>(new TrueNode<>(), and)); + equals("E(\"p\" U true)", expected); + } + + @Test + void testEWU() throws ParseException { + AndNode and = new AndNode<>(new AtomicNode<>("p"), new DiamondNode<>(new VariableNode<>("Z0"))); + LfpNode lfp = new LfpNode<>("Z0", new OrNode<>(new AtomicNode<>("q"), and)); + OrNode or = + new OrNode<>(new DiamondNode<>(new VariableNode<>("Z1")), new BoxNode<>(new FalseNode<>())); + GfpNode gfp = new GfpNode<>("Z1", new AndNode<>(new AtomicNode<>("p"), or)); + equals("E(\"p\" W \"q\")", new OrNode<>(lfp, gfp)); + } + + private void equals(String inputFormula, FormulaNode expectedResult) throws ParseException { + FormulaNode ctlNode = M3CParser.parse(inputFormula); + Assert.assertEquals(expectedResult, transformer.toMuCalc(ctlNode)); + } +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/FormulaNodeToStringTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/FormulaNodeToStringTest.java new file mode 100644 index 0000000000..d7edc222e6 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/FormulaNodeToStringTest.java @@ -0,0 +1,57 @@ +/* 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.modelcheckers.m3c.formula.visitor; + +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class FormulaNodeToStringTest { + + @Test + void testBaseCases() throws ParseException { + // CTL + testCorrectness("true"); + testCorrectness("false"); + testCorrectness("!true"); + testCorrectness("\"a,b,c\""); + testCorrectness("AF true"); + testCorrectness("AG true"); + testCorrectness("A(false U true)"); + testCorrectness("A(false W true)"); + testCorrectness("EF true"); + testCorrectness("EG true"); + testCorrectness("E(false U true)"); + testCorrectness("E(false W true)"); + testCorrectness("true || false"); + testCorrectness("true && false"); + + // mu-calc + testCorrectness("mu X.(\"a\" || <>X)"); + testCorrectness("nu X.(\"a\" || <>X)"); + testCorrectness("mu X.(\"a\" || [b]X)"); + testCorrectness("nu X.(\"a\" || [b]X)"); + } + + private void testCorrectness(String formula) throws ParseException { + FormulaNode ast = M3CParser.parse(formula); + String astToString = ast.toString(); + FormulaNode backToAst = M3CParser.parse(astToString); + Assert.assertEquals(ast, backToAst); + } +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/NNFVisitorTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/NNFVisitorTest.java new file mode 100644 index 0000000000..ebf2b15a3b --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/formula/visitor/NNFVisitorTest.java @@ -0,0 +1,135 @@ +/* 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.modelcheckers.m3c.formula.visitor; + +import net.automatalib.modelcheckers.m3c.formula.AndNode; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.FalseNode; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.NotNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AGNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.GfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.VariableNode; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class NNFVisitorTest { + + @Test + void testBaseCases() throws ParseException { + NNFVisitor nnfVisitor = new NNFVisitor<>(); + + FormulaNode atomicNode = M3CParser.parse("! \"a\""); + FormulaNode nnfAtomicNode = nnfVisitor.transformToNNF(atomicNode); + Assert.assertEquals(atomicNode, nnfAtomicNode); + + FormulaNode trueNode = M3CParser.parse("! true"); + FormulaNode nnfTrueNode = nnfVisitor.transformToNNF(trueNode); + Assert.assertEquals(new FalseNode<>(), nnfTrueNode); + + FormulaNode falseNode = M3CParser.parse("! false"); + FormulaNode nnfFalseNode = nnfVisitor.transformToNNF(falseNode); + Assert.assertEquals(new TrueNode<>(), nnfFalseNode); + } + + @Test + void testGfp() throws ParseException { + FormulaNode gfpNode = M3CParser.parse("! (nu X.(false || X))"); + FormulaNode nnfGfpNode = gfpNode.toNNF(); + + /* Create (mu X.(true & X) */ + LfpNode lfpNode = new LfpNode<>("X", new AndNode<>(new TrueNode<>(), new VariableNode<>("X"))); + Assert.assertEquals(lfpNode, nnfGfpNode); + } + + @Test + void testLfp() throws ParseException { + FormulaNode lfpNode = M3CParser.parse("! (mu X.(false || !X))"); + FormulaNode nnfLfpNode = lfpNode.toNNF(); + + /* Create nu X.(true & !X) */ + GfpNode gfpNode = + new GfpNode<>("X", new AndNode<>(new TrueNode<>(), new NotNode<>(new VariableNode<>("X")))); + Assert.assertEquals(gfpNode, nnfLfpNode); + } + + @Test + void testAnd() throws ParseException { + FormulaNode andNode = M3CParser.parse("!(<> false && true)"); + FormulaNode nnfAndNode = andNode.toNNF(); + + /* Create ([]true | false) */ + OrNode orNode = new OrNode<>(new BoxNode<>(new TrueNode<>()), new FalseNode<>()); + Assert.assertEquals(orNode, nnfAndNode); + } + + @Test + void testOr() throws ParseException { + FormulaNode orNode = M3CParser.parse("!([a] false || true)"); + FormulaNode nnfOrNode = orNode.toNNF(); + + /* Create ( true & false) */ + AndNode andNode = new AndNode<>(new DiamondNode<>("a", new TrueNode<>()), new FalseNode<>()); + Assert.assertEquals(andNode, nnfOrNode); + } + + @Test + void testBoxNode() throws ParseException { + FormulaNode boxNode = M3CParser.parse("![a]true"); + FormulaNode nnfBoxNode = boxNode.toNNF(); + + /* Create (false)*/ + DiamondNode diamondNode = new DiamondNode<>("a", new FalseNode<>()); + Assert.assertEquals(diamondNode, nnfBoxNode); + } + + @Test + void testDiamondNode() throws ParseException { + FormulaNode diamondNode = M3CParser.parse("!false"); + FormulaNode nnfDiamondNode = diamondNode.toNNF(); + + /* Create ([a] true) */ + BoxNode boxNode = new BoxNode<>("a", new TrueNode<>()); + Assert.assertEquals(boxNode, nnfDiamondNode); + } + + @Test + void testDefaultExample() throws ParseException { + FormulaNode ast = M3CParser.parse("!(mu X.(true || <>X))"); + FormulaNode nnfAst = ast.toNNF(); + + /* Create nu X.([b][b]false & []X)*/ + GfpNode gfpNode = new GfpNode<>("X", + new AndNode<>(new BoxNode<>("b", + new BoxNode<>("b", + new FalseNode<>())), + new BoxNode<>(new VariableNode<>("X")))); + Assert.assertEquals(gfpNode, nnfAst); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + void testError() { + FormulaNode ast = new AGNode<>(new TrueNode<>()); + ast.toNNF(); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/AbstractSolverHistoryTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/AbstractSolverHistoryTest.java new file mode 100644 index 0000000000..66e67ccea6 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/AbstractSolverHistoryTest.java @@ -0,0 +1,194 @@ +/* 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.modelcheckers.m3c.solver; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.graphs.ProceduralModalProcessGraph; +import net.automatalib.graphs.concepts.NodeIDs; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import net.automatalib.modelcheckers.m3c.transformer.AbstractPropertyTransformer; +import net.automatalib.modelcheckers.m3c.transformer.TransformerSerializer; +import net.automatalib.modelcheckers.m3c.util.Examples; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +public abstract class AbstractSolverHistoryTest> { + + protected final ContextFreeModalProcessSystem cfmps; + protected TransformerSerializer serializer; + + public AbstractSolverHistoryTest() { + this.cfmps = Examples.getCfmpsAnBn(Collections.emptySet()); + } + + @AfterClass + public void after() { + shutdownDDManager(); + } + + public abstract AbstractDDSolver getSolver(); + + public abstract void testInitialPropertyTransformers(SolverData data, N s1, N s2); + + public abstract void testMustTransformers(SolverHistory history); + + public abstract void shutdownDDManager(); + + @Test + public void testSolverHistory() throws ParseException { + final AbstractDDSolver solver = getSolver(); + final FormulaNode formula = M3CParser.parse("mu X.(true || <>X)"); + final SolverHistory history = solver.solveAndRecordHistory(formula); + final Map> data = history.getData(); + + Assert.assertEquals(data.size(), 1); + + final SolverData solverData = data.get("P"); + + Assert.assertNotNull(solverData); + testSolverHistory(history, solverData); + } + + private void testSolverHistory(SolverHistory history, + SolverData data) { + final ProceduralModalProcessGraph pmpg = data.getPmpg(); + final N initialNode = pmpg.getInitialNode(); + final N s1 = getS1(pmpg); + final N s2 = getS2(pmpg, s1); + + testNodeIDs(data); + testInitialPropertyTransformers(data, s1, s2); + testInitialSatisifedSubformulas(data, s1, s2); + testMustTransformers(history); + testSolverStates(history, pmpg, initialNode, s1, s2); + + Assert.assertTrue(history.getMayTransformers(serializer).isEmpty()); + Assert.assertTrue(history.isSat()); + } + + private void testSolverStates(SolverHistory history, + ProceduralModalProcessGraph pmpg, + N initialNode, + N s1, + N s2) { + final List updatedOrder = + Arrays.asList(initialNode, s1, initialNode, s2, s1, initialNode, s1, initialNode, s1, initialNode, s1); + Assert.assertEquals(history.getSolverStates().size(), updatedOrder.size()); + List> workSets = getWorkSetHistory(initialNode, s1, s2); + boolean[] allAPDeadlockedNode = new boolean[5]; + allAPDeadlockedNode[3] = true; + for (int i = 0; i < updatedOrder.size(); i++) { + final N expectedNode = updatedOrder.get(i); + final SolverState solverState = history.getSolverStates().get(i); + @SuppressWarnings("unchecked") + final N actualNode = (N) solverState.getUpdatedNode(); + Assert.assertEquals(actualNode, expectedNode); + Assert.assertEquals(pmpg.getOutgoingEdges(actualNode).size(), + solverState.getCompositions(serializer).size()); + Assert.assertEquals(solverState.getUpdatedNodePMPG(), cfmps.getMainProcess()); + Assert.assertEquals(solverState.getWorkSet().get(cfmps.getMainProcess()), workSets.get(i)); + testSatisfiedSubformulasAndUpdatedPT(allAPDeadlockedNode, solverState); + } + } + + protected void testNodeIDs(SolverData data) { + + final ProceduralModalProcessGraph pmpg = data.getPmpg(); + final NodeIDs nodeIDs = data.getNodeIDs(); + + // check that nodeIDs contains a mapping for each node in pmpg + for (final N node : pmpg.getNodes()) { + nodeIDs.getNodeId(node); + } + } + + protected void testInitialSatisifedSubformulas(SolverData data, N s1, N s2) { + + final ProceduralModalProcessGraph pmpg = data.getPmpg(); + final Mapping>> initialSatisfiedSubformulas = + data.getInitialSatisfiedSubformulas(); + + Assert.assertTrue(initialSatisfiedSubformulas.get(pmpg.getInitialNode()).isEmpty()); + Assert.assertTrue(initialSatisfiedSubformulas.get(s1).isEmpty()); + Assert.assertTrue(initialSatisfiedSubformulas.get(s2).isEmpty()); + + final List> finalNodeSatisfiedSubformulas = + initialSatisfiedSubformulas.get(pmpg.getFinalNode()); + Assert.assertEquals(finalNodeSatisfiedSubformulas.size(), 1); + Assert.assertTrue(finalNodeSatisfiedSubformulas.get(0) instanceof TrueNode); + } + + public void testSatisfiedSubformulasAndUpdatedPT(boolean[] allAPDeadlockedNode, + SolverState solverState) { + final Set actualSatisfiedSubformulas = solverState.getUpdatedNodeSatisfiedSubformula() + .stream() + .map(FormulaNode::getVarNumber) + .collect(Collectors.toSet()); + final T updatedPropertyTransformer = solverState.getUpdatedPropTransformer(serializer); + Set expectedSatisfiedSubformulas = updatedPropertyTransformer.evaluate(allAPDeadlockedNode); + Assert.assertEquals(actualSatisfiedSubformulas, expectedSatisfiedSubformulas); + } + + protected List> getWorkSetHistory(N initialNode, N s1, N s2) { + final Set workSetOnlyS1 = Collections.singleton(s1); + final Set workSetOnlyInitialNode = Collections.singleton(initialNode); + + return Arrays.asList(new HashSet<>(Arrays.asList(s1, s2)), + new HashSet<>(Arrays.asList(initialNode, s2)), + Collections.singleton(s2), + workSetOnlyS1, + workSetOnlyInitialNode, + workSetOnlyS1, + workSetOnlyInitialNode, + workSetOnlyS1, + workSetOnlyInitialNode, + workSetOnlyS1, + Collections.emptySet()); + } + + protected N getS1(ProceduralModalProcessGraph pmpg) { + final N initalNode = pmpg.getInitialNode(); + // the initial node is connected to s1 by an "a" labeled edge + for (final E edge : pmpg.getOutgoingEdges(initalNode)) { + if ("a".equals(pmpg.getEdgeLabel(edge))) { + return pmpg.getTarget(edge); + } + } + throw new IllegalStateException("unexpected modal process graph"); + } + + protected N getS2(ProceduralModalProcessGraph pmpg, N s1) { + // s1's only adjacent target is s2 + for (final N adjacentTarget : pmpg.getAdjacentTargets(s1)) { + return adjacentTarget; + } + throw new IllegalStateException("unexpected modal process graph"); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/AbstractSolverTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/AbstractSolverTest.java new file mode 100644 index 0000000000..61c49cc567 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/AbstractSolverTest.java @@ -0,0 +1,112 @@ +/* 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.modelcheckers.m3c.solver; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.graphs.ProceduralModalProcessGraph; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import net.automatalib.modelcheckers.m3c.transformer.AbstractPropertyTransformer; +import net.automatalib.modelcheckers.m3c.util.Examples; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.testng.Assert; +import org.testng.annotations.Test; + +public abstract class AbstractSolverTest> { + + @Test + void testSolve() throws ParseException { + final M3CSolver solver = getSolver(Examples.getCfmpsAnBn(Collections.emptySet())); + + final String formula = "mu X.(true || <>X)"; + assertSolve(solver, formula, true); + + final String negatedFormula = "!(" + formula + ")"; + assertSolve(solver, negatedFormula, false); + + // use !'a' to simulate true, as no node satisfies 'a' + final String formulaWithNegatedAP = "mu X.(!'a' || <>X)"; + assertSolve(solver, formulaWithNegatedAP, true); + } + + @Test + void testSolveWithSingleAP() throws ParseException { + final ContextFreeModalProcessSystem cfmps = Examples.getCfmpsAnBn(Collections.singleton("a")); + final M3CSolver solver = getSolver(cfmps); + final String formula = "mu X.(<>X || 'a,b')"; + + assertSolve(solver, formula, false); + } + + @Test + void testSolveWithMultipleAPs() throws ParseException { + final ContextFreeModalProcessSystem cfmps = + Examples.getCfmpsAnBn(new HashSet<>(Arrays.asList("a", "b"))); + final M3CSolver solver = getSolver(cfmps); + + final String formula = "mu X.(<>X || 'a' && 'b')"; + assertSolve(solver, formula, true); + + final String formulaWithNegatedAP = "mu X.(<>X || !('a' && 'b'))"; + assertSolve(solver, formulaWithNegatedAP, true); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + void testSolveWithInvalidMainProcess() { + ContextFreeModalProcessSystem cfmps = new ContextFreeModalProcessSystem() { + + @Override + public Map> getPMPGs() { + return new HashMap<>(); + } + + @Override + public @Nullable String getMainProcess() { + return "P"; + } + }; + getSolver(cfmps); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + void testSolveWithNoMainProcess() { + ContextFreeModalProcessSystem cfmps = new ContextFreeModalProcessSystem() { + + @Override + public Map> getPMPGs() { + return new HashMap<>(); + } + + @Override + public @Nullable String getMainProcess() { + return null; + } + }; + getSolver(cfmps); + } + + public abstract M3CSolver getSolver(ContextFreeModalProcessSystem cfmps); + + protected

void assertSolve(M3CSolver

solver, P property, boolean expectedIsSat) throws ParseException { + Assert.assertEquals(solver.solve(property), expectedIsSat); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/ExternalSystemDeserializer.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/ExternalSystemDeserializer.java new file mode 100644 index 0000000000..9a1fd36a18 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/ExternalSystemDeserializer.java @@ -0,0 +1,142 @@ +/* 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.modelcheckers.m3c.solver; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import com.google.common.collect.Maps; +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.graphs.MutableProceduralModalProcessGraph; +import net.automatalib.graphs.base.DefaultMCFPS; +import net.automatalib.graphs.base.compact.CompactPMPG; +import net.automatalib.ts.modal.transition.ModalEdgeProperty.ModalType; +import net.automatalib.ts.modal.transition.MutableProceduralModalEdgeProperty; +import net.automatalib.ts.modal.transition.ProceduralModalEdgeProperty.ProceduralType; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +final class ExternalSystemDeserializer { + + private ExternalSystemDeserializer() { + // prevent instantiation + } + + static ContextFreeModalProcessSystem parse(InputStream is) + throws ParserConfigurationException, IOException, SAXException { + + final Element root = getRoot(is); + final NodeList procedures = root.getElementsByTagName("pmpg"); + final Map> pmpgs = + Maps.newLinkedHashMapWithExpectedSize(procedures.getLength()); + + for (int i = 0; i < procedures.getLength(); i++) { + final Element procedure = (Element) procedures.item(i); + final String id = getFirstElementByTagName(procedure, "id").getTextContent(); + + final Map idToNode = new HashMap<>(); + final CompactPMPG pmpg = new CompactPMPG<>(""); + + final Element statesElement = getFirstElementByTagName(procedure, "states"); + final NodeList states = statesElement.getElementsByTagName("state"); + for (int j = 0; j < states.getLength(); j++) { + final Element state = (Element) states.item(j); + addNode(pmpg, state, idToNode); + } + + final Element transitionsElement = getFirstElementByTagName(procedure, "transitions"); + final NodeList transitions = transitionsElement.getElementsByTagName("transition"); + for (int j = 0; j < transitions.getLength(); j++) { + final Element transition = (Element) transitions.item(j); + addEdge(pmpg, transition, idToNode); + } + + pmpgs.put(id, pmpg); + } + + final String initialId = pmpgs.keySet().iterator().next(); + return new DefaultMCFPS<>(initialId, pmpgs); + } + + private static Element getRoot(InputStream is) throws ParserConfigurationException, IOException, SAXException { + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + final DocumentBuilder builder = factory.newDocumentBuilder(); + final Document document = builder.parse(is); + return document.getDocumentElement(); + } + + private static Element getFirstElementByTagName(Element elem, String tagName) { + final Node node = elem.getElementsByTagName(tagName).item(0); + assert node != null; + return (Element) node; + } + + private static boolean getBooleanAttributeByTagName(Element elem, String tagName) { + final Element attributes = (Element) elem.getElementsByTagName("attributes").item(0); + + if (attributes == null) { + return false; + } + + final Node node = attributes.getElementsByTagName(tagName).item(0); + return node != null && Boolean.parseBoolean(node.getTextContent()); + } + + private static void addNode(MutableProceduralModalProcessGraph pmpg, + Element state, + Map idToNode) { + + final String id = getFirstElementByTagName(state, "id").getTextContent(); + boolean isInitial = getBooleanAttributeByTagName(state, "isInitial"); + + final N node = pmpg.addNode(Collections.emptySet()); + + if (isInitial) { + pmpg.setInitialNode(node); + } else if ("end".equals(id)) { + pmpg.setFinalNode(node); + } + + idToNode.put(id, node); + } + + private static void addEdge(MutableProceduralModalProcessGraph pmpg, + Element transition, + Map idToNode) { + final String sourceId = getFirstElementByTagName(transition, "sourceId").getTextContent(); + final String targetId = getFirstElementByTagName(transition, "targetId").getTextContent(); + final String label = getFirstElementByTagName(transition, "label").getTextContent(); + + final boolean isMust = getBooleanAttributeByTagName(transition, "isMust"); + final boolean isProcedural = getBooleanAttributeByTagName(transition, "isProcedural"); + + final E edge = pmpg.connect(idToNode.get(sourceId), idToNode.get(targetId)); + pmpg.getEdgeProperty(edge).setProceduralType(isProcedural ? ProceduralType.PROCESS : ProceduralType.INTERNAL); + pmpg.getEdgeProperty(edge).setModalType(isMust ? ModalType.MUST : ModalType.MAY); + pmpg.setEdgeLabel(edge, label); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/ExternalSystemTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/ExternalSystemTest.java new file mode 100755 index 0000000000..a6ef5d19aa --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/ExternalSystemTest.java @@ -0,0 +1,150 @@ +/* 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.modelcheckers.m3c.solver; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.util.function.Function; + +import javax.xml.parsers.ParserConfigurationException; + +import net.automatalib.commons.util.IOUtil; +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import org.xml.sax.SAXException; + +/** + * Test for a set of external systems that have been model-checked externally. Used to assert our model-checker behaves + * similarly. + */ +public class ExternalSystemTest { + + private final Function, M3CSolver> solverProvider; + + @Factory(dataProvider = "solvers") + public ExternalSystemTest(Function, M3CSolver> solverProvider) { + this.solverProvider = solverProvider; + } + + @DataProvider + public static Object[] solvers() { + Function, M3CSolver> addSolver = M3CSolvers::addSolver; + Function, M3CSolver> bddSolver = M3CSolvers::bddSolver; + return new Function[] {addSolver, bddSolver}; + } + + @Test + public void testSetting1System1() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting1/system1/"); + } + + @Test + public void testSetting1System2() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting1/system2/"); + } + + @Test + public void testSetting1System3() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting1/system3/"); + } + + @Test + public void testSetting2System1() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system1/"); + } + + @Test + public void testSetting2System2() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system2/"); + } + + @Test + public void testSetting2System3() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system3/"); + } + + @Test + public void testSetting2System4() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system4/"); + } + + @Test + public void testSetting2System5() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system5/"); + } + + @Test + public void testSetting2System6() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system6/"); + } + + @Test + public void testSetting2System7() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system7/"); + } + + @Test + public void testSetting2System8() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system8/"); + } + + @Test + public void testSetting2System9() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/setting2/system9/"); + } + + @Test + public void testPalindrome() throws IOException, ParserConfigurationException, SAXException, ParseException { + testBenchmark("/cfmps/palindrome/"); + } + + private void testBenchmark(String id) + throws IOException, ParserConfigurationException, SAXException, ParseException { + + try (InputStream seed = ExternalSystemTest.class.getResourceAsStream(id + "seed.xml"); + InputStream properties = ExternalSystemTest.class.getResourceAsStream(id + "properties.txt"); + InputStream solutions = ExternalSystemTest.class.getResourceAsStream(id + "solutions.txt")) { + + final ContextFreeModalProcessSystem cfmps = ExternalSystemDeserializer.parse(seed); + final M3CSolver solver = this.solverProvider.apply(cfmps); + + try (BufferedReader propertiesReader = new BufferedReader(IOUtil.asUTF8Reader(properties)); + BufferedReader solutionsReader = new BufferedReader(IOUtil.asUTF8Reader(solutions))) { + + String prop = propertiesReader.readLine(); + String sol = solutionsReader.readLine(); + + while (prop != null || sol != null) { + Assert.assertNotNull(prop, "Unequal number of properties and solutions"); + Assert.assertNotNull(sol, "Unequal number of properties and solutions"); + + Assert.assertEquals(solver.solve(prop), + Boolean.parseBoolean(sol), + "Error solving: \"" + prop + "\" with " + solver); + + prop = propertiesReader.readLine(); + sol = solutionsReader.readLine(); + } + } + } + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverADDTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverADDTest.java new file mode 100644 index 0000000000..71099920ab --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverADDTest.java @@ -0,0 +1,27 @@ +/* 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.modelcheckers.m3c.solver; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.transformer.ADDTransformer; + +public class SolverADDTest extends AbstractSolverTest> { + + public M3CSolver getSolver(ContextFreeModalProcessSystem cfmps) { + return M3CSolvers.addSolver(cfmps); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverBDDTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverBDDTest.java new file mode 100644 index 0000000000..91df6cbf09 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverBDDTest.java @@ -0,0 +1,27 @@ +/* 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.modelcheckers.m3c.solver; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.modelcheckers.m3c.transformer.BDDTransformer; + +public class SolverBDDTest extends AbstractSolverTest> { + + public M3CSolver getSolver(ContextFreeModalProcessSystem cfmps) { + return M3CSolvers.bddSolver(cfmps); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverHistoryADDTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverHistoryADDTest.java new file mode 100644 index 0000000000..6f727fdac6 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverHistoryADDTest.java @@ -0,0 +1,121 @@ +/* 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.modelcheckers.m3c.solver; + +import java.util.Map; +import java.util.Set; + +import info.scce.addlib.dd.xdd.XDD; +import info.scce.addlib.dd.xdd.XDDManager; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVector; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVectorLogicDDManager; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.graphs.ProceduralModalProcessGraph; +import net.automatalib.modelcheckers.m3c.transformer.ADDTransformer; +import net.automatalib.modelcheckers.m3c.transformer.ADDTransformerSerializer; +import org.testng.Assert; + +public class SolverHistoryADDTest extends AbstractSolverHistoryTest> { + + private final int numSubformulas; + private final XDDManager xddManager; + + public SolverHistoryADDTest() { + this.numSubformulas = 5; + this.xddManager = new BooleanVectorLogicDDManager(numSubformulas); + this.serializer = new ADDTransformerSerializer<>(xddManager); + } + + @Override + public void shutdownDDManager() { + xddManager.quit(); + } + + @Override + public AbstractDDSolver, String, String> getSolver() { + return new ADDSolver<>(cfmps); + } + + @Override + public void testInitialPropertyTransformers(SolverData, String, String> data, + N s1, + N s2) { + + final ProceduralModalProcessGraph pmpg = data.getPmpg(); + final Mapping> initialPropertyTransformers = + data.getInitialPropertyTransformers(serializer); + + final ADDTransformer startPT = initialPropertyTransformers.get(pmpg.getInitialNode()); + final ADDTransformer endPT = initialPropertyTransformers.get(pmpg.getFinalNode()); + final ADDTransformer s1PT = initialPropertyTransformers.get(s1); + final ADDTransformer s2PT = initialPropertyTransformers.get(s2); + + // the PTs of start, s1 and s2 are initialized with an array of zero BDDs + Assert.assertEquals(startPT, s1PT); + Assert.assertEquals(startPT, s2PT); + Assert.assertEquals(s1PT, s2PT); + XDD startDD = startPT.getAdd(); + Assert.assertNotNull(startDD); + Assert.assertTrue(startDD.isConstant()); + Assert.assertEquals(startDD.v().data(), new boolean[numSubformulas]); + + // the end node PT is initialized with the identity function + Assert.assertTrue(endPT.isIdentity()); + } + + @Override + public void testMustTransformers(SolverHistory, String, String> history) { + final Map> mustTransformers = history.getMustTransformers(serializer); + Assert.assertEquals(mustTransformers.size(), 3); + final ADDTransformer aPT = mustTransformers.get("a"); + final ADDTransformer bPT = mustTransformers.get("b"); + final ADDTransformer ePT = mustTransformers.get("e"); + Assert.assertEquals(aPT, ePT); + Assert.assertNotEquals(aPT, bPT); + + for (int i = 0; i < Math.pow(2, numSubformulas); i++) { + String binaryString = String.format("%05d", Integer.parseInt(Integer.toBinaryString(i))); + boolean[] input = new boolean[numSubformulas]; + input[0] = binaryString.charAt(0) == '1'; + input[1] = binaryString.charAt(1) == '1'; + input[2] = binaryString.charAt(2) == '1'; + input[3] = binaryString.charAt(3) == '1'; + input[4] = binaryString.charAt(4) == '1'; + Set aSatVarNumbers = aPT.evaluate(input); + boolean[] aResult = new boolean[numSubformulas]; + for (int j = 0; j < numSubformulas; j++) { + aResult[j] = aSatVarNumbers.contains(j); + } + Assert.assertEquals(aResult[4], input[0]); + Assert.assertFalse(aResult[0]); + Assert.assertFalse(aResult[1]); + Assert.assertFalse(aResult[2]); + Assert.assertFalse(aResult[3]); + + Set bSatVarNumbers = bPT.evaluate(input); + boolean[] bResult = new boolean[numSubformulas]; + for (int j = 0; j < numSubformulas; j++) { + bResult[j] = bSatVarNumbers.contains(j); + } + Assert.assertEquals(bResult[1], input[2]); + Assert.assertEquals(bResult[2], input[3]); + Assert.assertEquals(bResult[4], input[0]); + Assert.assertFalse(bResult[0]); + Assert.assertFalse(bResult[3]); + } + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverHistoryBDDTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverHistoryBDDTest.java new file mode 100644 index 0000000000..5a0e7c601c --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/solver/SolverHistoryBDDTest.java @@ -0,0 +1,109 @@ +/* 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.modelcheckers.m3c.solver; + +import java.util.Map; + +import info.scce.addlib.dd.bdd.BDD; +import info.scce.addlib.dd.bdd.BDDManager; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.graphs.ProceduralModalProcessGraph; +import net.automatalib.modelcheckers.m3c.transformer.BDDTransformer; +import net.automatalib.modelcheckers.m3c.transformer.BDDTransformerSerializer; +import org.testng.Assert; + +public class SolverHistoryBDDTest extends AbstractSolverHistoryTest> { + + private final BDDManager bddManager; + + public SolverHistoryBDDTest() { + this.bddManager = new BDDManager(); + this.serializer = new BDDTransformerSerializer<>(bddManager); + } + + @Override + public AbstractDDSolver, String, String> getSolver() { + return new BDDSolver<>(cfmps); + } + + @Override + public void shutdownDDManager() { + bddManager.quit(); + } + + @Override + public void testInitialPropertyTransformers(SolverData, String, String> data, + N s1, + N s2) { + + final ProceduralModalProcessGraph pmpg = data.getPmpg(); + final Mapping> initialPropertyTransformers = + data.getInitialPropertyTransformers(serializer); + + final BDDTransformer startPT = initialPropertyTransformers.get(pmpg.getInitialNode()); + final BDDTransformer endPT = initialPropertyTransformers.get(pmpg.getFinalNode()); + final BDDTransformer s1PT = initialPropertyTransformers.get(s1); + final BDDTransformer s2PT = initialPropertyTransformers.get(s2); + + // the PTs of start, s1 and s2 are initialized with an array of zero BDDs + Assert.assertEquals(startPT, s1PT); + Assert.assertEquals(startPT, s2PT); + Assert.assertEquals(s1PT, s2PT); + // the end node PT is initialized with the identity function + Assert.assertNotEquals(startPT, endPT); + + final BDD zeroDD = bddManager.readLogicZero(); + for (int i = 0; i < startPT.getNumberOfVars(); i++) { + Assert.assertEquals(startPT.getBDD(i), zeroDD); + } + for (int i = 0; i < endPT.getNumberOfVars(); i++) { + BDD ithDD = endPT.getBDD(i); + Assert.assertEquals(ithDD, bddManager.ithVar(i)); + } + } + + @Override + public void testMustTransformers(SolverHistory, String, String> history) { + final Map> mustTransformers = history.getMustTransformers(serializer); + Assert.assertEquals(mustTransformers.size(), 3); + final BDDTransformer aPT = mustTransformers.get("a"); + final BDDTransformer bPT = mustTransformers.get("b"); + final BDDTransformer ePT = mustTransformers.get("e"); + Assert.assertEquals(aPT, ePT); + Assert.assertNotEquals(aPT, bPT); + + for (int i = 0; i < aPT.getNumberOfVars(); i++) { + final BDD aDD = aPT.getBDD(i); + if (i == 4) { + Assert.assertEquals(aDD, bddManager.ithVar(0)); + } else { + Assert.assertEquals(aDD, bddManager.readLogicZero()); + } + } + + for (int i = 0; i < bPT.getNumberOfVars(); i++) { + final BDD bDD = bPT.getBDD(i); + if (i == 1 || i == 2) { + Assert.assertEquals(bDD, bddManager.ithVar(i + 1)); + } else if (i == 4) { + Assert.assertEquals(bDD, bddManager.ithVar(0)); + } else { + Assert.assertEquals(bDD, bddManager.readLogicZero()); + } + } + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformerTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformerTest.java new file mode 100644 index 0000000000..982341c694 --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/transformer/ADDTransformerTest.java @@ -0,0 +1,267 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.BitSet; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import info.scce.addlib.dd.xdd.XDD; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVector; +import info.scce.addlib.dd.xdd.latticedd.example.BooleanVectorLogicDDManager; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DependencyGraph; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.EquationalBlock; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AGNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import net.automatalib.ts.modal.transition.ModalEdgeProperty; +import net.automatalib.ts.modal.transition.ModalEdgePropertyImpl; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class ADDTransformerTest { + + private static DependencyGraph dg; + private static BooleanVectorLogicDDManager xddManager; + private static OrNode orNode; + private static DiamondNode diaNode1; + private static DiamondNode diaNode2; + private static BoxNode boxNode; + private static TrueNode trueNode; + + @BeforeClass + public static void setup() throws ParseException { + String formula = "mu X.([b]true || <>X)"; + dg = new DependencyGraph<>(M3CParser.parse(formula)); + xddManager = new BooleanVectorLogicDDManager(dg.getNumVariables()); + final LfpNode gfpNode = (LfpNode) dg.getAST(); + orNode = (OrNode) gfpNode.getChild(); + diaNode1 = (DiamondNode) orNode.getLeftChild(); + diaNode2 = (DiamondNode) orNode.getRightChild(); + boxNode = (BoxNode) diaNode1.getChild(); + trueNode = (TrueNode) boxNode.getChild(); + } + + @Test + void testADDIdentity() { + ADDTransformer transformer = new ADDTransformer<>(xddManager); + double numVarCombinations = Math.pow(2, dg.getNumVariables()); + + /* Check output of each possible input */ + for (int i = 0; i < numVarCombinations; i++) { + + /* Construct boolean input vector from BitSet */ + BitSet bs = BitSet.valueOf(new long[] {i}); + boolean[] input = new boolean[dg.getNumVariables()]; + for (int idx = 0; idx < dg.getNumVariables(); idx++) { + input[idx] = bs.get(idx); + } + + /* Test correctness of identity by checking if input equals output */ + Set satisfiedVars = transformer.evaluate(input); + for (int idx = 0; i < input.length; i++) { + if (input[idx]) { + Assert.assertTrue(satisfiedVars.contains(idx)); + } + if (satisfiedVars.contains(idx)) { + Assert.assertTrue(input[idx]); + } + } + } + } + + @Test + void testADDNodeInitialization() { + ADDTransformer transformer = new ADDTransformer<>(xddManager, dg); + XDD add = transformer.getAdd(); + Assert.assertNotNull(add); + Assert.assertTrue(add.isConstant()); + boolean[] leafData = add.v().data(); + for (EquationalBlock block : dg.getBlocks()) { + for (FormulaNode node : block.getNodes()) { + boolean val = leafData[node.getVarNumber()]; + boolean isMaxBlock = block.isMaxBlock(); + Assert.assertEquals(isMaxBlock, val); + } + } + } + + @Test + void testEdgeTransformerMust() { + ADDTransformer transformer = + new ADDTransformer<>(xddManager, "b", new ModalEdgePropertyImpl(ModalEdgeProperty.ModalType.MUST), dg); + double numVarCombinations = Math.pow(2, dg.getNumVariables()); + + for (int i = 0; i < numVarCombinations; i++) { + + /* Construct boolean input vector from BitSet */ + BitSet bs = BitSet.valueOf(new long[] {i}); + boolean[] input = new boolean[dg.getNumVariables()]; + for (int idx = 0; idx < dg.getNumVariables(); idx++) { + input[idx] = bs.get(idx); + } + + Set satisfiedVars = transformer.evaluate(input); + Assert.assertFalse(satisfiedVars.contains(orNode.getVarNumber())); + + boolean diaNode1ExpectedTrue = input[diaNode1.getVarNumberChild()]; + boolean diaNode1ActualTrue = satisfiedVars.contains(diaNode1.getVarNumber()); + Assert.assertEquals(diaNode1ExpectedTrue, diaNode1ActualTrue); + + boolean diaNode2ExpectedTrue = input[diaNode2.getVarNumberChild()]; + boolean diaNode2ActualTrue = satisfiedVars.contains(diaNode2.getVarNumber()); + Assert.assertEquals(diaNode2ExpectedTrue, diaNode2ActualTrue); + + boolean boxNodeExpectedTrue = input[boxNode.getVarNumberChild()]; + boolean boxNodeActualTrue = satisfiedVars.contains(boxNode.getVarNumber()); + Assert.assertEquals(boxNodeExpectedTrue, boxNodeActualTrue); + + Assert.assertFalse(satisfiedVars.contains(trueNode.getVarNumber())); + } + } + + @Test + void testEdgeTransformerNoMatch() { + ADDTransformer transformer = + new ADDTransformer<>(xddManager, "a", new ModalEdgePropertyImpl(ModalEdgeProperty.ModalType.MUST), dg); + double numVarCombinations = Math.pow(2, dg.getNumVariables()); + for (int i = 0; i < numVarCombinations; i++) { + + /* Construct boolean input vector from BitSet */ + BitSet bs = BitSet.valueOf(new long[] {i}); + boolean[] input = new boolean[dg.getNumVariables()]; + for (int idx = 0; idx < dg.getNumVariables(); idx++) { + input[idx] = bs.get(idx); + } + + Set satisfiedVars = transformer.evaluate(input); + Assert.assertFalse(satisfiedVars.contains(orNode.getVarNumber())); + + Assert.assertFalse(satisfiedVars.contains(diaNode1.getVarNumber())); + + boolean diaNode2ExpectedTrue = input[diaNode2.getVarNumberChild()]; + boolean diaNode2ActualTrue = satisfiedVars.contains(diaNode2.getVarNumber()); + Assert.assertEquals(diaNode2ExpectedTrue, diaNode2ActualTrue); + + Assert.assertTrue(satisfiedVars.contains(boxNode.getVarNumber())); + + Assert.assertFalse(satisfiedVars.contains(trueNode.getVarNumber())); + } + } + + @Test + void testEdgeTransformerMay() { + ADDTransformer transformer = + new ADDTransformer<>(xddManager, "b", new ModalEdgePropertyImpl(ModalEdgeProperty.ModalType.MAY), dg); + double numVarCombinations = Math.pow(2, dg.getNumVariables()); + for (int i = 0; i < numVarCombinations; i++) { + + /* Construct boolean input vector from BitSet */ + BitSet bs = BitSet.valueOf(new long[] {i}); + boolean[] input = new boolean[dg.getNumVariables()]; + for (int idx = 0; idx < dg.getNumVariables(); idx++) { + input[idx] = bs.get(idx); + } + + Set satisfiedVars = transformer.evaluate(input); + Assert.assertFalse(satisfiedVars.contains(orNode.getVarNumber())); + + Assert.assertFalse(satisfiedVars.contains(diaNode1.getVarNumber())); + + Assert.assertFalse(satisfiedVars.contains(diaNode2.getVarNumber())); + + boolean boxNodeExpectedTrue = input[boxNode.getVarNumberChild()]; + boolean boxNodeActualTrue = satisfiedVars.contains(boxNode.getVarNumber()); + Assert.assertEquals(boxNodeExpectedTrue, boxNodeActualTrue); + + Assert.assertFalse(satisfiedVars.contains(trueNode.getVarNumber())); + } + } + + @Test + void testComposition() { + ADDTransformer transformer = new ADDTransformer<>(xddManager, dg); + ADDTransformer identity = new ADDTransformer<>(xddManager); + ADDTransformer composition = transformer.compose(identity); + Assert.assertEquals(transformer, composition); + + ADDTransformer inverseComposition = identity.compose(transformer); + Assert.assertEquals(transformer, inverseComposition); + } + + @Test(expectedExceptions = IllegalStateException.class) + void testCompositionWithTwoIdentities() { + ADDTransformer identity = new ADDTransformer<>(xddManager); + ADDTransformer anotherIdentity = new ADDTransformer<>(xddManager); + identity.compose(anotherIdentity); + } + + @Test + void testUpdate() throws ParseException { + final String formulaWithNegatedAP = "mu X.(!'a' || <>X)"; + DependencyGraph dependencyGraph = new DependencyGraph<>(M3CParser.parse(formulaWithNegatedAP)); + ADDTransformer transformer = new ADDTransformer<>(xddManager, dependencyGraph); + Set atomicPropositions = new HashSet<>(); + atomicPropositions.add("a"); + ADDTransformer updatedTransformer = + transformer.createUpdate(atomicPropositions, Collections.emptyList(), dependencyGraph.getBlock(0)); + XDD add = updatedTransformer.getAdd(); + Assert.assertNotNull(add); + add.monadicApply(vector -> { + boolean[] result = vector.data(); + Assert.assertFalse(result[0]); + Assert.assertFalse(result[1]); + Assert.assertFalse(result[2]); + Assert.assertFalse(result[3]); + Assert.assertTrue(result[4]); + Assert.assertFalse(result[5]); + return new BooleanVector(result); + }); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + void testUpdateDeadlockException() throws ParseException { + final String formulaWithNegatedAP = "mu X.(!'a' || <>X)"; + DependencyGraph dependencyGraph = new DependencyGraph<>(M3CParser.parse(formulaWithNegatedAP)); + ADDTransformer transformer = new ADDTransformer<>(xddManager, dependencyGraph); + Set atomicPropositions = new HashSet<>(); + atomicPropositions.add("a"); + EquationalBlock block = new EquationalBlock<>(false); + block.addNode(new AGNode<>(new TrueNode<>())); + transformer.createUpdate(atomicPropositions, Collections.emptyList(), block); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + void testUpdateException() throws ParseException { + final String formulaWithNegatedAP = "mu X.(!'a' || <>X)"; + DependencyGraph dependencyGraph = new DependencyGraph<>(M3CParser.parse(formulaWithNegatedAP)); + ADDTransformer transformer = new ADDTransformer<>(xddManager, dependencyGraph); + Set atomicPropositions = new HashSet<>(); + atomicPropositions.add("a"); + EquationalBlock block = new EquationalBlock<>(false); + block.addNode(new AGNode<>(new TrueNode<>())); + transformer.createUpdate(atomicPropositions, Collections.singletonList(transformer), block); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformerTest.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformerTest.java new file mode 100644 index 0000000000..96a3a16a3b --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/transformer/BDDTransformerTest.java @@ -0,0 +1,228 @@ +/* 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.modelcheckers.m3c.transformer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import info.scce.addlib.dd.bdd.BDD; +import info.scce.addlib.dd.bdd.BDDManager; +import net.automatalib.modelcheckers.m3c.formula.BoxNode; +import net.automatalib.modelcheckers.m3c.formula.DependencyGraph; +import net.automatalib.modelcheckers.m3c.formula.DiamondNode; +import net.automatalib.modelcheckers.m3c.formula.EquationalBlock; +import net.automatalib.modelcheckers.m3c.formula.FormulaNode; +import net.automatalib.modelcheckers.m3c.formula.OrNode; +import net.automatalib.modelcheckers.m3c.formula.TrueNode; +import net.automatalib.modelcheckers.m3c.formula.ctl.AGNode; +import net.automatalib.modelcheckers.m3c.formula.modalmu.LfpNode; +import net.automatalib.modelcheckers.m3c.formula.parser.M3CParser; +import net.automatalib.modelcheckers.m3c.formula.parser.ParseException; +import net.automatalib.ts.modal.transition.ModalEdgeProperty.ModalType; +import net.automatalib.ts.modal.transition.ModalEdgePropertyImpl; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class BDDTransformerTest { + + private static DependencyGraph dg; + private static BDDManager bddManager; + private static OrNode orNode; + private static DiamondNode diaNode1; + private static DiamondNode diaNode2; + private static BoxNode boxNode; + private static TrueNode trueNode; + + @BeforeClass + public static void setup() throws ParseException { + final String formula = "mu X.([b]true || <>X)"; + dg = new DependencyGraph<>(M3CParser.parse(formula)); + bddManager = new BDDManager(); + final LfpNode gfpNode = (LfpNode) dg.getAST(); + orNode = (OrNode) gfpNode.getChild(); + diaNode1 = (DiamondNode) orNode.getLeftChild(); + diaNode2 = (DiamondNode) orNode.getRightChild(); + boxNode = (BoxNode) diaNode1.getChild(); + trueNode = (TrueNode) boxNode.getChild(); + } + + @Test + void testBDDIdentity() { + BDDTransformer transformer = new BDDTransformer<>(bddManager, dg.getNumVariables()); + for (int var = 0; var < transformer.getNumberOfVars(); var++) { + Assert.assertEquals(transformer.getBDD(var), bddManager.ithVar(var)); + } + } + + @Test + void testBDDNodeInitialization() { + BDDTransformer transformer = new BDDTransformer<>(bddManager, dg); + for (EquationalBlock block : dg.getBlocks()) { + for (FormulaNode node : block.getNodes()) { + BDD actual = transformer.getBDD(node.getVarNumber()); + BDD expected; + if (block.isMaxBlock()) { + expected = bddManager.readOne(); + } else { + expected = bddManager.readLogicZero(); + } + Assert.assertEquals(expected, actual); + } + } + } + + @Test + void testEdgeTransformerMust() { + BDDTransformer transformer = + new BDDTransformer<>(bddManager, "b", new ModalEdgePropertyImpl(ModalType.MUST), dg); + + BDD bddOrNode = transformer.getBDD(orNode.getVarNumber()); + BDD expectedBDDOrNode = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDOrNode, bddOrNode); + + BDD bddDiaNode1 = transformer.getBDD(diaNode1.getVarNumber()); + BDD expectedBDDDiaNode1 = bddManager.ithVar(diaNode1.getVarNumberChild()); + Assert.assertEquals(expectedBDDDiaNode1, bddDiaNode1); + + BDD bddDiaNode2 = transformer.getBDD(diaNode2.getVarNumber()); + BDD expectedBDDDiaNode2 = bddManager.ithVar(diaNode2.getVarNumberChild()); + Assert.assertEquals(expectedBDDDiaNode2, bddDiaNode2); + + BDD bddBoxNode = transformer.getBDD(boxNode.getVarNumber()); + BDD expectedBDDBoxNode = bddManager.ithVar(boxNode.getVarNumberChild()); + Assert.assertEquals(expectedBDDBoxNode, bddBoxNode); + + BDD bddTrueNode = transformer.getBDD(trueNode.getVarNumber()); + BDD expectedBDDTrueNode = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDTrueNode, bddTrueNode); + } + + @Test + void testEdgeTransformerNoMatch() { + BDDTransformer transformer = + new BDDTransformer<>(bddManager, "a", new ModalEdgePropertyImpl(ModalType.MUST), dg); + + BDD bddOrNode = transformer.getBDD(orNode.getVarNumber()); + BDD expectedBDDOrNode = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDOrNode, bddOrNode); + + BDD bddDiaNode1 = transformer.getBDD(diaNode1.getVarNumber()); + BDD expectedBDDDiaNode1 = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDDiaNode1, bddDiaNode1); + + BDD bddDiaNode2 = transformer.getBDD(diaNode2.getVarNumber()); + BDD expectedBDDDiaNode2 = bddManager.ithVar(diaNode2.getVarNumberChild()); + Assert.assertEquals(expectedBDDDiaNode2, bddDiaNode2); + + BDD bddBoxNode = transformer.getBDD(boxNode.getVarNumber()); + BDD expectedBDDBoxNode = bddManager.readOne(); + Assert.assertEquals(expectedBDDBoxNode, bddBoxNode); + + BDD bddTrueNode = transformer.getBDD(trueNode.getVarNumber()); + BDD expectedBDDTrueNode = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDTrueNode, bddTrueNode); + } + + @Test + void testEdgeTransformerMay() { + BDDTransformer transformer = + new BDDTransformer<>(bddManager, "b", new ModalEdgePropertyImpl(ModalType.MAY), dg); + + BDD bddOrNode = transformer.getBDD(orNode.getVarNumber()); + BDD expectedBDDOrNode = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDOrNode, bddOrNode); + + BDD bddDiaNode1 = transformer.getBDD(diaNode1.getVarNumber()); + BDD expectedBDDDiaNode1 = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDDiaNode1, bddDiaNode1); + + BDD bddDiaNode2 = transformer.getBDD(diaNode2.getVarNumber()); + BDD expectedBDDDiaNode2 = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDDiaNode2, bddDiaNode2); + + BDD bddBoxNode = transformer.getBDD(boxNode.getVarNumber()); + BDD expectedBDDBoxNode = bddManager.ithVar(boxNode.getVarNumberChild()); + Assert.assertEquals(expectedBDDBoxNode, bddBoxNode); + + BDD bddTrueNode = transformer.getBDD(trueNode.getVarNumber()); + BDD expectedBDDTrueNode = bddManager.readLogicZero(); + Assert.assertEquals(expectedBDDTrueNode, bddTrueNode); + } + + @Test + void testComposition() { + BDDTransformer transformer = new BDDTransformer<>(bddManager, dg); + BDDTransformer identity = new BDDTransformer<>(bddManager, dg.getNumVariables()); + BDDTransformer composition = transformer.compose(identity); + Assert.assertEquals(5, composition.getNumberOfVars()); + Assert.assertEquals(transformer, composition); + + BDDTransformer inverseComposition = identity.compose(transformer); + Assert.assertEquals(transformer, inverseComposition); + } + + @Test + void testOrBDDListOnes() { + BDDTransformer edgeTransformer = + new BDDTransformer<>(bddManager, "b", new ModalEdgePropertyImpl(ModalType.MUST), dg); + BDD[] oneBDDs = new BDD[dg.getNumVariables()]; + for (int var = 0; var < oneBDDs.length; var++) { + oneBDDs[var] = bddManager.readOne(); + } + BDDTransformer oneTransformer = new BDDTransformer<>(bddManager, oneBDDs); + + List> comps = new ArrayList<>(); + comps.add(edgeTransformer); + comps.add(oneTransformer); + + BDD disjunction = edgeTransformer.orBddList(comps, diaNode1.getVarNumber()); + Assert.assertEquals(bddManager.readOne(), disjunction); + } + + @Test + void testOrBDDListZeros() { + BDDTransformer edgeTransformer = + new BDDTransformer<>(bddManager, "b", new ModalEdgePropertyImpl(ModalType.MUST), dg); + BDD[] oneBDDs = new BDD[dg.getNumVariables()]; + for (int var = 0; var < oneBDDs.length; var++) { + oneBDDs[var] = bddManager.readLogicZero(); + } + BDDTransformer oneTransformer = new BDDTransformer<>(bddManager, oneBDDs); + + List> comps = new ArrayList<>(); + comps.add(edgeTransformer); + comps.add(oneTransformer); + BDD disjunction = edgeTransformer.orBddList(comps, diaNode1.getVarNumber()); + Assert.assertEquals(bddManager.ithVar(diaNode1.getVarNumberChild()), disjunction); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testUpdateException() throws ParseException { + final String formulaWithNegatedAP = "mu X.(!'a' || <>X)"; + DependencyGraph dependencyGraph = new DependencyGraph<>(M3CParser.parse(formulaWithNegatedAP)); + BDDTransformer transformer = new BDDTransformer<>(bddManager, dependencyGraph); + Set atomicPropositions = new HashSet<>(); + atomicPropositions.add("a"); + EquationalBlock block = new EquationalBlock<>(false); + block.addNode(new AGNode<>(new TrueNode<>())); + transformer.createUpdate(atomicPropositions, Collections.emptyList(), block); + } + +} diff --git a/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/util/Examples.java b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/util/Examples.java new file mode 100644 index 0000000000..a37051a25e --- /dev/null +++ b/modelchecking/m3c/src/test/java/net/automatalib/modelcheckers/m3c/util/Examples.java @@ -0,0 +1,69 @@ +/* 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.modelcheckers.m3c.util; + +import java.util.Collections; +import java.util.Set; + +import net.automatalib.graphs.ContextFreeModalProcessSystem; +import net.automatalib.graphs.MutableProceduralModalProcessGraph; +import net.automatalib.graphs.base.DefaultMCFPS; +import net.automatalib.graphs.base.compact.CompactPMPG; + +public final class Examples { + + private Examples() {} + + public static ContextFreeModalProcessSystem getCfmpsAnBn(Set finalNodesAP) { + final CompactPMPG pmpg = buildPMPG(new CompactPMPG<>(""), finalNodesAP); + return new DefaultMCFPS<>("P", Collections.singletonMap("P", pmpg)); + } + + private static > M buildPMPG(M pmpg, + Set finalNodeAPs) { + + final N start = pmpg.addNode(); + final N end = pmpg.addNode(); + final N s1 = pmpg.addNode(); + final N s2 = pmpg.addNode(); + + pmpg.setInitialNode(start); + pmpg.setFinalNode(end); + pmpg.setAtomicPropositions(s2, finalNodeAPs); + pmpg.setAtomicPropositions(end, finalNodeAPs); + + final E e1 = pmpg.connect(start, s1); + final E e2 = pmpg.connect(start, end); + final E e3 = pmpg.connect(s1, s2); + final E e4 = pmpg.connect(s2, end); + + pmpg.getEdgeProperty(e1).setMust(); + pmpg.setEdgeLabel(e1, "a"); + + pmpg.getEdgeProperty(e2).setMust(); + pmpg.setEdgeLabel(e2, "e"); + + pmpg.getEdgeProperty(e3).setMust(); + pmpg.getEdgeProperty(e3).setProcess(); + pmpg.setEdgeLabel(e3, "P"); + + pmpg.getEdgeProperty(e4).setMust(); + pmpg.setEdgeLabel(e4, "b"); + + return pmpg; + } + +} diff --git a/modelchecking/m3c/src/test/resources/cfmps/palindrome/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/palindrome/properties.txt new file mode 100644 index 0000000000..2a1a497e0e --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/palindrome/properties.txt @@ -0,0 +1,13 @@ +mu X.(<>X || true) +mu X.(<>X || true) +mu X.(<>X || true) +true +true +true +true +true +nu X. ([]X && [] false) +mu X. (<>X || [] false) +nu X. ([]X && mu Y. (<>Y || [] false)) +nu X. ([]X && (true -> (mu Y. (Y || true)))) +nu X. ([]X && (true -> [S](mu Y. (<>Y || true)))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/palindrome/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/palindrome/seed.xml new file mode 100755 index 0000000000..cf61c632af --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/palindrome/seed.xml @@ -0,0 +1,221 @@ + + + S + + + start + + true + + + + s0 + + + s1 + + + s2 + + + s3 + + + s4 + + + s5 + + + end + + + + + start + s0 + + + true + + + + s0 + end + + + true + + + + s0 + s1 + + + true + + + + s0 + s2 + + + true + + + + s0 + s5 + + + true + true + + + + s1 + end + + + true + + + + s1 + s3 + + + true + true + + + + s2 + end + + + true + + + + s2 + s4 + + + true + true + + + + s3 + s5 + + + true + + + + s4 + s5 + + + true + + + + s5 + end + + + true + + + + + + T + + + start + + true + + + + t0 + + + t1 + + + t2 + + + t3 + + + end + + + + + start + t0 + + + true + + + + t0 + t1 + + + true + + + + t0 + t3 + + + true + true + + + + t1 + end + + + true + + + + t1 + t2 + + + true + true + + + + t2 + t3 + + + true + + + + t3 + end + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/palindrome/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/palindrome/solutions.txt new file mode 100644 index 0000000000..b1cc9ee170 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/palindrome/solutions.txt @@ -0,0 +1,13 @@ +false +true +false +false +false +true +false +true +false +true +true +true +true \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/properties.txt new file mode 100755 index 0000000000..4fd18b5776 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/properties.txt @@ -0,0 +1,20 @@ +(A((( true) -> ((A(([c0_t13] false) W ( true))))) W (( true) || ( true)))) +(A(([c0_t1] false) W (( true) || ( true)))) +(AF(A(([c0_t13] false) W ( true)))) +(A(([c0_t7] false) W (( true) || ( true)))) +(AG(( true) -> (AF( true)))) +(A(([c0_t5] false) W ( true))) +(A(([c0_t5] false) U (( true) || ( true)))) +(AG(( true) -> ((A(([c0_t5] false) W ( true)))))) +(AG(( true) -> (AG(([c0_t6] false))))) +(AG(( true) -> ((A(([c0_t8] false) W ( true)))))) +(A((([c0_t1] false) && ([c0_t6] false)) W (( true) || ( true)))) +(A((( true) -> ((A(([c0_t2] false) U ( true))))) W ( true))) +(AF(A(([c0_t6] false) W ( true)))) +(A((( true) -> (AG(([c0_t9] false)))) W (( true) || ( true)))) +(AF((( true) && (AG(([c0_t3] false)))))) +(A((( true) -> ((A(([c0_t12] false) U ( true))))) W ( true))) +(A((( true) -> ((A(([c0_t1] false) W ( true))))) W ( true))) +(A((( true) -> (AF( true))) U ( true))) +(A((( true) -> ((A(([c0_t12] false) W ( true))))) U (( true) || ( true)))) +(AF(A(([c0_t5] false) W ( true)))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/seed.xml new file mode 100755 index 0000000000..939a0c12dc --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/seed.xml @@ -0,0 +1,176 @@ + + + main + + + 11 + + + 10 + + + 1 + + + 3 + + + 2 + + + 5 + + + 4 + + true + + + + 7 + + + 6 + + + 9 + + + 8 + + + end + + + + + 2 + end + + + true + + + + 8 + 4 + + + true + + + + 6 + 2 + + + true + + + + 1 + 2 + + + true + + + + 3 + 4 + + + true + + + + 7 + 8 + + + true + + + + 4 + 1 + + + true + + + + 7 + 10 + + + true + + + + 4 + 7 + + + true + + + + 10 + 11 + + + true + + + + 11 + 9 + + + true + + + + 2 + 6 + + + true + + + + 2 + 3 + + + true + + + + 2 + 5 + + + true + + + + 9 + 7 + + + true + + + + 5 + 2 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/solutions.txt new file mode 100755 index 0000000000..a7740cccba --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system1/solutions.txt @@ -0,0 +1,20 @@ +true +false +false +true +false +true +true +true +false +true +true +true +true +true +false +true +true +false +false +true \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/properties.txt new file mode 100755 index 0000000000..2f47131577 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/properties.txt @@ -0,0 +1,20 @@ +(AG(( true) -> (AF( true)))) +(A(([c0_t23] false) W (( true) || ( true)))) +(A(([c0_t25] false) W ( true))) +(A(([c0_t23] false) W (( true) || ( true)))) +(A((( true) -> (AG(([c0_t26] false)))) U (( true) || ( true)))) +(AF(A(([c0_t29] false) W ( true)))) +(A(([c0_t25] false) U (( true) || ( true)))) +(AG(( true) -> ((A(([c0_t2] false) W ( true)))))) +(AG(( true) -> (AG(([c0_t3] false))))) +(A((( true) -> ((A(([c0_t22] false) U ( true))))) W (( true) || ( true)))) +(A((([c0_t6] false) && ([c0_t30] false)) U ( true))) +(A((( true) -> ((A(([c0_t1] false) U ( true))))) U (( true) || ( true)))) +(AF(( true))) +(AF(A(([c0_t23] false) W ( true)))) +(AF((( true) && (AG(([c0_t24] false)))))) +(A((([c0_t9] false) && ([c0_t28] false)) U ( true))) +(A((( true) -> (AF( true))) U ( true))) +(A((( true) -> (AF( true))) U ( true))) +(A((( true) -> ((A(([c0_t19] false) W ( true))))) U (( true) || ( true)))) +(A(([c0_t19] false) W (( true) || ( true)))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/seed.xml new file mode 100755 index 0000000000..f51b1e4f01 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/seed.xml @@ -0,0 +1,331 @@ + + + main + + + 11 + + + 10 + + + 13 + + + 12 + + + 15 + + + 14 + + + 17 + + + 16 + + + 19 + + + 18 + + + 20 + + + 1 + + true + + + + 3 + + + 2 + + + 5 + + + 4 + + + 7 + + + 6 + + + 9 + + + 8 + + + end + + + + + 2 + end + + + true + + + + 7 + 8 + + + true + + + + 1 + 2 + + + true + + + + 13 + 2 + + + true + + + + 3 + 4 + + + true + + + + 4 + 14 + + + true + + + + 4 + 7 + + + true + + + + 12 + 6 + + + true + + + + 2 + 5 + + + true + + + + 2 + 12 + + + true + + + + 7 + 13 + + + true + + + + 6 + 2 + + + true + + + + 14 + 15 + + + true + + + + 6 + 7 + + + true + + + + 16 + 6 + + + true + + + + 8 + 4 + + + true + + + + 15 + 2 + + + true + + + + 2 + 3 + + + true + + + + 9 + 7 + + + true + + + + 5 + 2 + + + true + + + + 2 + 16 + + + true + + + + 20 + 17 + + + true + + + + 6 + 4 + + + true + + + + 7 + 10 + + + true + + + + 10 + 11 + + + true + + + + 2 + 18 + + + true + + + + 18 + 19 + + + true + + + + 19 + 20 + + + true + + + + 4 + 1 + + + true + + + + 17 + 2 + + + true + + + + 11 + 9 + + + true + + + + 2 + 6 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/solutions.txt new file mode 100755 index 0000000000..bd70fc912d --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system2/solutions.txt @@ -0,0 +1,20 @@ +true +true +true +true +true +true +false +true +false +true +true +true +false +true +false +true +true +false +true +true \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/properties.txt new file mode 100755 index 0000000000..0957b1f4a0 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/properties.txt @@ -0,0 +1,20 @@ +(A((( true) -> ((A(([c0_t39] false) W ( true))))) W ( true))) +(A(([c0_t16] false) W (( true) || ( true)))) +(A((( true) -> ((A(([c0_t12] false) U ( true))))) W ( true))) +(A((( true) -> (AF( true))) W (( true) || ( true)))) +(AG(( true) -> ((A(([c0_t26] false) W ( true)))))) +(A((( true) -> ((A(([c0_t10] false) U ( true))))) W ( true))) +(A(([c0_t27] false) U (( true) || ( true)))) +(AG(( true) -> ((A(([c0_t38] false) W ( true)))))) +(AG(( true) -> (AG(([c0_t10] false))))) +(AF(AF( true))) +(AF(( true))) +(A((( true) -> ((A(([c0_t27] false) U ( true))))) U (( true) || ( true)))) +(AF(( true))) +(AG(( true) -> (AF( true)))) +(AF((( true) && (AG(([c0_t34] false)))))) +(A((( true) -> ((A(([c0_t41] false) U ( true))))) W (( true) || ( true)))) +(A((( true) -> ((A(([c0_t4] false) W ( true))))) U ( true))) +(A((( true) -> (AF( true))) U ( true))) +(A((( true) -> ((A(([c0_t29] false) W ( true))))) U (( true) || ( true)))) +(A((( true) -> (AG(([c0_t36] false)))) W (( true) || ( true)))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/seed.xml new file mode 100755 index 0000000000..4109bc5178 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/seed.xml @@ -0,0 +1,486 @@ + + + main + + + 24 + + + 25 + + + 26 + + + 27 + + + 20 + + + 21 + + + 22 + + + 23 + + + 28 + + + 29 + + + 1 + + + 3 + + + 2 + + + 5 + + + 4 + + + 7 + + + 6 + + + 9 + + + 8 + + + 11 + + + 10 + + + 13 + + true + + + + 12 + + + 15 + + + 14 + + + 17 + + + 16 + + + 19 + + + 18 + + + end + + + + + 2 + end + + + true + + + + 7 + 8 + + + true + + + + 1 + 2 + + + true + + + + 23 + 24 + + + true + + + + 13 + 2 + + + true + + + + 3 + 4 + + + true + + + + 4 + 14 + + + true + + + + 4 + 7 + + + true + + + + 12 + 6 + + + true + + + + 2 + 5 + + + true + + + + 6 + 29 + + + true + + + + 2 + 12 + + + true + + + + 7 + 13 + + + true + + + + 6 + 2 + + + true + + + + 14 + 15 + + + true + + + + 6 + 7 + + + true + + + + 16 + 6 + + + true + + + + 8 + 4 + + + true + + + + 15 + 2 + + + true + + + + 4 + 21 + + + true + + + + 2 + 3 + + + true + + + + 24 + 4 + + + true + + + + 9 + 7 + + + true + + + + 5 + 2 + + + true + + + + 2 + 16 + + + true + + + + 25 + 26 + + + true + + + + 27 + 12 + + + true + + + + 6 + 4 + + + true + + + + 7 + 10 + + + true + + + + 12 + 25 + + + true + + + + 10 + 11 + + + true + + + + 7 + 27 + + + true + + + + 28 + 27 + + + true + + + + 2 + 18 + + + true + + + + 26 + 7 + + + true + + + + 18 + 19 + + + true + + + + 22 + 2 + + + true + + + + 29 + 28 + + + true + + + + 19 + 20 + + + true + + + + 4 + 1 + + + true + + + + 17 + 2 + + + true + + + + 20 + 17 + + + true + + + + 11 + 9 + + + true + + + + 2 + 6 + + + true + + + + 27 + 13 + + + true + + + + 13 + 6 + + + true + + + + 2 + 23 + + + true + + + + 21 + 22 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/solutions.txt new file mode 100755 index 0000000000..da05e31ae2 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting1/system3/solutions.txt @@ -0,0 +1,20 @@ +true +false +true +true +true +true +true +false +false +false +false +false +false +false +false +true +false +false +false +true \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/properties.txt new file mode 100644 index 0000000000..f0a40346aa --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/properties.txt @@ -0,0 +1,10 @@ +(AG(([b] false) && ([j] false))) +(AF(A(([h] false) W ( true)))) +(AG(( true) -> (AG(([f] false))))) +(AG(([e] false))) +A((([c] false) && ([d] false)) W ( true)) +A((([f] false) && ([j] false)) U (( true) || ( true))) +AG(([f] false) && (( true) -> ((A(([d] false) U ( true)))))) +AG((([b] false) && ([a] false)) && (( true) -> ((A(([c] false) U ( true)))))) +A((( true) -> ((A(([c] false) W ( true))))) W ( true)) +A((( true) -> (AG(([d] false)))) W (( true) || ( true))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/seed.xml new file mode 100644 index 0000000000..9967b03150 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/seed.xml @@ -0,0 +1,655 @@ + + + main + + + s45 + + + s16 + + + s9 + + + s42 + + + s25 + + + s5 + + + s10 + + + s44 + + + s19 + + + s17 + + + s20 + + + s32 + + + s36 + + + s35 + + + s40 + + + s30 + + + s3 + + + s33 + + + s24 + + + s27 + + + s4 + + + s26 + + + s34 + + + s2 + + + s8 + + + s0 + + true + + + + s28 + + + s14 + + + s31 + + + s38 + + + s12 + + + s43 + + + s15 + + + s11 + + + s23 + + + s39 + + + s22 + + + s6 + + + s29 + + + s37 + + + s41 + + + s1 + + + s13 + + + s21 + + + s7 + + + s18 + + + end + + + + + s9 + end + + + true + + + + s11 + s12 + + + + s1 + s33 + + + true + + + + s11 + s22 + + + true + + + + s44 + s45 + + + + s45 + s45 + + + + s12 + s13 + + + + s12 + s13 + + + + s12 + s13 + + + + s13 + s13 + + + + s13 + s13 + + + + s13 + s13 + + + + s13 + s13 + + + + s13 + s14 + + + true + + + + s13 + s29 + + + true + + + + s14 + s15 + + + true + + + + s15 + s16 + + + true + + + + s16 + s16 + + + true + + + + s17 + s17 + + + true + + + + s4 + s5 + + + + s1 + s3 + + + true + + + + s18 + s19 + + + true + + + + s19 + s20 + + + true + + + + s20 + s21 + + + true + + + + s42 + s42 + + + true + + + + s21 + s21 + + + true + + + + s6 + s8 + + + + s22 + s23 + + + true + + + + s3 + s43 + + + + s23 + s24 + + + true + + + + s5 + s8 + + + true + + + + s24 + s24 + + + true + + + + s6 + s37 + + + true + + + + s25 + s26 + + + true + + + + s26 + s27 + + + true + + + + s43 + s44 + + + + s7 + s9 + + + true + + + + s27 + s28 + + + true + + + + s7 + s10 + + + true + + + + s28 + s28 + + + true + + + + s2 + s4 + + + true + + + + s29 + s30 + + + true + + + + s10 + s13 + + + true + + + + s30 + s30 + + + true + + + + s7 + s11 + + + true + + + + s31 + s31 + + + true + + + + s3 + s5 + + + true + + + + s32 + s32 + + + true + + + + s6 + s25 + + + true + + + + s33 + s34 + + + true + + + + s8 + s10 + + + + s34 + s35 + + + true + + + + s35 + s36 + + + true + + + + s9 + s9 + + + + s36 + s36 + + + true + + + + s4 + s6 + + + true + + + + s37 + s38 + + + true + + + + s9 + s9 + + + + s38 + s39 + + + true + + + + s9 + s9 + + + + s39 + s40 + + + true + + + + s2 + s3 + + + + s9 + s9 + + + + s40 + s41 + + + true + + + + s9 + s31 + + + true + + + + s41 + s42 + + + true + + + + s10 + s12 + + + + s0 + s1 + + + true + + + + s12 + s13 + + + + s0 + s2 + + + true + + + + s5 + s7 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/solutions.txt new file mode 100644 index 0000000000..c9e5ef9ea8 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system1/solutions.txt @@ -0,0 +1,10 @@ +false +false +false +false +true +true +false +false +true +true \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/properties.txt new file mode 100644 index 0000000000..3c74fc3502 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/properties.txt @@ -0,0 +1,10 @@ +A((( true) -> ((A(([b] false) W ( true))))) U (( true) || ( true))) +AG((( true) -> (AF( true))) && (( true) -> ((A(([h] false) U ( true)))))) +(AF(( true))) +A((([c] false) && ([i] false)) U ( true)) +AG((( true) -> ((A(([a] false) U ( true))))) && (([g] false) && ([d] false))) +A((([g] false) && ([d] false)) W (( true) || ( true))) +AG((( true) -> ((A(([i] false) W ( true))))) && (( true) -> ((A(([a] false) W ( true)))))) +(AF((( true) && (AG(([a] false)))))) +A((([d] false) && ([h] false)) U (( true) || ( true))) +AG((( true) -> ((A(([f] false) W ( true))))) && (( true) -> ((A(([j] false) U ( true)))))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/seed.xml new file mode 100644 index 0000000000..f05ac2287d --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/seed.xml @@ -0,0 +1,1751 @@ + + + main + + + s6 + + + s19 + + + s92 + + + s11 + + + s61 + + + s114 + + + s1 + + + s13 + + + s103 + + + s44 + + + s7 + + + s104 + + + s55 + + + s85 + + + s3 + + + s90 + + + s111 + + + s94 + + + s105 + + + s106 + + + s79 + + + s49 + + + s30 + + + s108 + + + s82 + + + s56 + + + s107 + + + s48 + + + s18 + + + s33 + + + s98 + + + s65 + + + s66 + + + s45 + + + s75 + + + s60 + + + s97 + + + s47 + + + s31 + + + s27 + + + s14 + + + s58 + + + s110 + + + s17 + + + s8 + + + s78 + + + s32 + + + s70 + + + s115 + + + s80 + + + s112 + + + s4 + + + s68 + + + s16 + + + s43 + + + s109 + + + s69 + + + s81 + + + s83 + + + s74 + + + s5 + + + s26 + + + s67 + + + s21 + + + s95 + + + s72 + + + s71 + + + s113 + + + s40 + + + s42 + + + s76 + + + s50 + + + s59 + + + s73 + + + s41 + + + s24 + + + s102 + + + s10 + + + s36 + + + s38 + + + s29 + + + s37 + + + s77 + + + s84 + + + s25 + + + s34 + + + s87 + + + s0 + + true + + + + s51 + + + s9 + + + s62 + + + s99 + + + s93 + + + s52 + + + s86 + + + s39 + + + s35 + + + s57 + + + s96 + + + s100 + + + s23 + + + s2 + + + s53 + + + s64 + + + s20 + + + s101 + + + s15 + + + s63 + + + s28 + + + s12 + + + s91 + + + s54 + + + s88 + + + s22 + + + s46 + + + s89 + + + end + + + + + s57 + end + + + true + + + + s113 + s114 + + + true + + + + s114 + s115 + + + true + + + + s115 + s112 + + + true + + + + s53 + s51 + + + + s53 + s67 + + + + s54 + s31 + + + + s1 + s5 + + + true + + + + s110 + s111 + + + true + + + + s111 + s112 + + + true + + + + s112 + s113 + + + true + + + + s0 + s1 + + + true + + + + s0 + s2 + + + true + + + + s1 + s4 + + + true + + + + s54 + s35 + + + + s20 + s73 + + + true + + + + s54 + s58 + + + + s20 + s76 + + + true + + + + s21 + s39 + + + + s55 + s32 + + + + s21 + s41 + + + + s55 + s36 + + + + s22 + s21 + + + + s55 + s54 + + + + s22 + s40 + + + + s55 + s59 + + + + s22 + s42 + + + + s56 + s56 + + + + s23 + s24 + + + + s56 + s56 + + + + s23 + s43 + + + true + + + + s56 + s56 + + + + s23 + s44 + + + + s56 + s56 + + + + s23 + s45 + + + + s56 + s56 + + + + s24 + s46 + + + + s57 + s56 + + + + s24 + s47 + + + + s58 + s44 + + + + s25 + s24 + + + + s58 + s48 + + + + s3 + s8 + + + + s25 + s48 + + + + s58 + s68 + + + + s25 + s49 + + + + s59 + s45 + + + + s26 + s21 + + + + s59 + s49 + + + + s26 + s50 + + + + s59 + s58 + + + + s5 + s11 + + + + s26 + s51 + + + + s59 + s69 + + + + s3 + s5 + + + + s27 + s22 + + + + s60 + s62 + + + + s4 + s85 + + + true + + + + s27 + s26 + + + + s61 + s60 + + + + s27 + s52 + + + + s61 + s63 + + + + s2 + s7 + + + true + + + + s27 + s53 + + + + s62 + s62 + + + + s5 + s104 + + + true + + + + s28 + s39 + + + + s62 + s62 + + + + s6 + s9 + + + + s29 + s28 + + + + s62 + s62 + + + + s2 + s4 + + + true + + + + s29 + s40 + + + + s62 + s62 + + + + s8 + s11 + + + + s30 + s17 + + + + s62 + s62 + + + + s6 + s12 + + + + s30 + s43 + + + + s62 + s64 + + + + s2 + s6 + + + + s30 + s54 + + + true + + + + s63 + s62 + + + + s30 + s55 + + + + s64 + s62 + + + + s6 + s13 + + + + s30 + s80 + + + true + + + + s65 + s63 + + + + s6 + s14 + + + + s31 + s33 + + + + s65 + s64 + + + + s7 + s10 + + + + s31 + s44 + + + + s66 + s56 + + + + s4 + s9 + + + true + + + + s32 + s31 + + + + s67 + s57 + + + + s7 + s13 + + + + s32 + s34 + + + + s67 + s66 + + + + s7 + s14 + + + + s32 + s45 + + + + s68 + s60 + + + + s7 + s15 + + + true + + + + s33 + s46 + + + + s68 + s64 + + + + s7 + s16 + + + + s34 + s33 + + + + s69 + s61 + + + + s8 + s7 + + + + s34 + s47 + + + + s69 + s65 + + + + s8 + s19 + + + + s35 + s33 + + + + s69 + s68 + + + + s4 + s10 + + + true + + + + s35 + s48 + + + + s70 + s71 + + + true + + + + s8 + s17 + + + + s36 + s34 + + + + s71 + s72 + + + true + + + + s8 + s18 + + + + s36 + s35 + + + + s72 + s72 + + + true + + + + s9 + s20 + + + true + + + + s36 + s49 + + + + s73 + s74 + + + true + + + + s9 + s21 + + + + s37 + s28 + + + + s74 + s75 + + + true + + + + s9 + s22 + + + + s37 + s50 + + + + s75 + s75 + + + true + + + + s10 + s21 + + + + s38 + s29 + + + + s76 + s77 + + + true + + + + s10 + s22 + + + + s38 + s37 + + + + s77 + s78 + + + true + + + + s10 + s23 + + + true + + + + s38 + s52 + + + + s78 + s79 + + + true + + + + s10 + s24 + + + + s39 + s56 + + + + s79 + s79 + + + true + + + + s11 + s10 + + + + s40 + s39 + + + + s80 + s81 + + + true + + + + s11 + s25 + + + + s40 + s57 + + + + s81 + s82 + + + true + + + + s11 + s26 + + + + s41 + s56 + + + + s82 + s83 + + + true + + + + s11 + s27 + + + + s42 + s41 + + + + s83 + s84 + + + true + + + + s12 + s20 + + + + s42 + s57 + + + + s84 + s84 + + + true + + + + s12 + s28 + + + + s43 + s25 + + + + s85 + s86 + + + true + + + + s12 + s29 + + + + s43 + s58 + + + + s86 + s87 + + + true + + + + s0 + s3 + + + + s13 + s21 + + + + s43 + s59 + + + + s13 + s28 + + + + s87 + s88 + + + true + + + + s14 + s13 + + + + s44 + s46 + + + + s88 + s88 + + + true + + + + s14 + s22 + + + + s44 + s60 + + + + s89 + s90 + + + true + + + + s14 + s29 + + + + s45 + s44 + + + + s90 + s91 + + + true + + + + s15 + s16 + + + + s45 + s47 + + + + s91 + s92 + + + true + + + + s15 + s23 + + + + s45 + s61 + + + + s92 + s93 + + + true + + + + s15 + s30 + + + true + + + + s46 + s62 + + + + s93 + s93 + + + true + + + + s15 + s31 + + + + s47 + s46 + + + + s94 + s95 + + + true + + + + s15 + s32 + + + + s47 + s63 + + + + s95 + s96 + + + true + + + + s16 + s24 + + + + s48 + s46 + + + + s96 + s97 + + + true + + + + s16 + s33 + + + + s48 + s64 + + + + s97 + s98 + + + true + + + + s16 + s34 + + + + s49 + s47 + + + + s98 + s97 + + + true + + + + s17 + s16 + + + + s49 + s48 + + + + s99 + s100 + + + true + + + + s17 + s25 + + + + s49 + s65 + + + + s100 + s101 + + + true + + + + s17 + s35 + + + + s50 + s39 + + + + s101 + s102 + + + true + + + + s17 + s36 + + + + s50 + s66 + + + + s102 + s103 + + + true + + + + s18 + s13 + + + + s51 + s41 + + + + s103 + s103 + + + true + + + + s18 + s26 + + + + s51 + s66 + + + + s104 + s105 + + + true + + + + s18 + s37 + + + + s52 + s40 + + + + s105 + s106 + + + true + + + + s19 + s14 + + + + s52 + s50 + + + + s106 + s107 + + + true + + + + s19 + s18 + + + + s52 + s67 + + + + s107 + s107 + + + true + + + + s19 + s27 + + + + s53 + s42 + + + + s108 + s109 + + + true + + + + s19 + s38 + + + + s109 + s110 + + + true + + + + s20 + s39 + + + + s20 + s40 + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/solutions.txt new file mode 100644 index 0000000000..16f061426c --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system2/solutions.txt @@ -0,0 +1,10 @@ +false +false +true +true +false +true +false +false +true +false \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/properties.txt new file mode 100644 index 0000000000..e626da9d4a --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/properties.txt @@ -0,0 +1,10 @@ +A((( true) -> ((A(([f] false) W ( true))))) U (( true) || ( true))) +A((( true) -> ((A(([e] false) W ( true))))) W ( true)) +AG((( true) -> ((A(([f] false) U ( true))))) && (([c] false) && ([g] false))) +(AG(( true) -> (AG(([e] false))))) +A(([f] false) U ( true)) +A((( true) -> ((A(([c] false) U ( true))))) U ( true)) +A((( true) -> (AF( true))) W (( true) || ( true))) +A(([h] false) W ( true)) +(AG(([g] false) && ([i] false))) +A((([b] false) && ([c] false)) W ( true)) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/seed.xml new file mode 100644 index 0000000000..871a333824 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/seed.xml @@ -0,0 +1,577 @@ + + + main + + + s28 + + + s31 + + + s43 + + + s14 + + + s3 + + + s30 + + + s36 + + + s17 + + + s0 + + true + + + + s38 + + + s8 + + + s10 + + + s9 + + + s41 + + + s32 + + + s13 + + + s35 + + + s11 + + + s2 + + + s26 + + + s5 + + + s24 + + + s22 + + + s1 + + + s34 + + + s20 + + + s25 + + + s27 + + + s19 + + + s33 + + + s18 + + + s39 + + + s23 + + + s7 + + + s40 + + + s29 + + + s15 + + + s12 + + + s37 + + + s42 + + + s6 + + + s21 + + + s4 + + + s16 + + + end + + + + + s16 + end + + + + s10 + s10 + + + + s1 + s3 + + + true + + + + s10 + s10 + + + + s11 + s11 + + + + s11 + s11 + + + + s11 + s11 + + + + s11 + s11 + + + + s11 + s11 + + + + s12 + s6 + + + true + + + + s12 + s11 + + + + s13 + s14 + + + true + + + + s14 + s15 + + + true + + + + s15 + s15 + + + true + + + + s16 + s17 + + + + s17 + s17 + + + + s18 + s18 + + + true + + + + s19 + s20 + + + true + + + + s3 + s8 + + + + s1 + s2 + + + true + + + + s20 + s20 + + + true + + + + s21 + s22 + + + true + + + + s22 + s23 + + + true + + + + s23 + s24 + + + true + + + + s4 + s16 + + + + s24 + s24 + + + true + + + + s25 + s25 + + + true + + + + s4 + s10 + + + + s26 + s27 + + + true + + + + s5 + s19 + + + true + + + + s27 + s28 + + + true + + + + s28 + s29 + + + true + + + + s29 + s30 + + + true + + + + s6 + s7 + + + true + + + + s30 + s30 + + + true + + + + s31 + s32 + + + true + + + + s10 + s10 + + + + s32 + s32 + + + true + + + + s7 + s11 + + + + s33 + s34 + + + true + + + + s34 + s35 + + + true + + + + s5 + s10 + + + + s35 + s36 + + + true + + + + s36 + s36 + + + true + + + + s8 + s4 + + + + s37 + s38 + + + true + + + + s8 + s12 + + + true + + + + s38 + s39 + + + true + + + + s3 + s9 + + + true + + + + s39 + s39 + + + true + + + + s40 + s41 + + + true + + + + s9 + s4 + + + + s41 + s42 + + + true + + + + s2 + s8 + + + true + + + + s9 + s5 + + + true + + + + s42 + s43 + + + true + + + + s10 + s10 + + + + s43 + s43 + + + true + + + + s10 + s10 + + + + s0 + s1 + + + true + + + + s10 + s10 + + + + s3 + s31 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/solutions.txt new file mode 100644 index 0000000000..a58835b50a --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system3/solutions.txt @@ -0,0 +1,10 @@ +true +false +false +false +true +true +true +true +true +true \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/properties.txt new file mode 100644 index 0000000000..3436ecbd77 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/properties.txt @@ -0,0 +1,10 @@ +A((([d] false) && ([e] false)) U (( true) || ( true))) +AG((( true) -> ((A(([c] false) W ( true))))) && (([h] false) && ([d] false))) +A((([c] false) && ([d] false)) W (( true) || ( true))) +A(([g] false) U ( true)) +A((([c] false) && ([h] false)) U (( true) || ( true))) +A(([i] false) W (( true) || ( true))) +A((([c] false) && ([f] false)) U (( true) || ( true))) +A(([c] false) W (( true) || ( true))) +A((( true) -> (AG(([f] false)))) W (( true) || ( true))) +(AF(( true))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/seed.xml new file mode 100644 index 0000000000..bfdd1972d2 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/seed.xml @@ -0,0 +1,1252 @@ + + + main + + + s31 + + + s40 + + + s13 + + + s12 + + + s61 + + + s71 + + + s54 + + + s19 + + + s16 + + + s80 + + + s10 + + + s5 + + + s51 + + + s58 + + + s25 + + + s65 + + + s42 + + + s60 + + + s28 + + + s35 + + + s36 + + + s27 + + + s14 + + + s11 + + + s67 + + + s73 + + + s0 + + + s29 + + + s43 + + + s6 + + + s48 + + + s39 + + + s69 + + + s45 + + + s21 + + + s53 + + + s8 + + + s47 + + + s1 + + + s66 + + + s59 + + + s17 + + + s30 + + + s55 + + + s24 + + + s75 + + + s52 + + + s2 + + + s41 + + + s44 + + + s4 + + + s38 + + + s62 + + + s37 + + + s72 + + + s76 + + + s79 + + + s15 + + + s33 + + + s49 + + + s22 + + + s23 + + + s18 + + + s70 + + + s77 + + + s46 + + + s34 + + + s7 + + + s78 + + + s74 + + + s26 + + + s56 + + + s20 + + + s68 + + + s63 + + + s64 + + + s3 + + true + + + + s81 + + + s57 + + + s32 + + + s50 + + + s9 + + + end + + + + + s49 + end + + + true + + + + s73 + s73 + + + true + + + + s74 + s75 + + + true + + + + s75 + s76 + + + true + + + + s76 + s77 + + + true + + + + s77 + s78 + + + true + + + + s78 + s78 + + + true + + + + s79 + s80 + + + true + + + + s80 + s81 + + + true + + + + s81 + s81 + + + true + + + + s70 + s71 + + + true + + + + s71 + s72 + + + true + + + + s72 + s73 + + + true + + + + s0 + s0 + + + + s0 + s0 + + + + s20 + s24 + + + + s21 + s8 + + + + s21 + s9 + + + + s22 + s10 + + + true + + + + s22 + s21 + + + + s22 + s25 + + + true + + + + s23 + s8 + + + + s23 + s10 + + + + s23 + s26 + + + true + + + + s24 + s9 + + + + s24 + s11 + + + + s24 + s25 + + + + s24 + s26 + + + + s25 + s9 + + + + s25 + s27 + + + + s0 + s0 + + + + s25 + s29 + + + + s25 + s70 + + + true + + + + s26 + s14 + + + + s26 + s16 + + + true + + + + s1 + s1 + + + + s26 + s29 + + + + s0 + s0 + + + + s27 + s17 + + + + s1 + s1 + + + + s27 + s18 + + + + s1 + s1 + + + + s28 + s17 + + + + s0 + s0 + + + + s28 + s19 + + + + s1 + s1 + + + + s29 + s14 + + + + s1 + s2 + + + + s29 + s17 + + + + s0 + s0 + + + + s30 + s13 + + + + s2 + s2 + + + + s30 + s29 + + + + s30 + s35 + + + + s0 + s0 + + + + s30 + s79 + + + true + + + + s1 + s1 + + + + s31 + s2 + + + + s2 + s2 + + + + s32 + s2 + + + + s2 + s2 + + + + s32 + s31 + + + + s2 + s2 + + + + s33 + s17 + + + + s1 + s1 + + + + s33 + s31 + + + + s2 + s2 + + + + s34 + s17 + + + + s2 + s2 + + + + s34 + s32 + + + + s2 + s2 + + + + s34 + s33 + + + + s2 + s2 + + + + s35 + s28 + + + + s2 + s2 + + + + s35 + s34 + + + + s3 + s48 + + + true + + + + s35 + s36 + + + + s1 + s1 + + + + s35 + s37 + + + + s3 + s4 + + + true + + + + s36 + s28 + + + + s3 + s39 + + + true + + + + s36 + s33 + + + + s3 + s58 + + + true + + + + s36 + s38 + + + + s4 + s5 + + + true + + + + s37 + s19 + + + + s4 + s20 + + + true + + + + s37 + s32 + + + + s37 + s38 + + + + s5 + s6 + + + true + + + + s38 + s19 + + + + s5 + s21 + + + + s38 + s31 + + + + s39 + s40 + + + true + + + + s6 + s7 + + + + s40 + s41 + + + true + + + + s6 + s8 + + + + s41 + s42 + + + true + + + + s6 + s46 + + + true + + + + s42 + s43 + + + true + + + + s7 + s0 + + + + s43 + s44 + + + true + + + + s7 + s12 + + + + s44 + s45 + + + true + + + + s8 + s7 + + + + s45 + s45 + + + true + + + + s8 + s13 + + + + s46 + s47 + + + true + + + + s0 + s0 + + + + s8 + s14 + + + + s47 + s47 + + + true + + + + s9 + s14 + + + + s48 + s49 + + + true + + + + s9 + s27 + + + + s49 + s50 + + + true + + + + s10 + s8 + + + + s50 + s51 + + + true + + + + s10 + s29 + + + + s51 + s52 + + + true + + + + s10 + s30 + + + true + + + + s52 + s53 + + + true + + + + s53 + s53 + + + true + + + + s11 + s15 + + + + s54 + s55 + + + true + + + + s11 + s16 + + + + s55 + s56 + + + true + + + + s11 + s27 + + + + s56 + s57 + + + true + + + + s12 + s0 + + + + s57 + s57 + + + true + + + + s0 + s0 + + + + s13 + s12 + + + + s58 + s59 + + + true + + + + s13 + s14 + + + + s59 + s60 + + + true + + + + s13 + s33 + + + + s60 + s61 + + + true + + + + s14 + s0 + + + + s61 + s62 + + + true + + + + s14 + s17 + + + + s62 + s63 + + + true + + + + s0 + s0 + + + + s15 + s1 + + + + s63 + s64 + + + true + + + + s15 + s18 + + + + s64 + s64 + + + true + + + + s16 + s1 + + + true + + + + s65 + s66 + + + true + + + + s16 + s17 + + + + s66 + s67 + + + true + + + + s17 + s2 + + + + s67 + s68 + + + true + + + + s18 + s2 + + + + s68 + s68 + + + true + + + + s19 + s2 + + + + s69 + s69 + + + true + + + + s20 + s21 + + + + s20 + s22 + + + true + + + + s20 + s23 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/solutions.txt new file mode 100644 index 0000000000..4d17555c79 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system4/solutions.txt @@ -0,0 +1,10 @@ +true +false +true +true +true +true +true +true +true +false \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/properties.txt new file mode 100644 index 0000000000..abbbe87648 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/properties.txt @@ -0,0 +1,10 @@ +(AG((( true) -> (AG(([h] false)))) && (( true) -> (AF( true))))) +A((([b] false) && ([d] false)) W (( true) || ( true))) +A((([c] false) && ([d] false)) U ( true)) +A((( true) -> ((A(([g] false) W ( true))))) W (( true) || ( true))) +(AG(( true) -> ((A(([g] false) U ( true)))))) +(AG((([e] false) && ([f] false)) && (( true) -> ((A(([b] false) W ( true))))))) +A(([d] false) W ( true)) +A((( true) -> ((A(([g] false) U ( true))))) W ( true)) +(AG(( true) -> (AG(([b] false))))) +AG((( true) -> ((A(([g] false) W ( true))))) && (( true) -> ((A(([b] false) U ( true)))))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/seed.xml new file mode 100644 index 0000000000..076cabf760 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/seed.xml @@ -0,0 +1,988 @@ + + + main + + + s53 + + + s42 + + + s23 + + + s48 + + + s63 + + + s64 + + + s31 + + + s1 + + + s57 + + + s15 + + + s59 + + + s36 + + + s7 + + + s27 + + + s50 + + + s16 + + + s34 + + + s29 + + + s32 + + + s22 + + + s33 + + + s56 + + + s37 + + + s28 + + + s21 + + + s2 + + + s11 + + + s60 + + + s17 + + + s38 + + + s39 + + + s51 + + + s12 + + + s62 + + + s49 + + + s54 + + + s41 + + + s25 + + + s18 + + + s3 + + + s14 + + + s9 + + + s40 + + + s26 + + + s44 + + + s47 + + + s58 + + + s30 + + + s46 + + + s61 + + + s0 + + true + + + + s4 + + + s8 + + + s6 + + + s5 + + + s43 + + + s52 + + + s55 + + + s10 + + + s20 + + + s24 + + + s45 + + + s13 + + + s19 + + + s35 + + + s8 + + + end + + + + + s8 + end + + + true + + + + s0 + s5 + + + + s0 + s1 + + + true + + + + s0 + s2 + + + + s0 + s4 + + + true + + + + s20 + s56 + + + true + + + + s21 + s22 + + + true + + + + s22 + s22 + + + true + + + + s23 + s24 + + + true + + + + s24 + s24 + + + true + + + + s25 + s26 + + + true + + + + s26 + s26 + + + true + + + + s27 + s28 + + + true + + + + s28 + s29 + + + true + + + + s29 + s30 + + + true + + + + s30 + s31 + + + true + + + + s31 + s32 + + + true + + + + s32 + s33 + + + true + + + + s33 + s34 + + + true + + + + s34 + s33 + + + true + + + + s2 + s2 + + + + s35 + s36 + + + true + + + + s36 + s37 + + + true + + + + s37 + s38 + + + true + + + + s38 + s39 + + + true + + + + s3 + s8 + + + true + + + + s39 + s40 + + + true + + + + s2 + s2 + + + + s40 + s41 + + + true + + + + s3 + s6 + + + + s41 + s42 + + + true + + + + s4 + s1 + + + + s42 + s43 + + + true + + + + s1 + s7 + + + true + + + + s43 + s43 + + + true + + + + s4 + s2 + + + + s44 + s45 + + + true + + + + s4 + s8 + + + + s45 + s46 + + + true + + + + s1 + s2 + + + + s46 + s46 + + + true + + + + s8 + s13 + + + true + + + + s47 + s48 + + + true + + + + s4 + s10 + + + true + + + + s48 + s49 + + + true + + + + s1 + s6 + + + + s49 + s50 + + + true + + + + s3 + s9 + + + true + + + + s50 + s51 + + + true + + + + s5 + s9 + + + + s51 + s49 + + + true + + + + s5 + s10 + + + + s52 + s53 + + + true + + + + s6 + s11 + + + + s53 + s54 + + + true + + + + s2 + s2 + + + + s54 + s55 + + + true + + + + s7 + s11 + + + + s55 + s55 + + + true + + + + s7 + s12 + + + + s56 + s57 + + + true + + + + s7 + s25 + + + true + + + + s57 + s58 + + + true + + + + s7 + s44 + + + true + + + + s58 + s57 + + + true + + + + s8 + s6 + + + + s59 + s60 + + + true + + + + s9 + s27 + + + true + + + + s60 + s61 + + + true + + + + s2 + s2 + + + + s61 + s62 + + + true + + + + s8 + s23 + + + true + + + + s62 + s63 + + + true + + + + s9 + s13 + + + + s63 + s64 + + + true + + + + s9 + s47 + + + true + + + + s64 + s64 + + + true + + + + s10 + s13 + + + + s10 + s21 + + + true + + + + s11 + s12 + + + + s11 + s12 + + + + s11 + s12 + + + + s11 + s12 + + + + s11 + s14 + + + + s12 + s12 + + + + s12 + s12 + + + + s12 + s12 + + + + s12 + s12 + + + + s12 + s14 + + + + s13 + s15 + + + true + + + + s0 + s3 + + + true + + + + s14 + s14 + + + + s14 + s14 + + + + s14 + s14 + + + + s14 + s14 + + + + s14 + s14 + + + + s15 + s16 + + + true + + + + s16 + s17 + + + + s16 + s17 + + + + s16 + s17 + + + + s16 + s18 + + + + s16 + s19 + + + + s16 + s20 + + + true + + + + s17 + s18 + + + + s17 + s19 + + + + s18 + s14 + + + + s19 + s14 + + + + s19 + s15 + + + + s19 + s17 + + + + s19 + s19 + + + + s19 + s19 + + + + s19 + s19 + + + + s20 + s15 + + + + s20 + s17 + + + + s20 + s35 + + + true + + + + s20 + s52 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/solutions.txt new file mode 100644 index 0000000000..bd3d50156a --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system5/solutions.txt @@ -0,0 +1,10 @@ +false +true +true +true +false +false +true +true +false +false \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/properties.txt new file mode 100644 index 0000000000..0be2583c1f --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/properties.txt @@ -0,0 +1,10 @@ +A(([h] false) U (( true) || ( true))) +A((( true) -> ((A(([g] false) U ( true))))) W ( true)) +A((([i] false) && ([j] false)) U (( true) || ( true))) +AG((( true) -> ((A(([b] false) W ( true))))) && (( true) -> ((A(([f] false) W ( true)))))) +(AG(([j] false))) +AG((( true) -> (AF( true))) && (( true) -> ((A(([i] false) W ( true)))))) +A((( true) -> (AF( true))) U ( true)) +A((([b] false) && ([j] false)) W ( true)) +A((([b] false) && ([f] false)) W (( true) || ( true))) +A((( true) -> (AF( true))) U (( true) || ( true))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/seed.xml new file mode 100644 index 0000000000..a1bc252830 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/seed.xml @@ -0,0 +1,2457 @@ + + + main + + + s6 + + + s71 + + + s138 + + + s84 + + + s35 + + + s87 + + + s133 + + + s127 + + + s56 + + + s15 + + + s12 + + + s85 + + + s49 + + + s115 + + + s33 + + + s143 + + + s29 + + + s96 + + + s146 + + + s163 + + + s91 + + + s105 + + + s65 + + + s135 + + + s112 + + + s153 + + + s66 + + + s151 + + + s36 + + + s144 + + + s131 + + + s74 + + + s126 + + + s73 + + + s122 + + + s154 + + + s97 + + + s13 + + + s30 + + + s132 + + + s148 + + + s19 + + + s142 + + + s10 + + + s107 + + + s57 + + + s88 + + + s28 + + + s52 + + + s24 + + + s1 + + + s38 + + + s134 + + + s47 + + + s82 + + + s164 + + + s78 + + + s109 + + + s108 + + + s7 + + + s43 + + + s140 + + + s77 + + + s46 + + + s18 + + + s59 + + + s124 + + + s130 + + + s55 + + + s17 + + + s139 + + + s45 + + + s69 + + + s129 + + + s160 + + + s64 + + + s128 + + + s157 + + + s3 + + + s93 + + + s155 + + + s162 + + + s37 + + + s2 + + + s158 + + + s95 + + + s27 + + + s42 + + + s114 + + + s5 + + + s53 + + + s150 + + + s31 + + + s102 + + + s117 + + + s137 + + + s23 + + + s68 + + + s81 + + + s25 + + + s159 + + + s149 + + + s22 + + + s67 + + + s79 + + + s60 + + + s8 + + + s41 + + + s98 + + + s116 + + + s83 + + + s9 + + + s100 + + + s61 + + + s14 + + + s40 + + + s70 + + + s118 + + + s152 + + + s26 + + + s111 + + + s62 + + + s34 + + + s120 + + + s80 + + + s39 + + + s125 + + + s48 + + + s51 + + + s145 + + + s136 + + + s92 + + + s119 + + + s11 + + + s72 + + + s16 + + + s141 + + + s101 + + + s89 + + + s123 + + + s21 + + + s161 + + + s121 + + + s32 + + + s58 + + + s147 + + + s4 + + + s113 + + + s54 + + + s156 + + + s63 + + + s0 + + true + + + + s50 + + + s99 + + + s103 + + + s110 + + + s104 + + + end + + + + + s159 + end + + + true + + + + s33 + s11 + + + + s33 + s42 + + + + s34 + s32 + + + + s34 + s33 + + + + s34 + s43 + + + + s35 + s10 + + + + s35 + s11 + + + + s35 + s34 + + + + s35 + s102 + + + + s36 + s12 + + + + s36 + s15 + + + + s36 + s40 + + + true + + + + s37 + s12 + + + + s37 + s13 + + + + s37 + s41 + + + + s37 + s96 + + + + s38 + s12 + + + + s38 + s42 + + + + s38 + s97 + + + + s39 + s13 + + + + s39 + s18 + + + + s39 + s36 + + + + s40 + s14 + + + + s40 + s19 + + + true + + + + s41 + s15 + + + + s41 + s16 + + + + s42 + s15 + + + + s42 + s17 + + + + s43 + s41 + + + + s43 + s42 + + + + s45 + s21 + + + + s45 + s22 + + + + s45 + s29 + + + + s45 + s83 + + + + s46 + s21 + + + + s46 + s30 + + + + s46 + s48 + + + + s46 + s84 + + + + s47 + s31 + + + + s47 + s49 + + + + s48 + s22 + + + + s48 + s23 + + + + s48 + s32 + + + + s49 + s24 + + + true + + + + s49 + s33 + + + + s50 + s34 + + + + s50 + s49 + + + + s51 + s35 + + + + s51 + s161 + + + true + + + + s52 + s25 + + + + s52 + s125 + + + true + + + + s53 + s25 + + + + s53 + s26 + + + + s53 + s29 + + + true + + + + s54 + s25 + + + + s54 + s30 + + + + s54 + s57 + + + + s54 + s88 + + + + s55 + s25 + + + + s55 + s31 + + + + s55 + s58 + + + + s56 + s54 + + + + s56 + s55 + + + + s56 + s59 + + + + s56 + s88 + + + + s57 + s26 + + + + s57 + s27 + + + + s57 + s32 + + + + s58 + s26 + + + + s58 + s28 + + + + s58 + s33 + + + + s59 + s34 + + + + s59 + s57 + + + + s59 + s58 + + + + s59 + s60 + + + true + + + + s60 + s27 + + + + s60 + s28 + + + + s60 + s35 + + + + s61 + s29 + + + + s61 + s30 + + + + s61 + s32 + + + + s61 + s65 + + + + s61 + s91 + + + + s62 + s29 + + + + s62 + s31 + + + + s62 + s33 + + + + s62 + s66 + + + + s63 + s34 + + + + s63 + s61 + + + + s63 + s62 + + + + s63 + s64 + + + + s63 + s67 + + + + s63 + s80 + + + true + + + + s63 + s91 + + + + s64 + s30 + + + + s64 + s31 + + + + s64 + s34 + + + + s64 + s56 + + + + s64 + s92 + + + + s64 + s95 + + + + s65 + s36 + + + + s65 + s37 + + + + s65 + s39 + + + + s65 + s41 + + + + s66 + s36 + + + + s66 + s38 + + + + s66 + s42 + + + + s67 + s43 + + + + s67 + s65 + + + + s67 + s66 + + + + s67 + s68 + + + + s67 + s98 + + + + s68 + s37 + + + + s68 + s38 + + + + s68 + s43 + + + + s68 + s95 + + + + s68 + s99 + + + + s69 + s77 + + + true + + + + s69 + s88 + + + + s70 + s69 + + + true + + + + s70 + s87 + + + + s71 + s45 + + + + s71 + s46 + + + + s71 + s48 + + + + s71 + s61 + + + + s71 + s83 + + + true + + + + s72 + s47 + + + + s72 + s49 + + + true + + + + s72 + s62 + + + + s72 + s73 + + + true + + + + s73 + s50 + + + + s73 + s63 + + + true + + + + s73 + s74 + + + + s74 + s47 + + + + s74 + s50 + + + + s74 + s64 + + + + s74 + s84 + + + + s77 + s52 + + + true + + + + s77 + s55 + + + + s78 + s53 + + + + s78 + s54 + + + + s78 + s57 + + + + s78 + s61 + + + + s78 + s87 + + + + s79 + s53 + + + + s79 + s55 + + + + s79 + s58 + + + + s79 + s62 + + + + s80 + s56 + + + + s80 + s59 + + + true + + + + s80 + s78 + + + + s80 + s79 + + + + s80 + s87 + + + + s81 + s81 + + + + s81 + s81 + + + + s81 + s81 + + + + s81 + s81 + + + + s81 + s81 + + + + s81 + s81 + + + + s81 + s81 + + + + s82 + s81 + + + + s82 + s82 + + + + s82 + s82 + + + + s82 + s82 + + + + s82 + s82 + + + + s3 + s81 + + + + s5 + s82 + + + + s7 + s3 + + + + s2 + s70 + + + true + + + + s8 + s9 + + + + s8 + s103 + + + + s13 + s18 + + + + s9 + s3 + + + + s2 + s53 + + + true + + + + s6 + s3 + + + + s9 + s15 + + + + s10 + s3 + + + + s10 + s107 + + + + s4 + s81 + + + + s11 + s3 + + + + s11 + s110 + + + + s1 + s71 + + + true + + + + s12 + s15 + + + + s12 + s103 + + + + s13 + s12 + + + + s14 + s19 + + + + s5 + s4 + + + + s13 + s101 + + + + s14 + s12 + + + + s14 + s108 + + + + s15 + s4 + + + + s16 + s4 + + + + s16 + s107 + + + + s17 + s4 + + + + s17 + s110 + + + + s18 + s15 + + + + s19 + s5 + + + true + + + + s19 + s15 + + + + s21 + s8 + + + + s21 + s22 + + + + s21 + s84 + + + + s22 + s6 + + + + s22 + s9 + + + + s23 + s6 + + + + s23 + s10 + + + + s24 + s11 + + + + s24 + s51 + + + true + + + + s25 + s8 + + + + s25 + s26 + + + + s26 + s7 + + + + s26 + s9 + + + + s27 + s7 + + + + s27 + s10 + + + + s28 + s7 + + + + s28 + s11 + + + + s29 + s8 + + + + s29 + s9 + + + + s29 + s36 + + + true + + + + s30 + s8 + + + + s30 + s32 + + + + s30 + s92 + + + + s30 + s96 + + + + s31 + s8 + + + + s31 + s33 + + + + s31 + s97 + + + + s32 + s9 + + + + s32 + s10 + + + + s32 + s41 + + + + s33 + s9 + + + + s1 + s2 + + + true + + + + s82 + s82 + + + + s83 + s72 + + + true + + + + s83 + s84 + + + + s83 + s85 + + + + s83 + s91 + + + + s84 + s47 + + + + s84 + s85 + + + + s84 + s92 + + + + s85 + s49 + + + + s85 + s93 + + + + s87 + s79 + + + + s87 + s88 + + + + s87 + s89 + + + + s88 + s55 + + + + s88 + s89 + + + + s89 + s58 + + + + s89 + s93 + + + + s91 + s62 + + + + s91 + s87 + + + + s91 + s92 + + + + s91 + s93 + + + + s91 + s98 + + + + s92 + s31 + + + + s92 + s88 + + + + s92 + s93 + + + + s92 + s100 + + + + s93 + s33 + + + + s93 + s104 + + + + s95 + s96 + + + + s95 + s97 + + + + s95 + s100 + + + + s95 + s102 + + + + s96 + s101 + + + + s96 + s103 + + + + s96 + s107 + + + + s97 + s103 + + + + s97 + s110 + + + + s98 + s66 + + + + s98 + s99 + + + + s98 + s104 + + + + s99 + s38 + + + + s99 + s100 + + + + s99 + s104 + + + + s100 + s97 + + + + s100 + s105 + + + + s101 + s103 + + + + s101 + s109 + + + + s102 + s107 + + + + s102 + s110 + + + + s103 + s81 + + + + s104 + s42 + + + + s105 + s110 + + + + s107 + s81 + + + + s108 + s82 + + + + s108 + s103 + + + + s109 + s81 + + + + s110 + s81 + + + + s111 + s112 + + + true + + + + s112 + s113 + + + true + + + + s113 + s114 + + + true + + + + s114 + s115 + + + true + + + + s115 + s116 + + + true + + + + s116 + s117 + + + true + + + + s117 + s117 + + + true + + + + s118 + s119 + + + true + + + + s119 + s120 + + + true + + + + s120 + s121 + + + true + + + + s121 + s122 + + + true + + + + s122 + s123 + + + true + + + + s123 + s124 + + + true + + + + s124 + s124 + + + true + + + + s125 + s126 + + + true + + + + s126 + s126 + + + true + + + + s127 + s128 + + + true + + + + s128 + s129 + + + true + + + + s129 + s130 + + + true + + + + s130 + s131 + + + true + + + + s131 + s132 + + + true + + + + s132 + s133 + + + true + + + + s133 + s133 + + + true + + + + s134 + s135 + + + true + + + + s135 + s136 + + + true + + + + s136 + s136 + + + true + + + + s137 + s138 + + + true + + + + s138 + s139 + + + true + + + + s139 + s140 + + + true + + + + s140 + s141 + + + true + + + + s141 + s142 + + + true + + + + s142 + s143 + + + true + + + + s143 + s144 + + + true + + + + s144 + s145 + + + true + + + + s145 + s146 + + + true + + + + s146 + s146 + + + true + + + + s147 + s148 + + + true + + + + s148 + s149 + + + true + + + + s149 + s150 + + + true + + + + s150 + s150 + + + true + + + + s151 + s152 + + + true + + + + s152 + s152 + + + true + + + + s153 + s154 + + + true + + + + s154 + s155 + + + true + + + + s155 + s156 + + + true + + + + s156 + s157 + + + true + + + + s157 + s158 + + + true + + + + s158 + s159 + + + true + + + + s159 + s160 + + + true + + + + s160 + s160 + + + true + + + + s161 + s162 + + + true + + + + s162 + s163 + + + true + + + + s163 + s164 + + + true + + + + s164 + s164 + + + true + + + + s0 + s153 + + + true + + + + s0 + s1 + + + true + + + + s0 + s111 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/solutions.txt new file mode 100644 index 0000000000..efe48503c7 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system6/solutions.txt @@ -0,0 +1,10 @@ +true +true +true +false +true +false +true +true +true +false \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/properties.txt new file mode 100644 index 0000000000..c231fc4a2c --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/properties.txt @@ -0,0 +1,10 @@ +AG(([h] false) && (( true) -> ((A(([j] false) W ( true)))))) +A((([e] false) && ([i] false)) W ( true)) +(AG(([c] false) && ([e] false))) +A((([c] false) && ([g] false)) W (( true) || ( true))) +(AF(( true))) +A((([b] false) && ([f] false)) U (( true) || ( true))) +(AG(([b] false) && ([d] false))) +(AG(([d] false) && (( true) -> (AG(([g] false)))))) +A((( true) -> (AG(([h] false)))) U ( true)) +AG((([i] false) && ([f] false)) && (( true) -> ((A(([a] false) W ( true)))))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/seed.xml new file mode 100644 index 0000000000..eb16d73e6c --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/seed.xml @@ -0,0 +1,696 @@ + + + main + + + s14 + + + s9 + + + s25 + + + s17 + + + s52 + + + s12 + + + s34 + + + s40 + + + s27 + + + s35 + + + s51 + + + s5 + + + s10 + + + s7 + + + s21 + + + s53 + + + s13 + + + s37 + + + s4 + + + s3 + + + s6 + + + s22 + + + s39 + + + s36 + + + s42 + + + s43 + + + s24 + + + s28 + + + s33 + + + s20 + + + s31 + + + s8 + + + s30 + + + s32 + + + s2 + + + s29 + + + s44 + + + s11 + + + s54 + + + s26 + + + s16 + + + s0 + + true + + + + s38 + + + s48 + + + s50 + + + s19 + + + s18 + + + s15 + + + s47 + + + s45 + + + s46 + + + s41 + + + s55 + + + s49 + + + s1 + + + s23 + + + end + + + + + s10 + end + + + true + + + + s45 + s45 + + + true + + + + s46 + s47 + + + true + + + + s47 + s48 + + + true + + + + s48 + s48 + + + true + + + + s49 + s50 + + + true + + + + s50 + s51 + + + true + + + + s51 + s51 + + + true + + + + s52 + s53 + + + true + + + + s53 + s54 + + + true + + + + s54 + s55 + + + true + + + + s55 + s55 + + + true + + + + s1 + s3 + + + true + + + + s1 + s2 + + + true + + + + s5 + s8 + + + + s4 + s8 + + + + s6 + s10 + + + true + + + + s3 + s6 + + + true + + + + s6 + s11 + + + true + + + + s7 + s12 + + + + s2 + s4 + + + + s12 + s12 + + + + s8 + s12 + + + + s2 + s5 + + + true + + + + s5 + s9 + + + true + + + + s8 + s13 + + + + s9 + s13 + + + + s3 + s41 + + + true + + + + s10 + s14 + + + true + + + + s10 + s15 + + + + s11 + s15 + + + + s11 + s16 + + + true + + + + s12 + s12 + + + + s14 + s19 + + + + s4 + s7 + + + + s13 + s18 + + + + s14 + s17 + + + + s15 + s17 + + + + s15 + s19 + + + + s15 + s20 + + + + s16 + s20 + + + + s17 + s17 + + + + s17 + s17 + + + + s17 + s17 + + + + s18 + s18 + + + + s19 + s21 + + + + s20 + s21 + + + + s0 + s52 + + + true + + + + s20 + s22 + + + + s21 + s22 + + + + s22 + s22 + + + + s22 + s22 + + + + s23 + s24 + + + true + + + + s24 + s24 + + + true + + + + s25 + s26 + + + true + + + + s26 + s27 + + + true + + + + s27 + s27 + + + true + + + + s28 + s29 + + + true + + + + s29 + s30 + + + true + + + + s0 + s1 + + + true + + + + s30 + s30 + + + true + + + + s31 + s32 + + + true + + + + s32 + s33 + + + true + + + + s33 + s34 + + + true + + + + s34 + s34 + + + true + + + + s35 + s36 + + + true + + + + s36 + s37 + + + true + + + + s37 + s38 + + + true + + + + s38 + s39 + + + true + + + + s39 + s40 + + + true + + + + s40 + s40 + + + true + + + + s41 + s42 + + + true + + + + s42 + s43 + + + true + + + + s43 + s43 + + + true + + + + s44 + s45 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/solutions.txt new file mode 100644 index 0000000000..7cf6cfd3f5 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system7/solutions.txt @@ -0,0 +1,10 @@ +false +true +true +true +true +true +true +true +false +false \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/properties.txt new file mode 100644 index 0000000000..ce3c03b93d --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/properties.txt @@ -0,0 +1,10 @@ +A(([h] false) W (( true) || ( true))) +AG((( true) -> ((A(([b] false) W ( true))))) && (( true) -> ((A(([a] false) W ( true)))))) +A((( true) -> ((A(([e] false) U ( true))))) U ( true)) +AG((( true) -> ((A(([a] false) U ( true))))) && (([h] false) && ([c] false))) +A((([e] false) && ([i] false)) W (( true) || ( true))) +A(([c] false) U (( true) || ( true))) +(AG((( true) -> (AG(([b] false)))) && (( true) -> ((A(([c] false) U ( true))))))) +(AG(([e] false))) +A((([g] false) && ([i] false)) W ( true)) +AG((( true) -> ((A(([d] false) U ( true))))) && (( true) -> (AG(([c] false))))) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/seed.xml new file mode 100644 index 0000000000..2744a166ca --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/seed.xml @@ -0,0 +1,3399 @@ + + + main + + + s33 + + + s5 + + + s212 + + + s24 + + + s231 + + + s37 + + + s226 + + + s60 + + + s182 + + + s216 + + + s9 + + + s82 + + + s26 + + + s27 + + + s35 + + + s14 + + + s52 + + + s23 + + + s240 + + + s7 + + + s235 + + + s50 + + + s131 + + + s225 + + + s159 + + + s241 + + + s70 + + + s133 + + + s106 + + + s115 + + + s233 + + + s107 + + + s210 + + + s206 + + + s96 + + + s161 + + + s94 + + + s211 + + + s171 + + + s22 + + + s80 + + + s185 + + + s234 + + + s102 + + + s3 + + + s46 + + + s153 + + + s135 + + + s104 + + + s25 + + + s88 + + + s119 + + + s237 + + + s38 + + + s32 + + + s98 + + + s55 + + + s10 + + + s8 + + + s232 + + + s229 + + + s209 + + + s31 + + + s201 + + + s62 + + + s97 + + + s154 + + + s48 + + + s30 + + + s144 + + + s49 + + + s6 + + + s81 + + + s208 + + + s42 + + + s108 + + + s207 + + + s128 + + + s103 + + + s193 + + + s165 + + + s222 + + + s139 + + + s64 + + + s66 + + + s90 + + + s79 + + + s84 + + + s16 + + + s168 + + + s28 + + + s71 + + + s18 + + + s199 + + + s191 + + + s129 + + + s17 + + + s41 + + + s1 + + + s203 + + + s87 + + + s180 + + + s198 + + + s239 + + + s63 + + + s75 + + + s110 + + + s116 + + + s127 + + + s140 + + + s221 + + + s57 + + + s73 + + + s34 + + + s227 + + + s166 + + + s86 + + + s72 + + + s123 + + + s78 + + + s162 + + + s36 + + + s47 + + + s20 + + + s93 + + + s169 + + + s175 + + + s215 + + + s137 + + + s59 + + + s155 + + + s228 + + + s68 + + + s223 + + + s236 + + + s192 + + + s214 + + + s186 + + + s117 + + + s238 + + + s15 + + + s40 + + + s200 + + + s218 + + + s43 + + + s114 + + + s13 + + + s149 + + + s12 + + + s196 + + + s136 + + + s29 + + + s213 + + + s205 + + + s120 + + + s85 + + + s219 + + + s220 + + + s143 + + + s11 + + + s39 + + + s142 + + + s65 + + + s99 + + + s92 + + + s4 + + + s224 + + + s132 + + + s134 + + + s54 + + + s125 + + + s21 + + + s204 + + + s113 + + + s122 + + + s19 + + + s100 + + + s0 + + true + + + + s67 + + + s160 + + + s58 + + + s230 + + + s91 + + + s217 + + + s74 + + + s146 + + + s44 + + + s51 + + + s130 + + + s151 + + + s45 + + + s76 + + + s202 + + + s53 + + + s89 + + + s56 + + + s111 + + + s2 + + + s158 + + + s83 + + + s10 + + + end + + + + + s180 + end + + + true + + + + s80 + s90 + + + + s80 + s128 + + + + s80 + s129 + + + + s81 + s78 + + + + s81 + s130 + + + true + + + + s81 + s131 + + + + s82 + s130 + + + + s82 + s132 + + + + s83 + s66 + + + + s83 + s132 + + + + s83 + s133 + + + + s84 + s92 + + + + s84 + s132 + + + + s84 + s134 + + + + s85 + s80 + + + + s85 + s93 + + + + s85 + s133 + + + + s85 + s134 + + + + s86 + s62 + + + + s86 + s110 + + + + s86 + s135 + + + + s87 + s65 + + + + s87 + s135 + + + + s87 + s136 + + + + s88 + s137 + + + + s89 + s129 + + + + s89 + s135 + + + + s89 + s139 + + + + s90 + s93 + + + + s90 + s139 + + + + s90 + s140 + + + + s91 + s89 + + + + s91 + s114 + + + + s91 + s134 + + + + s91 + s142 + + + + s92 + s142 + + + + s92 + s143 + + + + s92 + s144 + + + + s93 + s142 + + + + s93 + s146 + + + + s94 + s66 + + + + s94 + s143 + + + + s94 + s144 + + + + s94 + s146 + + + + s96 + s67 + + + + s96 + s96 + + + + s96 + s96 + + + + s96 + s96 + + + + s96 + s96 + + + + s96 + s96 + + + + s96 + s225 + + + + s97 + s68 + + + + s97 + s144 + + + + s97 + s228 + + + true + + + + s98 + s123 + + + + s98 + s216 + + + true + + + + s99 + s104 + + + + s99 + s149 + + + true + + + + s100 + s74 + + + + s100 + s106 + + + + s100 + s149 + + + + s100 + s151 + + + true + + + + s102 + s75 + + + + s102 + s149 + + + + s102 + s153 + + + + s102 + s154 + + + true + + + + s103 + s99 + + + + s103 + s155 + + + + s104 + s92 + + + + s104 + s153 + + + + s106 + s76 + + + + s106 + s94 + + + + s106 + s153 + + + + s107 + s40 + + + + s107 + s94 + + + + s107 + s151 + + + + s107 + s154 + + + + s108 + s74 + + + + s108 + s155 + + + + s111 + s135 + + + + s111 + s159 + + + + s113 + s117 + + + + s113 + s140 + + + + s113 + s159 + + + + s114 + s160 + + + + s115 + s143 + + + + s115 + s160 + + + + s115 + s235 + + + + s116 + s143 + + + + s116 + s160 + + + + s117 + s160 + + + + s119 + s73 + + + + s119 + s87 + + + + s119 + s161 + + + + s120 + s111 + + + + s120 + s161 + + + + s120 + s162 + + + true + + + + s122 + s114 + + + + s123 + s125 + + + + s125 + s116 + + + + s127 + s110 + + + + s127 + s165 + + + + s128 + s136 + + + + s128 + s165 + + + + s129 + s139 + + + + s129 + s165 + + + + s130 + s110 + + + + s130 + s127 + + + + s130 + s166 + + + true + + + + s131 + s113 + + + + s131 + s128 + + + + s131 + s166 + + + + s132 + s116 + + + + s132 + s168 + + + + s133 + s117 + + + + s133 + s128 + + + + s133 + s168 + + + + s134 + s129 + + + + s134 + s142 + + + + s134 + s168 + + + + s1 + s5 + + + + s135 + s114 + + + + s135 + s169 + + + + s136 + s117 + + + + s136 + s169 + + + + s137 + s110 + + + + s137 + s171 + + + + s139 + s142 + + + + s139 + s171 + + + + s140 + s136 + + + + s140 + s171 + + + + s142 + s175 + + + + s143 + s115 + + + + s143 + s143 + + + + s143 + s143 + + + + s143 + s143 + + + + s143 + s143 + + + + s143 + s143 + + + + s143 + s143 + + + + s143 + s175 + + + + s144 + s116 + + + + s144 + s143 + + + + s144 + s143 + + + + s144 + s143 + + + + s144 + s143 + + + + s144 + s143 + + + + s144 + s143 + + + + s144 + s175 + + + + s146 + s117 + + + + s146 + s140 + + + + s146 + s175 + + + + s149 + s123 + + + + s149 + s153 + + + + s149 + s180 + + + true + + + + s151 + s74 + + + + s151 + s94 + + + + s151 + s180 + + + + s151 + s182 + + + true + + + + s153 + s125 + + + + s153 + s144 + + + + s154 + s75 + + + + s154 + s143 + + + + s154 + s144 + + + + s154 + s180 + + + + s154 + s238 + + + true + + + + s155 + s123 + + + + s158 + s111 + + + + s158 + s114 + + + + s0 + s4 + + + + s2 + s9 + + + true + + + + s3 + s11 + + + true + + + + s2 + s8 + + + true + + + + s3 + s8 + + + + s3 + s13 + + + + s2 + s5 + + + + s4 + s7 + + + + s4 + s9 + + + + s1 + s6 + + + true + + + + s7 + s18 + + + + s4 + s12 + + + + s1 + s7 + + + true + + + + s3 + s12 + + + true + + + + s5 + s14 + + + + s5 + s15 + + + + s5 + s16 + + + + s2 + s10 + + + + s6 + s14 + + + + s6 + s17 + + + true + + + + s6 + s18 + + + + s6 + s19 + + + + s7 + s15 + + + + s8 + s20 + + + true + + + + s3 + s6 + + + + s7 + s221 + + + true + + + + s8 + s14 + + + + s8 + s21 + + + + s8 + s22 + + + + s8 + s23 + + + + s9 + s15 + + + + s9 + s22 + + + + s9 + s24 + + + true + + + + s10 + s16 + + + + s10 + s23 + + + + s10 + s24 + + + + s10 + s25 + + + + s11 + s26 + + + true + + + + s11 + s27 + + + true + + + + s11 + s28 + + + true + + + + s12 + s18 + + + + s12 + s22 + + + + s12 + s27 + + + + s12 + s29 + + + true + + + + s13 + s19 + + + + s13 + s23 + + + + s13 + s28 + + + + s13 + s29 + + + + s13 + s30 + + + + s14 + s31 + + + + s14 + s32 + + + + s14 + s33 + + + + s15 + s32 + + + + s15 + s34 + + + + s16 + s33 + + + + s16 + s34 + + + + s16 + s35 + + + + s17 + s14 + + + + s17 + s36 + + + true + + + + s17 + s37 + + + + s17 + s38 + + + + s18 + s32 + + + + s18 + s37 + + + + s18 + s39 + + + + s19 + s33 + + + + s19 + s38 + + + + s19 + s39 + + + + s158 + s160 + + + + s159 + s160 + + + + s159 + s171 + + + + s161 + s122 + + + + s161 + s135 + + + + s162 + s122 + + + + s162 + s158 + + + + s162 + s205 + + + true + + + + s165 + s169 + + + + s166 + s159 + + + + s166 + s165 + + + + s166 + s185 + + + true + + + + s168 + s160 + + + + s168 + s165 + + + + s169 + s171 + + + + s169 + s186 + + + + s171 + s169 + + + + s171 + s171 + + + + s171 + s171 + + + + s171 + s171 + + + + s171 + s171 + + + + s171 + s171 + + + + s171 + s171 + + + + s171 + s175 + + + + s175 + s160 + + + + s175 + s171 + + + + s180 + s123 + + + + s180 + s143 + + + + s180 + s144 + + + + s180 + s191 + + + true + + + + s182 + s146 + + + + s182 + s191 + + + + s182 + s192 + + + true + + + + s185 + s160 + + + + s185 + s168 + + + + s186 + s193 + + + + s191 + s175 + + + + s191 + s196 + + + true + + + + s192 + s140 + + + + s192 + s196 + + + + s192 + s209 + + + true + + + + s193 + s160 + + + + s193 + s171 + + + + s193 + s175 + + + + s193 + s175 + + + + s193 + s175 + + + + s193 + s175 + + + + s193 + s175 + + + + s193 + s175 + + + + s196 + s171 + + + + s196 + s202 + + + true + + + + s198 + s199 + + + true + + + + s199 + s200 + + + true + + + + s200 + s201 + + + true + + + + s201 + s201 + + + true + + + + s202 + s203 + + + true + + + + s203 + s204 + + + true + + + + s204 + s203 + + + true + + + + s205 + s206 + + + true + + + + s206 + s207 + + + true + + + + s207 + s208 + + + true + + + + s208 + s207 + + + true + + + + s209 + s210 + + + true + + + + s210 + s211 + + + true + + + + s211 + s210 + + + true + + + + s212 + s213 + + + true + + + + s213 + s214 + + + true + + + + s214 + s215 + + + true + + + + s215 + s215 + + + true + + + + s216 + s217 + + + true + + + + s217 + s218 + + + true + + + + s218 + s219 + + + true + + + + s219 + s220 + + + true + + + + s220 + s220 + + + true + + + + s221 + s222 + + + true + + + + s222 + s223 + + + true + + + + s223 + s224 + + + true + + + + s224 + s223 + + + true + + + + s225 + s226 + + + + s226 + s227 + + + + s227 + s226 + + + + s228 + s229 + + + true + + + + s229 + s230 + + + true + + + + s230 + s229 + + + true + + + + s231 + s232 + + + true + + + + s232 + s233 + + + true + + + + s233 + s234 + + + true + + + + s234 + s233 + + + true + + + + s235 + s236 + + + + s236 + s237 + + + + s237 + s235 + + + + s238 + s239 + + + true + + + + s239 + s240 + + + true + + + + s240 + s241 + + + true + + + + s241 + s240 + + + true + + + + s0 + s3 + + + true + + + + s0 + s1 + + + true + + + + s0 + s2 + + + true + + + + s19 + s40 + + + + s20 + s41 + + + true + + + + s20 + s42 + + + true + + + + s20 + s43 + + + + s20 + s44 + + + + s21 + s41 + + + + s21 + s45 + + + + s21 + s46 + + + + s21 + s47 + + + + s22 + s32 + + + + s22 + s43 + + + + s22 + s46 + + + + s22 + s48 + + + + s23 + s33 + + + + s23 + s44 + + + + s23 + s48 + + + + s23 + s49 + + + + s23 + s50 + + + + s24 + s34 + + + + s24 + s48 + + + + s24 + s51 + + + true + + + + s25 + s50 + + + + s25 + s51 + + + + s25 + s52 + + + + s26 + s53 + + + true + + + + s26 + s54 + + + + s27 + s53 + + + + s27 + s55 + + + true + + + + s28 + s54 + + + + s28 + s55 + + + + s28 + s56 + + + true + + + + s29 + s39 + + + + s29 + s48 + + + + s29 + s55 + + + + s29 + s57 + + + true + + + + s30 + s57 + + + + s30 + s58 + + + + s30 + s59 + + + + s30 + s60 + + + + s31 + s62 + + + + s31 + s63 + + + + s32 + s62 + + + + s32 + s64 + + + + s33 + s64 + + + + s33 + s65 + + + + s33 + s66 + + + + s34 + s64 + + + + s34 + s67 + + + + s34 + s68 + + + + s35 + s66 + + + + s35 + s67 + + + + s35 + s68 + + + + s36 + s31 + + + + s36 + s70 + + + true + + + + s36 + s71 + + + + s37 + s32 + + + + s37 + s70 + + + + s37 + s72 + + + + s38 + s33 + + + + s38 + s72 + + + + s38 + s73 + + + + s38 + s74 + + + + s39 + s64 + + + + s39 + s72 + + + + s39 + s75 + + + + s40 + s74 + + + + s40 + s75 + + + + s40 + s76 + + + + s41 + s78 + + + true + + + + s41 + s79 + + + + s41 + s80 + + + + s42 + s81 + + + true + + + + s42 + s82 + + + true + + + + s42 + s83 + + + + s43 + s79 + + + + s43 + s82 + + + + s43 + s84 + + + + s44 + s50 + + + + s44 + s83 + + + + s44 + s84 + + + + s44 + s85 + + + + s45 + s31 + + + + s45 + s86 + + + + s45 + s87 + + + + s46 + s79 + + + + s46 + s86 + + + + s46 + s88 + + + + s46 + s89 + + + + s47 + s80 + + + + s47 + s87 + + + + s47 + s89 + + + + s47 + s90 + + + + s48 + s64 + + + + s48 + s84 + + + + s48 + s91 + + + + s48 + s92 + + + + s49 + s47 + + + + s49 + s65 + + + + s49 + s85 + + + + s49 + s91 + + + + s49 + s93 + + + + s50 + s92 + + + + s50 + s93 + + + + s50 + s94 + + + + s51 + s92 + + + + s51 + s96 + + + + s51 + s97 + + + true + + + + s52 + s35 + + + + s52 + s94 + + + + s52 + s96 + + + + s52 + s97 + + + + s53 + s98 + + + true + + + + s54 + s74 + + + + s54 + s98 + + + + s55 + s98 + + + + s55 + s99 + + + true + + + + s56 + s60 + + + + s56 + s99 + + + + s56 + s100 + + + true + + + + s57 + s102 + + + true + + + + s57 + s103 + + + + s57 + s104 + + + + s58 + s40 + + + + s58 + s100 + + + + s58 + s102 + + + + s58 + s106 + + + + s58 + s107 + + + + s59 + s56 + + + + s59 + s103 + + + + s59 + s108 + + + + s60 + s50 + + + + s60 + s104 + + + + s60 + s106 + + + + s62 + s110 + + + + s62 + s111 + + + + s63 + s87 + + + + s63 + s111 + + + + s63 + s113 + + + + s64 + s114 + + + + s64 + s116 + + + + s65 + s114 + + + + s65 + s117 + + + + s66 + s116 + + + + s66 + s117 + + + + s67 + s96 + + + + s68 + s116 + + + + s70 + s62 + + + + s70 + s120 + + + true + + + + s71 + s63 + + + + s71 + s119 + + + + s71 + s120 + + + + s72 + s64 + + + + s72 + s122 + + + + s72 + s123 + + + + s73 + s65 + + + + s73 + s122 + + + + s74 + s76 + + + + s74 + s123 + + + + s75 + s123 + + + + s75 + s125 + + + + s76 + s66 + + + + s76 + s125 + + + + s78 + s127 + + + + s78 + s128 + + + + s79 + s88 + + + + s79 + s127 + + + + s79 + s129 + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/solutions.txt new file mode 100644 index 0000000000..dcc9cbb232 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system8/solutions.txt @@ -0,0 +1,10 @@ +true +false +true +false +true +true +false +false +true +false \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/properties.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/properties.txt new file mode 100644 index 0000000000..249f55d815 --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/properties.txt @@ -0,0 +1,10 @@ +(AG(( true) -> (AG(([a] false))))) +(AG(([c] false))) +A((([b] false) && ([j] false)) U (( true) || ( true))) +AG((( true) -> ((A(([d] false) W ( true))))) && (([b] false) && ([h] false))) +A((( true) -> (AG(([j] false)))) W (( true) || ( true))) +A((([d] false) && ([i] false)) W (( true) || ( true))) +A((( true) -> (AG(([b] false)))) U ( true)) +AG((( true) -> ((A(([j] false) U ( true))))) && (( true) -> ((A(([c] false) U ( true)))))) +AG((( true) -> (AF( true))) && (( true) -> (AF( true)))) +A((([e] false) && ([f] false)) W ( true)) \ No newline at end of file diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/seed.xml b/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/seed.xml new file mode 100644 index 0000000000..b9520bc03f --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/seed.xml @@ -0,0 +1,1399 @@ + + + main + + + s37 + + + s2 + + + s40 + + + s17 + + + s33 + + + s13 + + + s55 + + + s7 + + + s54 + + + s36 + + + s53 + + + s3 + + + s15 + + + s66 + + + s29 + + + s32 + + + s19 + + + s63 + + + s20 + + + s62 + + + s59 + + + s47 + + + s1 + + + s81 + + + s30 + + + s83 + + + s10 + + + s80 + + + s70 + + + s78 + + + s12 + + + s82 + + + s41 + + + s18 + + + s35 + + + s69 + + + s50 + + + s58 + + + s56 + + + s60 + + + s44 + + + s6 + + + s68 + + + s31 + + + s39 + + + s45 + + + s5 + + + s8 + + + s71 + + + s21 + + + s24 + + + s46 + + + s4 + + + s16 + + + s72 + + + s43 + + + s57 + + + s67 + + + s42 + + + s74 + + + s26 + + + s61 + + + s73 + + + s77 + + + s28 + + + s34 + + + s51 + + + s9 + + + s0 + + true + + + + s11 + + + s27 + + + s23 + + + s14 + + + s75 + + + s22 + + + s38 + + + s52 + + + s49 + + + s76 + + + s79 + + + s64 + + + s48 + + + s65 + + + end + + + + + s10 + end + + + true + + + + s27 + s36 + + + + s51 + s51 + + + + s28 + s37 + + + + s51 + s51 + + + + s29 + s38 + + + + s51 + s51 + + + + s30 + s30 + + + + s51 + s51 + + + + s30 + s30 + + + + s52 + s51 + + + + s30 + s30 + + + + s52 + s51 + + + + s30 + s30 + + + + s52 + s51 + + + + s30 + s30 + + + + s52 + s51 + + + + s30 + s30 + + + + s52 + s51 + + + + s30 + s39 + + + + s31 + s38 + + + + s31 + s40 + + + + s52 + s61 + + + true + + + + s32 + s17 + + + + s53 + s54 + + + true + + + + s32 + s41 + + + true + + + + s54 + s54 + + + true + + + + s32 + s42 + + + + s55 + s56 + + + true + + + + s3 + s4 + + + true + + + + s33 + s20 + + + + s56 + s56 + + + true + + + + s33 + s28 + + + + s57 + s58 + + + true + + + + s33 + s42 + + + + s58 + s59 + + + true + + + + s59 + s60 + + + true + + + + s4 + s11 + + + true + + + + s34 + s35 + + + + s60 + s60 + + + true + + + + s2 + s7 + + + + s34 + s43 + + + true + + + + s61 + s62 + + + true + + + + s4 + s10 + + + + s34 + s44 + + + + s62 + s62 + + + true + + + + s5 + s12 + + + + s35 + s39 + + + + s63 + s64 + + + true + + + + s2 + s6 + + + true + + + + s35 + s45 + + + + s64 + s65 + + + true + + + + s5 + s13 + + + + s36 + s30 + + + + s65 + s66 + + + true + + + + s6 + s8 + + + + s36 + s30 + + + + s66 + s67 + + + true + + + + s2 + s3 + + + + s36 + s30 + + + + s67 + s67 + + + true + + + + s9 + s17 + + + + s36 + s30 + + + + s68 + s69 + + + true + + + + s6 + s12 + + + + s36 + s30 + + + + s69 + s69 + + + true + + + + s2 + s5 + + + + s36 + s30 + + + + s70 + s71 + + + true + + + + s5 + s3 + + + + s36 + s39 + + + + s71 + s71 + + + true + + + + s6 + s14 + + + true + + + + s36 + s45 + + + + s72 + s73 + + + true + + + + s6 + s15 + + + + s37 + s37 + + + + s73 + s74 + + + true + + + + s6 + s16 + + + + s37 + s37 + + + + s74 + s74 + + + true + + + + s3 + s8 + + + true + + + + s37 + s37 + + + + s75 + s76 + + + true + + + + s7 + s9 + + + + s37 + s37 + + + + s76 + s76 + + + true + + + + s7 + s15 + + + + s37 + s37 + + + + s77 + s78 + + + true + + + + s1 + s77 + + + true + + + + s8 + s17 + + + + s37 + s37 + + + + s8 + s18 + + + true + + + + s37 + s37 + + + + s78 + s79 + + + true + + + + s9 + s17 + + + + s38 + s38 + + + + s79 + s80 + + + true + + + + s10 + s20 + + + + s38 + s38 + + + + s80 + s81 + + + true + + + + s3 + s9 + + + + s38 + s38 + + + + s81 + s82 + + + true + + + + s10 + s8 + + + + s38 + s38 + + + + s82 + s83 + + + true + + + + s10 + s19 + + + + s38 + s38 + + + + s83 + s83 + + + true + + + + s11 + s9 + + + + s38 + s38 + + + + s11 + s19 + + + + s39 + s39 + + + + s11 + s68 + + + true + + + + s39 + s39 + + + + s12 + s8 + + + + s39 + s39 + + + + s12 + s21 + + + + s39 + s39 + + + + s12 + s22 + + + + s39 + s39 + + + + s12 + s23 + + + + s39 + s39 + + + + s13 + s9 + + + + s40 + s38 + + + + s13 + s22 + + + + s40 + s38 + + + + s14 + s15 + + + + s40 + s38 + + + + s14 + s21 + + + + s40 + s38 + + + + s14 + s24 + + + true + + + + s40 + s38 + + + + s14 + s26 + + + true + + + + s40 + s38 + + + + s41 + s19 + + + + s15 + s17 + + + + s41 + s46 + + + + s15 + s27 + + + + s41 + s70 + + + true + + + + s16 + s23 + + + + s42 + s28 + + + + s16 + s26 + + + + s42 + s46 + + + + s16 + s27 + + + + s42 + s47 + + + + s17 + s28 + + + + s43 + s48 + + + true + + + + s18 + s20 + + + + s43 + s49 + + + + s18 + s28 + + + + s44 + s39 + + + + s18 + s57 + + + true + + + + s44 + s45 + + + + s19 + s17 + + + + s44 + s49 + + + + s19 + s29 + + + + s45 + s39 + + + + s20 + s29 + + + + s45 + s39 + + + + s21 + s22 + + + + s45 + s39 + + + + s21 + s23 + + + + s45 + s39 + + + + s21 + s24 + + + + s45 + s39 + + + + s22 + s17 + + + + s45 + s39 + + + + s22 + s31 + + + + s46 + s29 + + + + s23 + s31 + + + + s46 + s50 + + + + s24 + s17 + + + + s47 + s37 + + + + s24 + s32 + + + true + + + + s47 + s50 + + + + s24 + s33 + + + true + + + + s48 + s51 + + + + s26 + s23 + + + + s48 + s52 + + + true + + + + s26 + s27 + + + + s49 + s51 + + + + s26 + s34 + + + true + + + + s49 + s52 + + + + s27 + s30 + + + + s50 + s38 + + + + s27 + s35 + + + + s51 + s51 + + + + s1 + s3 + + + true + + + + s0 + s1 + + + true + + + + s0 + s2 + + + true + + + + + diff --git a/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/solutions.txt b/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/solutions.txt new file mode 100644 index 0000000000..dd49fefb3e --- /dev/null +++ b/modelchecking/m3c/src/test/resources/cfmps/setting2/system9/solutions.txt @@ -0,0 +1,10 @@ +false +true +true +false +true +true +false +false +false +true \ No newline at end of file diff --git a/modelchecking/pom.xml b/modelchecking/pom.xml index db572c79d4..4dc408c328 100644 --- a/modelchecking/pom.xml +++ b/modelchecking/pom.xml @@ -33,5 +33,6 @@ limitations under the License. ltsmin + m3c diff --git a/pom.xml b/pom.xml index b63cb3d2b9..b0332e7b8d 100644 --- a/pom.xml +++ b/pom.xml @@ -84,6 +84,14 @@ limitations under the License. Developer + + Alnis Murtovi + TU Dortmund University, Chair of Programming Systems + http://ls5-www.cs.tu-dortmund.de/ + + Developer + + Maximilian Schlüter TU Dortmund, Chair for Programming Systems @@ -225,6 +233,7 @@ limitations under the License. 1.1.0 + 2.0.20-BETA-SNAPSHOT 0.1 1.11-8 1.10 @@ -375,6 +384,12 @@ limitations under the License. ${project.version} + + net.automatalib + automata-modelchecking-m3c + ${project.version} + + net.automatalib @@ -505,7 +520,7 @@ limitations under the License. graphviz-awt-shapes ${graphviz-awt-shapes.version} - + com.github.misberner.buildergen buildergen @@ -547,6 +562,18 @@ limitations under the License. ${logback.version} + + info.scce + addlib-core + ${addlib.version} + + + + info.scce + addlib-cudd + ${addlib.version} + + org.testng testng @@ -577,6 +604,20 @@ limitations under the License. + + + + maven-central + Maven Central Repository + https://repo.maven.apache.org/maven2/ + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + diff --git a/serialization/dot/src/test/java/net/automatalib/serialization/dot/DOTSerializationTest.java b/serialization/dot/src/test/java/net/automatalib/serialization/dot/DOTSerializationTest.java index 9638457d02..d2f424f7f6 100644 --- a/serialization/dot/src/test/java/net/automatalib/serialization/dot/DOTSerializationTest.java +++ b/serialization/dot/src/test/java/net/automatalib/serialization/dot/DOTSerializationTest.java @@ -37,6 +37,7 @@ import net.automatalib.commons.util.IOUtil; import net.automatalib.commons.util.io.UnclosableOutputStream; import net.automatalib.graphs.Graph; +import net.automatalib.graphs.base.DefaultMCFPS; import net.automatalib.graphs.base.compact.CompactEdge; import net.automatalib.graphs.base.compact.CompactGraph; import net.automatalib.ts.modal.CompactMC; @@ -145,6 +146,15 @@ public void writePreamble(Appendable a) throws IOException { checkDOTOutput(writer, DOTSerializationUtil.CLUSTER_RESOURCE); } + @Test + public void testMCFPSExport() throws IOException { + + final DefaultMCFPS cfmps = DOTSerializationUtil.CFMPS; + + ThrowingWriter writer = w -> GraphDOT.write(cfmps, w); + checkDOTOutput(writer, DOTSerializationUtil.MCFPS_RESOURCE); + } + @Test public void testVisualizationHelper() throws IOException { diff --git a/serialization/dot/src/test/java/net/automatalib/serialization/dot/DOTSerializationUtil.java b/serialization/dot/src/test/java/net/automatalib/serialization/dot/DOTSerializationUtil.java index 0f05101fdb..61a6f0c7ea 100644 --- a/serialization/dot/src/test/java/net/automatalib/serialization/dot/DOTSerializationUtil.java +++ b/serialization/dot/src/test/java/net/automatalib/serialization/dot/DOTSerializationUtil.java @@ -16,17 +16,27 @@ package net.automatalib.serialization.dot; import java.net.URL; +import java.util.Collections; +import java.util.Map; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import net.automatalib.automata.fsa.impl.compact.CompactDFA; import net.automatalib.automata.fsa.impl.compact.CompactNFA; import net.automatalib.automata.transducers.impl.compact.CompactMealy; import net.automatalib.automata.transducers.impl.compact.CompactMoore; import net.automatalib.automata.transducers.impl.compact.CompactSST; +import net.automatalib.graphs.base.DefaultMCFPS; import net.automatalib.graphs.base.compact.CompactGraph; +import net.automatalib.graphs.base.compact.CompactPMPG; +import net.automatalib.graphs.base.compact.CompactPMPGEdge; import net.automatalib.ts.modal.CompactMC; import net.automatalib.ts.modal.CompactMTS; import net.automatalib.ts.modal.transition.ModalContractEdgeProperty.EdgeColor; import net.automatalib.ts.modal.transition.ModalEdgeProperty.ModalType; +import net.automatalib.ts.modal.transition.MutableProceduralModalEdgeProperty; +import net.automatalib.ts.modal.transition.ProceduralModalEdgeProperty.ProceduralType; +import net.automatalib.ts.modal.transition.ProceduralModalEdgePropertyImpl; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; @@ -46,6 +56,7 @@ final class DOTSerializationUtil { static final String MTS_RESOURCE = "/mts.dot"; static final String MC_RESOURCE = "/mc.dot"; static final String CLUSTER_RESOURCE = "/cluster.dot"; + static final String MCFPS_RESOURCE = "/cfmps.dot"; static final String FAULTY_AUTOMATON_RESOURCE = "/faulty_automaton.dot"; static final String FAULTY_GRAPH_RESOURCE = "/faulty_graph.dot"; @@ -63,6 +74,7 @@ final class DOTSerializationUtil { static final CompactGraph GRAPH; static final CompactMTS MTS; static final CompactMC MC; + static final DefaultMCFPS CFMPS; static { STRING_ALPHABET = Alphabets.closedCharStringRange('a', 'c'); @@ -76,6 +88,7 @@ final class DOTSerializationUtil { GRAPH = buildGraph(); MTS = buildMTS(); MC = buildMC(); + CFMPS = buildMCFPS(); } private DOTSerializationUtil() {} @@ -231,4 +244,46 @@ private static CompactMC buildMC() { return result; } + + private static DefaultMCFPS buildMCFPS() { + final ProceduralModalEdgePropertyImpl p1 = + new ProceduralModalEdgePropertyImpl(ProceduralType.INTERNAL, ModalType.MUST); + final ProceduralModalEdgePropertyImpl p2 = + new ProceduralModalEdgePropertyImpl(ProceduralType.INTERNAL, ModalType.MAY); + final ProceduralModalEdgePropertyImpl p3 = + new ProceduralModalEdgePropertyImpl(ProceduralType.PROCESS, ModalType.MUST); + final ProceduralModalEdgePropertyImpl p4 = + new ProceduralModalEdgePropertyImpl(ProceduralType.PROCESS, ModalType.MAY); + + final CompactPMPG s = new CompactPMPG<>('?'); + final int s0 = s.addIntNode(); + final int s1 = s.addIntNode(Sets.newHashSet('a', 'b')); + final int s2 = s.addIntNode(Collections.singleton('c')); + + final CompactPMPGEdge e1 = s.connect(s0, s1, p1); + final CompactPMPGEdge e2 = s.connect(s0, s1, p2); + final CompactPMPGEdge e3 = s.connect(s1, s2, p3); + final CompactPMPGEdge e4 = s.connect(s2, s0, p4); + + s.setEdgeLabel(e1, '1'); + s.setEdgeLabel(e2, '2'); + s.setEdgeLabel(e3, '3'); + s.setEdgeLabel(e4, '4'); + s.setInitialNode(s0); + + final CompactPMPG t = new CompactPMPG<>('?'); + final int t0 = t.addIntNode(); + final int t1 = t.addIntNode(Collections.singleton('d')); + + t.connect(t0, t1, p1); + t.connect(t0, t1, p2); + t.connect(t1, t1, p3); + t.connect(t1, t0, p4); + + final Map> pmpgs = Maps.newHashMapWithExpectedSize(2); + pmpgs.put('s', s); + pmpgs.put('t', t); + + return new DefaultMCFPS<>('s', pmpgs); + } } diff --git a/serialization/dot/src/test/resources/cfmps.dot b/serialization/dot/src/test/resources/cfmps.dot new file mode 100644 index 0000000000..ed6cde3c46 --- /dev/null +++ b/serialization/dot/src/test/resources/cfmps.dot @@ -0,0 +1,20 @@ +digraph g { + + s0 [shape="circle" label=""]; + s1 [shape="circle" label="[d]"]; + s2 [shape="circle" label=""]; + s3 [shape="circle" label="[a, b]"]; + s4 [shape="circle" label="[c]"]; + s0 -> s1 [style="" label="?"]; + s0 -> s1 [style="dashed" label="?"]; + s1 -> s1 [style="bold" label="?"]; + s1 -> s0 [style="dashed,bold" label="?"]; + s2 -> s3 [style="" label="1"]; + s2 -> s3 [style="dashed" label="2"]; + s3 -> s4 [style="bold" label="3"]; + s4 -> s2 [style="dashed,bold" label="4"]; + +__start0 [label="" shape="none" width="0" height="0"]; +__start0 -> s2; + +} diff --git a/util/src/main/java/net/automatalib/util/ts/modal/MCUtil.java b/util/src/main/java/net/automatalib/util/ts/modal/MCUtil.java index d5d5b5ae6a..c14fe41ee3 100644 --- a/util/src/main/java/net/automatalib/util/ts/modal/MCUtil.java +++ b/util/src/main/java/net/automatalib/util/ts/modal/MCUtil.java @@ -232,7 +232,7 @@ public static , S1, I, T, T x -> new ModalEdgePropertyImpl( contract.getTransitionProperty( x) - .getType()), + .getModalType()), () -> new ModalEdgePropertyImpl( ModalType.MAY)); @@ -250,7 +250,7 @@ public static , S1, I, T, T x -> new ModalEdgePropertyImpl( contract.getTransitionProperty( x) - .getType()), + .getModalType()), () -> new ModalEdgePropertyImpl( ModalType.MAY)); diff --git a/util/src/main/java/net/automatalib/util/ts/modal/ModalParallelComposition.java b/util/src/main/java/net/automatalib/util/ts/modal/ModalParallelComposition.java index 57fca9ca04..ac4d8c1050 100644 --- a/util/src/main/java/net/automatalib/util/ts/modal/ModalParallelComposition.java +++ b/util/src/main/java/net/automatalib/util/ts/modal/ModalParallelComposition.java @@ -118,17 +118,17 @@ protected List> generateNewTransitions(Pair pr newTransitions.add(new TransitionData<>(symbol, Pair.of(mts0.getSuccessor(transition), productState.getSecond()), - mts0.getTransitionProperty(transition).getType())); + mts0.getTransitionProperty(transition).getModalType())); } else { for (T1 partnerTransition : mts1.getTransitions(productState.getSecond(), symbol)) { newTransitions.add(new TransitionData<>(symbol, Pair.of(mts0.getSuccessor(transition), mts1.getSuccessor(partnerTransition)), minimalCompatibleType(mts0.getTransitionProperty( - transition).getType(), + transition).getModalType(), mts1.getTransitionProperty( partnerTransition) - .getType()))); + .getModalType()))); } } } @@ -141,7 +141,7 @@ protected List> generateNewTransitions(Pair pr for (T1 transition : mts1.getTransitions(productState.getSecond(), symbol)) { newTransitions.add(new TransitionData<>(symbol, Pair.of(productState.getFirst(), mts1.getSuccessor(transition)), - mts1.getTransitionProperty(transition).getType())); + mts1.getTransitionProperty(transition).getModalType())); } } diff --git a/util/src/main/java/net/automatalib/util/ts/modal/ModalRefinement.java b/util/src/main/java/net/automatalib/util/ts/modal/ModalRefinement.java index 407b1f3043..c8d65637b9 100644 --- a/util/src/main/java/net/automatalib/util/ts/modal/ModalRefinement.java +++ b/util/src/main/java/net/automatalib/util/ts/modal/ModalRefinement.java @@ -44,7 +44,7 @@ private static Set partnerTransit for (BT candidateTransition : b.getTransitions(source, input)) { BTP property = b.getTransitionProperty(candidateTransition); - if (property != null && acceptableValues.contains(property.getType())) { + if (property != null && acceptableValues.contains(property.getModalType())) { coTransitions.add(candidateTransition); } } @@ -62,7 +62,7 @@ private static boolean eligiblePartner(ModalTransitionSystem for (I label : inputs) { for (AT transition : a.getTransitions(source, label)) { - if (!acceptableValues.contains(a.getTransitionProperty(transition).getType())) { + if (!acceptableValues.contains(a.getTransitionProperty(transition).getModalType())) { continue; } diff --git a/util/src/test/java/net/automatalib/util/ts/modal/regression/RegressionTests.java b/util/src/test/java/net/automatalib/util/ts/modal/regression/RegressionTests.java index 18b4833379..f9a6339618 100644 --- a/util/src/test/java/net/automatalib/util/ts/modal/regression/RegressionTests.java +++ b/util/src/test/java/net/automatalib/util/ts/modal/regression/RegressionTests.java @@ -78,7 +78,7 @@ public void testDecompContext(DecompositionTest testCase) throws IOException { new CompactMTS.Creator<>(), (x) -> new ModalEdgePropertyImpl( x.getProperty() - .getType()), + .getModalType()), () -> new ModalEdgePropertyImpl( ModalType.MAY)); @@ -112,7 +112,7 @@ public void testDecompContextReverse(DecompositionTest testCase) throws IOExcept new CompactMTS.Creator<>(), (x) -> new ModalEdgePropertyImpl( x.getProperty() - .getType()), + .getModalType()), () -> new ModalEdgePropertyImpl( ModalType.MAY)); @@ -150,7 +150,7 @@ public void testDecompSystem(DecompositionTest testCase) throws IOException { new CompactMTS.Creator<>(), (x) -> new ModalEdgePropertyImpl( x.getProperty() - .getType()), + .getModalType()), () -> new ModalEdgePropertyImpl( ModalType.MAY));