Browse Source
Patch in DTMC-LTL model checking for explicit engine (from prism-games-bruni).
Patch in DTMC-LTL model checking for explicit engine (from prism-games-bruni).
git-svn-id: https://www.prismmodelchecker.org/svn/prism/prism/trunk@7080 bbc10eb1-c90d-0410-af57-cb519fbb1720master
4 changed files with 384 additions and 1 deletions
-
98prism/src/explicit/DTMCModelChecker.java
-
8prism/src/explicit/DTMCSimple.java
-
237prism/src/explicit/LTLModelChecker.java
-
42prism/src/prism/Pair.java
@ -0,0 +1,237 @@ |
|||
//============================================================================== |
|||
// |
|||
// Copyright (c) 2002- |
|||
// Authors: |
|||
// * Alessandro Bruni <albr@dtu.dk> (Technical University of Denmark) |
|||
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford) |
|||
// |
|||
//------------------------------------------------------------------------------ |
|||
// |
|||
// This file is part of PRISM. |
|||
// |
|||
// PRISM is free software; you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation; either version 2 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// PRISM is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with PRISM; if not, write to the Free Software Foundation, |
|||
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|||
// |
|||
//============================================================================== |
|||
|
|||
package explicit; |
|||
|
|||
import java.awt.Point; |
|||
import java.util.Arrays; |
|||
import java.util.BitSet; |
|||
import java.util.LinkedList; |
|||
import java.util.List; |
|||
import java.util.Vector; |
|||
|
|||
import parser.ast.Expression; |
|||
import parser.ast.ExpressionBinaryOp; |
|||
import parser.ast.ExpressionLabel; |
|||
import parser.ast.ExpressionTemporal; |
|||
import parser.ast.ExpressionUnaryOp; |
|||
import parser.type.TypeBool; |
|||
import parser.type.TypePathBool; |
|||
import prism.DRA; |
|||
import prism.LTL2RabinLibrary; |
|||
import prism.Pair; |
|||
import prism.PrismException; |
|||
import explicit.SCCComputer.SCCMethod; |
|||
|
|||
public class LTLModelChecker |
|||
{ |
|||
|
|||
public static DRA<BitSet> convertLTLFormulaToDRA(Expression ltl) throws PrismException |
|||
{ |
|||
return LTL2RabinLibrary.convertLTLFormulaToDRA(ltl); |
|||
} |
|||
|
|||
public Expression checkMaximalStateFormulas(ProbModelChecker mc, Model model, Expression expr, Vector<BitSet> labelBS) throws PrismException |
|||
{ |
|||
// A state formula |
|||
if (expr.getType() instanceof TypeBool) { |
|||
// Model check |
|||
StateValues sv = mc.checkExpression(model, expr); |
|||
if (sv.type != TypeBool.getInstance() || sv.valuesB == null) { |
|||
throw new PrismException("Excepting a boolean value here!"); |
|||
} |
|||
BitSet bs = sv.getBitSet(); |
|||
// Detect special cases (true, false) for optimisation |
|||
if (bs.isEmpty()) { |
|||
return Expression.False(); |
|||
} |
|||
BitSet tmp = (BitSet) bs.clone(); |
|||
tmp.flip(0, tmp.length()); |
|||
if (tmp.isEmpty()) { |
|||
return Expression.True(); |
|||
} |
|||
// See if we already have an identical result |
|||
// (in which case, reuse it) |
|||
int i = labelBS.indexOf(bs); |
|||
if (i != -1) { |
|||
return new ExpressionLabel("L" + i); |
|||
} |
|||
// Otherwise, add result to list, return new label |
|||
labelBS.add(bs); |
|||
return new ExpressionLabel("L" + (labelBS.size() - 1)); |
|||
} |
|||
// A path formula (recurse, modify, return) |
|||
else if (expr.getType() instanceof TypePathBool) { |
|||
if (expr instanceof ExpressionBinaryOp) { |
|||
ExpressionBinaryOp exprBinOp = (ExpressionBinaryOp) expr; |
|||
exprBinOp.setOperand1(checkMaximalStateFormulas(mc, model, exprBinOp.getOperand1(), labelBS)); |
|||
exprBinOp.setOperand2(checkMaximalStateFormulas(mc, model, exprBinOp.getOperand2(), labelBS)); |
|||
} else if (expr instanceof ExpressionUnaryOp) { |
|||
ExpressionUnaryOp exprUnOp = (ExpressionUnaryOp) expr; |
|||
exprUnOp.setOperand(checkMaximalStateFormulas(mc, model, exprUnOp.getOperand(), labelBS)); |
|||
} else if (expr instanceof ExpressionTemporal) { |
|||
ExpressionTemporal exprTemp = (ExpressionTemporal) expr; |
|||
if (exprTemp.getOperand1() != null) { |
|||
exprTemp.setOperand1(checkMaximalStateFormulas(mc, model, exprTemp.getOperand1(), labelBS)); |
|||
} |
|||
if (exprTemp.getOperand2() != null) { |
|||
exprTemp.setOperand2(checkMaximalStateFormulas(mc, model, exprTemp.getOperand2(), labelBS)); |
|||
} |
|||
} |
|||
} |
|||
return expr; |
|||
} |
|||
|
|||
/** |
|||
* Constructs the product of a DTMC and a DRA automaton |
|||
* |
|||
* @param dra the DRA representing the LTL formula |
|||
* @param model the original model |
|||
* @param labelBS a set of labels for states in the original model |
|||
* @return a Pair consisting of the product model and a map from |
|||
* (s_i * draSize + q_j) to the right state in the DRA product |
|||
* @throws PrismException |
|||
*/ |
|||
public Pair<Model, int[]> constructProductMC(DRA<BitSet> dra, Model model, Vector<BitSet> labelBS) throws PrismException |
|||
{ |
|||
if (!(model instanceof DTMCSimple)) { |
|||
throw new PrismException("Expecting a DTMC here"); |
|||
} |
|||
|
|||
DTMCSimple modelDTMC = (DTMCSimple) model; |
|||
DTMCSimple prodModel = new DTMCSimple(); |
|||
|
|||
int draSize = dra.size(); |
|||
int modelNumStates = modelDTMC.getNumStates(); |
|||
int prodNumStates = modelNumStates * draSize; |
|||
|
|||
// Encoding: |
|||
// each state s' = <s, q> = s * draSize + q |
|||
// s(s') = s' / draSize |
|||
// q(s') = s' % draSize |
|||
|
|||
// Initial states |
|||
LinkedList<Point> queue = new LinkedList<Point>(); |
|||
int map[] = new int[prodNumStates]; |
|||
Arrays.fill(map, -1); |
|||
int q_0 = dra.getStartState(); |
|||
for (int s_0 : model.getInitialStates()) { |
|||
queue.add(new Point(s_0, q_0)); |
|||
prodModel.addState(); |
|||
prodModel.addInitialState(prodModel.getNumStates() - 1); |
|||
map[s_0 * draSize + q_0] = prodModel.getNumStates() - 1; |
|||
} |
|||
|
|||
// Product states |
|||
BitSet visited = new BitSet(prodNumStates); |
|||
int q_1 = 0, q_2 = 0, s_1 = 0, s_2 = 0; |
|||
while (!queue.isEmpty()) { |
|||
Point p = queue.pop(); |
|||
s_1 = p.x; |
|||
q_1 = p.y; |
|||
visited.set(s_1 * draSize + q_1); |
|||
int numEdges = dra.getNumEdges(q_1); |
|||
for (int j = 0; j < numEdges; j++) { |
|||
q_2 = dra.getEdgeDest(q_1, j); |
|||
BitSet label = computeLabel(dra, labelBS, modelNumStates, q_1, j); |
|||
for (s_2 = label.nextSetBit(0); s_2 != -1; s_2 = label.nextSetBit(s_2 + 1)) { |
|||
if (!visited.get(s_2 * draSize + q_2) && map[s_2 * draSize + q_2] == -1) { |
|||
queue.add(new Point(s_2, q_2)); |
|||
prodModel.addState(); |
|||
map[s_2 * draSize + q_2] = prodModel.getNumStates() - 1; |
|||
} |
|||
double prob = modelDTMC.getProbability(s_1, s_2); |
|||
prodModel.setProbability(map[s_1 * draSize + q_1], map[s_2 * draSize + q_2], prob); |
|||
} |
|||
} |
|||
} |
|||
|
|||
int invMap[] = new int[prodModel.getNumStates()]; |
|||
for (int i = 0; i < map.length; i++) { |
|||
if (map[i] != -1) { |
|||
invMap[map[i]] = i; |
|||
} |
|||
} |
|||
|
|||
prodModel.findDeadlocks(false); |
|||
|
|||
return new Pair<Model, int[]>(prodModel, invMap); |
|||
} |
|||
|
|||
private BitSet computeLabel(DRA<BitSet> dra, Vector<BitSet> labelBS, int origStates, int q_1, int j) |
|||
{ |
|||
int numAPs = dra.getAPList().size(); |
|||
List<String> apList = dra.getAPList(); |
|||
BitSet label = new BitSet(origStates); |
|||
label.flip(0, origStates); |
|||
for (int k = 0; k < numAPs; k++) { |
|||
int bsID = Integer.parseInt(apList.get(k).substring(1)); |
|||
BitSet bs = labelBS.get(bsID); |
|||
if (dra.getEdgeLabel(q_1, j).get(k)) { |
|||
label.and(bs); |
|||
} else { |
|||
label.andNot(bs); |
|||
} |
|||
} |
|||
return label; |
|||
} |
|||
|
|||
public BitSet findAcceptingBSCCs(DRA<BitSet> dra, Model modelProduct, int invMap[], SCCMethod sccMethod) |
|||
{ |
|||
// Compute bottom strongly connected components (BSCCs) |
|||
SCCComputer sccComputer = SCCComputer.createSCCComputer(sccMethod, modelProduct); |
|||
sccComputer.computeBSCCs(); |
|||
List<BitSet> bsccs = sccComputer.getBSCCs(); |
|||
|
|||
int draSize = dra.size(); |
|||
|
|||
BitSet result = new BitSet(); |
|||
for (BitSet bscc : bsccs) { |
|||
int numAcceptancePairs = dra.getNumAcceptancePairs(); |
|||
boolean isLEmpty = true; |
|||
boolean isKEmpty = true; |
|||
for (int acceptancePair = 0; acceptancePair < numAcceptancePairs && isLEmpty && isKEmpty; acceptancePair++) { |
|||
BitSet L = dra.getAcceptanceL(acceptancePair); |
|||
BitSet K = dra.getAcceptanceK(acceptancePair); |
|||
|
|||
for (int state = bscc.nextSetBit(0); state != -1; state = bscc.nextSetBit(state + 1)) { |
|||
int draState = invMap[state] % draSize; |
|||
isLEmpty &= !L.get(draState); |
|||
isKEmpty &= !K.get(draState); |
|||
} |
|||
} |
|||
|
|||
if (isLEmpty && !isKEmpty) { |
|||
// Acceptance condition |
|||
result.or(bscc); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
//============================================================================== |
|||
// |
|||
// Copyright (c) 2002- |
|||
// Authors: |
|||
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford) |
|||
// |
|||
//------------------------------------------------------------------------------ |
|||
// |
|||
// This file is part of PRISM. |
|||
// |
|||
// PRISM is free software; you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation; either version 2 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// PRISM is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with PRISM; if not, write to the Free Software Foundation, |
|||
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|||
// |
|||
//============================================================================== |
|||
|
|||
package prism; |
|||
|
|||
/** |
|||
* Simple class to store a pair of values. |
|||
*/ |
|||
public class Pair<X,Y> |
|||
{ |
|||
public X first; |
|||
public Y second; |
|||
|
|||
public Pair(X first, Y second) |
|||
{ |
|||
this.first = first; |
|||
this.second = second; |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue