Browse Source
Add experimental bisimulation option (explicit engine, hidden option).
Add experimental bisimulation option (explicit engine, hidden option).
git-svn-id: https://www.prismmodelchecker.org/svn/prism/prism/trunk@7630 bbc10eb1-c90d-0410-af57-cb519fbb1720master
5 changed files with 485 additions and 0 deletions
-
282prism/src/explicit/Bisimulation.java
-
4prism/src/explicit/ModelExplicit.java
-
176prism/src/explicit/StateModelChecker.java
-
19prism/src/prism/Prism.java
-
4prism/src/prism/PrismCL.java
@ -0,0 +1,282 @@ |
|||
//============================================================================== |
|||
// |
|||
// Copyright (c) 2002- |
|||
// Authors: |
|||
// * Dave Parker <d.a.parker@cs.bham.ac.uk> (University of Birmingham/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.util.ArrayList; |
|||
import java.util.BitSet; |
|||
import java.util.Iterator; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import parser.State; |
|||
import prism.PrismComponent; |
|||
import prism.PrismException; |
|||
|
|||
/** |
|||
* Class to perform bisimulation minimisation for explicit-state models. |
|||
*/ |
|||
public class Bisimulation extends PrismComponent |
|||
{ |
|||
// Local storage of partition info |
|||
protected int numStates; |
|||
protected int[] partition; |
|||
protected int numBlocks; |
|||
protected MDPSimple mdp; |
|||
|
|||
/** |
|||
* Construct a new Bisimulation object. |
|||
*/ |
|||
public Bisimulation(PrismComponent parent) throws PrismException |
|||
{ |
|||
super(parent); |
|||
} |
|||
|
|||
/** |
|||
* Perform bisimulation minimisation on a model. |
|||
* @param model The model |
|||
* @param propNames Names of the propositions in {@code propBSs} |
|||
* @param propBSs Propositions (satisfying sets of states) to be preserved by bisimulation. |
|||
*/ |
|||
public Model minimise(Model model, List<String> propNames, List<BitSet> propBSs) throws PrismException |
|||
{ |
|||
switch (model.getModelType()) { |
|||
case DTMC: |
|||
return minimiseDTMC((DTMC) model, propNames, propBSs); |
|||
case CTMC: |
|||
return minimiseCTMC((CTMC) model, propNames, propBSs); |
|||
default: |
|||
throw new PrismException("Bisimulation minimisation not yet supported for " + model.getModelType() + "s"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Perform bisimulation minimisation on a DTMC. |
|||
* @param dtmc The DTMC |
|||
* @param propNames Names of the propositions in {@code propBSs} |
|||
* @param propBSs Propositions (satisfying sets of states) to be preserved by bisimulation. |
|||
*/ |
|||
private DTMC minimiseDTMC(DTMC dtmc, List<String> propNames, List<BitSet> propBSs) |
|||
{ |
|||
// Create initial partition based on propositions |
|||
initialisePartitionInfo(dtmc, propBSs); |
|||
//printPartition(dtmc); |
|||
|
|||
// Iterative splitting |
|||
boolean changed = true; |
|||
while (changed) |
|||
changed = splitDTMC(dtmc); |
|||
mainLog.println("Minimisation: " + numStates + " to " + numBlocks + " States"); |
|||
//printPartition(dtmc); |
|||
|
|||
// Build reduced model |
|||
DTMCSimple dtmcNew = new DTMCSimple(numBlocks); |
|||
for (int i = 0; i < numBlocks; i++) { |
|||
for (Map.Entry<Integer, Double> e : mdp.getChoice(i, 0)) { |
|||
dtmcNew.setProbability((Integer) mdp.getAction(i, 0), e.getKey(), e.getValue()); |
|||
} |
|||
} |
|||
attachStatesAndLabels(dtmc, dtmcNew, propNames, propBSs); |
|||
|
|||
return dtmcNew; |
|||
} |
|||
|
|||
/** |
|||
* Perform bisimulation minimisation on a CTMC. |
|||
* @param ctmc The CTMC |
|||
* @param propNames Names of the propositions in {@code propBSs} |
|||
* @param propBSs Propositions (satisfying sets of states) to be preserved by bisimulation. |
|||
*/ |
|||
private CTMC minimiseCTMC(CTMC ctmc, List<String> propNames, List<BitSet> propBSs) |
|||
{ |
|||
// Create initial partition based on propositions |
|||
initialisePartitionInfo(ctmc, propBSs); |
|||
//printPartition(ctmc); |
|||
|
|||
// Iterative splitting |
|||
boolean changed = true; |
|||
while (changed) |
|||
changed = splitDTMC(ctmc); |
|||
mainLog.println("Minimisation: " + numStates + " to " + numBlocks + " States"); |
|||
//printPartition(ctmc); |
|||
|
|||
// Build reduced model |
|||
CTMCSimple ctmcNew = new CTMCSimple(numBlocks); |
|||
for (int i = 0; i < numBlocks; i++) { |
|||
for (Map.Entry<Integer, Double> e : mdp.getChoice(i, 0)) { |
|||
ctmcNew.setProbability((Integer) mdp.getAction(i, 0), e.getKey(), e.getValue()); |
|||
} |
|||
} |
|||
attachStatesAndLabels(ctmc, ctmcNew, propNames, propBSs); |
|||
|
|||
return ctmcNew; |
|||
} |
|||
|
|||
/** |
|||
* Construct the initial partition based on a set of proposition bitsets. |
|||
* Store info in {@code numStates}, {@code numBlocks} and {@code partition}. |
|||
*/ |
|||
private void initialisePartitionInfo(Model model, List<BitSet> propBSs) |
|||
{ |
|||
BitSet bs1, bs0; |
|||
numStates = model.getNumStates(); |
|||
partition = new int[numStates]; |
|||
|
|||
// Compute all non-empty combinations of propositions |
|||
List<BitSet> all = new ArrayList<BitSet>(); |
|||
bs1 = (BitSet) propBSs.get(0).clone(); |
|||
bs0 = (BitSet) bs1.clone(); |
|||
bs0.flip(0, numStates); |
|||
all.add(bs1); |
|||
all.add(bs0); |
|||
int n = propBSs.size(); |
|||
for (int i = 1; i < n; i++) { |
|||
BitSet bs = propBSs.get(i); |
|||
int m = all.size(); |
|||
for (int j = 0; j < m; j++) { |
|||
bs1 = all.get(j); |
|||
bs0 = (BitSet) bs1.clone(); |
|||
bs0.andNot(bs); |
|||
bs1.and(bs); |
|||
if (bs1.isEmpty()) { |
|||
all.set(j, bs0); |
|||
} else { |
|||
if (!bs0.isEmpty()) |
|||
all.add(bs0); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Construct initial partition |
|||
numBlocks = all.size(); |
|||
for (int j = 0; j < numBlocks; j++) { |
|||
BitSet bs = all.get(j); |
|||
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { |
|||
partition[i] = j; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Perform a split of the current partition, if possible, updating {@code numBlocks} and {@code partition}. |
|||
* @return whether or not the partition was split |
|||
*/ |
|||
private boolean splitDTMC(DTMC dtmc) |
|||
{ |
|||
int s, a, i, numBlocksNew, numChoicesOld; |
|||
Distribution distrNew; |
|||
int partitionNew[]; |
|||
|
|||
partitionNew = new int[numStates]; |
|||
numBlocksNew = 0; |
|||
// Compute the signature for each state (i.e. the distribution for outgoing |
|||
// transitions, lifted to the current partition) |
|||
// For convenience, we just store them as an MDP, with action label equal to the index of the block |
|||
mdp = new MDPSimple(numBlocks); |
|||
for (s = 0; s < numStates; s++) { |
|||
// Build lifted distribution |
|||
Iterator<Map.Entry<Integer, Double>> iter = dtmc.getTransitionsIterator(s); |
|||
distrNew = new Distribution(); |
|||
while (iter.hasNext()) { |
|||
Map.Entry<Integer, Double> e = iter.next(); |
|||
distrNew.add(partition[e.getKey()], e.getValue()); |
|||
} |
|||
// Store in MDP, update new partition |
|||
a = partition[s]; |
|||
numChoicesOld = mdp.getNumChoices(a); |
|||
i = mdp.addChoice(a, distrNew); |
|||
if (i == numChoicesOld) |
|||
mdp.setAction(a, i, numBlocksNew++); |
|||
partitionNew[s] = (Integer) mdp.getAction(a, i); |
|||
} |
|||
// Debug info |
|||
//mainLog.println("New partition: " + java.util.Arrays.toString(partitionNew)); |
|||
//mainLog.println("Signatures MDP: " + mdp.infoString()); |
|||
//mainLog.println("Signatures MDP: " + mdp); |
|||
//try { mdp.exportToDotFile("mdp.dot"); } catch (PrismException e) {} |
|||
// Update info |
|||
boolean changed = numBlocks != numBlocksNew; |
|||
partition = partitionNew; |
|||
numBlocks = numBlocksNew; |
|||
|
|||
return changed; |
|||
} |
|||
|
|||
/** |
|||
* Display the current partition, showing the states in each block. |
|||
*/ |
|||
private void printPartition(Model model) |
|||
{ |
|||
for (int i = 0; i < numBlocks; i++) { |
|||
mainLog.print(i + ":"); |
|||
for (int j = 0; j < numStates; j++) |
|||
if (partition[j] == i) |
|||
if (model.getStatesList() != null) |
|||
mainLog.print(" " + model.getStatesList().get(j)); |
|||
else |
|||
mainLog.print(" " + j); |
|||
mainLog.println(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Attach a list of states to the minimised model by adding a representative state |
|||
* from the original model. |
|||
* Also attach information about the propositions (used for bisimulation minimisation) |
|||
* to the minimised model, in the form of labels (stored as BitSets). |
|||
* @param model The original model |
|||
* @param modelNew The minimised model |
|||
* @param propNames The names of the propositions |
|||
* @param propBSs Satisfying states (of the minimised model) for the propositions |
|||
*/ |
|||
private void attachStatesAndLabels(Model model, ModelExplicit modelNew, List<String> propNames, List<BitSet> propBSs) |
|||
{ |
|||
// Attach states |
|||
if (model.getStatesList() != null) { |
|||
List<State> statesList = model.getStatesList(); |
|||
List<State> statesListNew = new ArrayList<State>(numBlocks); |
|||
for (int i = 0; i < numBlocks; i++) { |
|||
statesListNew.add(null); |
|||
} |
|||
for (int i = 0; i < numStates; i++) { |
|||
if (statesListNew.get(partition[i]) == null) |
|||
statesListNew.set(partition[i], statesList.get(i)); |
|||
} |
|||
modelNew.setStatesList(statesListNew); |
|||
} |
|||
|
|||
// Build/attach new labels |
|||
int numProps = propBSs.size(); |
|||
for (int i = 0; i < numProps; i++) { |
|||
String propName = propNames.get(i); |
|||
BitSet propBS = propBSs.get(i); |
|||
BitSet propBSnew = new BitSet(); |
|||
for (int j = propBS.nextSetBit(0); j >= 0; j = propBS.nextSetBit(j + 1)) |
|||
propBSnew.set(partition[j]); |
|||
modelNew.labels.put(propName, propBSnew); |
|||
} |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue