You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
11 KiB
359 lines
11 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2002-
|
|
// Authors:
|
|
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford)
|
|
// * Vojtech Forejt <vojtech.forejt@cs.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.io.File;
|
|
import java.io.FileNotFoundException;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
|
|
import parser.State;
|
|
import parser.Values;
|
|
import parser.VarList;
|
|
import parser.ast.Expression;
|
|
import parser.ast.ModulesFile;
|
|
import prism.ModelType;
|
|
import prism.Prism;
|
|
import prism.PrismComponent;
|
|
import prism.PrismException;
|
|
import prism.PrismLog;
|
|
import prism.PrismPrintStreamLog;
|
|
import prism.ProgressDisplay;
|
|
import prism.UndefinedConstants;
|
|
import simulator.SimulatorEngine;
|
|
|
|
public class ConstructModel extends PrismComponent
|
|
{
|
|
// The simulator engine
|
|
protected SimulatorEngine engine;
|
|
|
|
// Options:
|
|
// Find deadlocks during model construction?
|
|
protected boolean findDeadlocks = true;
|
|
// Automatically fix deadlocks?
|
|
protected boolean fixDeadlocks = true;
|
|
|
|
// Details of built model
|
|
protected List<State> statesList;
|
|
|
|
public ConstructModel(PrismComponent parent, SimulatorEngine engine) throws PrismException
|
|
{
|
|
super(parent);
|
|
this.engine = engine;
|
|
}
|
|
|
|
public List<State> getStatesList()
|
|
{
|
|
return statesList;
|
|
}
|
|
|
|
public void setFixDeadlocks(boolean b)
|
|
{
|
|
fixDeadlocks = b;
|
|
}
|
|
|
|
/**
|
|
* Build the set of reachable states for a PRISM model language description and return.
|
|
* @param modulesFile The PRISM model
|
|
*/
|
|
public List<State> computeReachableStates(ModulesFile modulesFile) throws PrismException
|
|
{
|
|
constructModel(modulesFile, true, false);
|
|
return statesList;
|
|
}
|
|
|
|
/**
|
|
* Construct an explicit-state model from a PRISM model language description and return.
|
|
* @param modulesFile The PRISM model
|
|
*/
|
|
public Model constructModel(ModulesFile modulesFile) throws PrismException
|
|
{
|
|
return constructModel(modulesFile, false, false, true);
|
|
}
|
|
|
|
/**
|
|
* Construct an explicit-state model from a PRISM model language description and return.
|
|
* If {@code justReach} is true, no model is built and null is returned;
|
|
* the set of reachable states can be obtained with {@link #getStatesList()}.
|
|
* @param modulesFile The PRISM model
|
|
* @param justReach If true, just build the reachable state set, not the model
|
|
* @param buildSparse Build a sparse version of the model (if possible)?
|
|
*/
|
|
public Model constructModel(ModulesFile modulesFile, boolean justReach, boolean buildSparse) throws PrismException
|
|
{
|
|
return constructModel(modulesFile, justReach, buildSparse, true);
|
|
}
|
|
|
|
/**
|
|
* Construct an explicit-state model from a PRISM model language description and return.
|
|
* If {@code justReach} is true, no model is built and null is returned;
|
|
* the set of reachable states can be obtained with {@link #getStatesList()}.
|
|
* @param modulesFile The PRISM model
|
|
* @param justReach If true, just build the reachable state set, not the model
|
|
* @param buildSparse Build a sparse version of the model (if possible)?
|
|
* @param distinguishActions True if actions should be attached to distributions (and used to distinguish them)
|
|
*/
|
|
public Model constructModel(ModulesFile modulesFile, boolean justReach, boolean buildSparse, boolean distinguishActions) throws PrismException
|
|
{
|
|
// Model info
|
|
ModelType modelType;
|
|
// State storage
|
|
StateStorage<State> states;
|
|
LinkedList<State> explore;
|
|
State state, stateNew;
|
|
// Explicit model storage
|
|
ModelSimple modelSimple = null;
|
|
DTMCSimple dtmc = null;
|
|
CTMCSimple ctmc = null;
|
|
MDPSimple mdp = null;
|
|
CTMDPSimple ctmdp = null;
|
|
ModelExplicit model = null;
|
|
Distribution distr = null;
|
|
// Misc
|
|
int i, j, nc, nt, src, dest;
|
|
long timer;
|
|
|
|
// Display a warning if there are unbounded vars
|
|
VarList varList = modulesFile.createVarList();
|
|
if (varList.containsUnboundedVariables())
|
|
mainLog.printWarning("Model contains one or more unbounded variables: model construction may not terminate");
|
|
|
|
// Starting reachability...
|
|
mainLog.print("\nComputing reachable states...");
|
|
mainLog.flush();
|
|
ProgressDisplay progress = new ProgressDisplay(mainLog);
|
|
progress.start();
|
|
timer = System.currentTimeMillis();
|
|
|
|
// Initialise simulator for this model
|
|
modelType = modulesFile.getModelType();
|
|
engine.createNewOnTheFlyPath(modulesFile);
|
|
|
|
// Create model storage
|
|
if (!justReach) {
|
|
// Create a (simple, mutable) model of the appropriate type
|
|
switch (modelType) {
|
|
case DTMC:
|
|
modelSimple = dtmc = new DTMCSimple();
|
|
break;
|
|
case CTMC:
|
|
modelSimple = ctmc = new CTMCSimple();
|
|
break;
|
|
case MDP:
|
|
modelSimple = mdp = new MDPSimple();
|
|
break;
|
|
case CTMDP:
|
|
modelSimple = ctmdp = new CTMDPSimple();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Initialise states storage
|
|
states = new IndexedSet<State>(true);
|
|
explore = new LinkedList<State>();
|
|
// Add initial state(s) to 'explore'
|
|
// Easy (normal) case: just one initial state
|
|
if (modulesFile.getInitialStates() == null) {
|
|
state = modulesFile.getDefaultInitialState();
|
|
explore.add(state);
|
|
}
|
|
// Otherwise, there may be multiple initial states
|
|
// For now, we handle this is in a very inefficient way
|
|
else {
|
|
Expression init = modulesFile.getInitialStates();
|
|
List<State> allPossStates = varList.getAllStates();
|
|
for (State possState : allPossStates) {
|
|
if (init.evaluateBoolean(modulesFile.getConstantValues(), possState)) {
|
|
explore.add(possState);
|
|
}
|
|
}
|
|
}
|
|
// Copy initial state(s) to 'states' and to the model
|
|
for (State initState : explore) {
|
|
states.add(initState);
|
|
if (!justReach) {
|
|
modelSimple.addState();
|
|
modelSimple.addInitialState(modelSimple.getNumStates() - 1);
|
|
}
|
|
}
|
|
// Explore...
|
|
src = -1;
|
|
while (!explore.isEmpty()) {
|
|
// Pick next state to explore
|
|
// (they are stored in order found so know index is src+1)
|
|
state = explore.removeFirst();
|
|
src++;
|
|
// Use simulator to explore all choices/transitions from this state
|
|
engine.initialisePath(state);
|
|
// Look at each outgoing choice in turn
|
|
nc = engine.getNumChoices();
|
|
for (i = 0; i < nc; i++) {
|
|
|
|
if (!justReach && (modelType == ModelType.MDP || modelType == ModelType.CTMDP)) {
|
|
distr = new Distribution();
|
|
}
|
|
// Look at each transition in the choice
|
|
nt = engine.getNumTransitions(i);
|
|
for (j = 0; j < nt; j++) {
|
|
stateNew = engine.computeTransitionTarget(i, j);
|
|
// Is this a new state?
|
|
if (states.add(stateNew)) {
|
|
// If so, add to the explore list
|
|
explore.add(stateNew);
|
|
// And to model
|
|
if (!justReach) {
|
|
modelSimple.addState();
|
|
}
|
|
}
|
|
// Get index of state in state set
|
|
dest = states.getIndexOfLastAdd();
|
|
// Add transitions to model
|
|
if (!justReach) {
|
|
switch (modelType) {
|
|
case DTMC:
|
|
dtmc.addToProbability(src, dest, engine.getTransitionProbability(i, j));
|
|
break;
|
|
case CTMC:
|
|
ctmc.addToProbability(src, dest, engine.getTransitionProbability(i, j));
|
|
break;
|
|
case MDP:
|
|
distr.add(dest, engine.getTransitionProbability(i, j));
|
|
break;
|
|
case CTMDP:
|
|
distr.add(dest, engine.getTransitionProbability(i, j));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!justReach) {
|
|
if (modelType == ModelType.MDP) {
|
|
if (distinguishActions) {
|
|
mdp.addActionLabelledChoice(src, distr, engine.getTransitionAction(i, 0));
|
|
} else {
|
|
mdp.addChoice(src, distr);
|
|
}
|
|
} else if (modelType == ModelType.CTMDP) {
|
|
if (distinguishActions) {
|
|
ctmdp.addActionLabelledChoice(src, distr, engine.getTransitionAction(i, 0));
|
|
} else {
|
|
ctmdp.addChoice(src, distr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Print some progress info occasionally
|
|
progress.updateIfReady(src + 1);
|
|
}
|
|
|
|
// Finish progress display
|
|
progress.update(src + 1);
|
|
progress.end(" states");
|
|
|
|
// Reachability complete
|
|
mainLog.print("Reachable states exploration" + (justReach ? "" : " and model construction"));
|
|
mainLog.println(" done in " + ((System.currentTimeMillis() - timer) / 1000.0) + " secs.");
|
|
//mainLog.println(states);
|
|
|
|
// Find/fix deadlocks (if required)
|
|
if (!justReach && findDeadlocks) {
|
|
modelSimple.findDeadlocks(fixDeadlocks);
|
|
}
|
|
|
|
boolean sort = true;
|
|
int permut[] = null;
|
|
|
|
if (sort) {
|
|
// Sort states and convert set to list
|
|
mainLog.println("Sorting reachable states list...");
|
|
permut = states.buildSortingPermutation();
|
|
statesList = states.toPermutedArrayList(permut);
|
|
//mainLog.println(permut);
|
|
} else {
|
|
statesList = states.toArrayList();
|
|
}
|
|
states.clear();
|
|
states = null;
|
|
//mainLog.println(statesList);
|
|
|
|
// Construct new explicit-state model (with correct state ordering)
|
|
if (!justReach) {
|
|
switch (modelType) {
|
|
case DTMC:
|
|
model = sort ? new DTMCSimple(dtmc, permut) : (DTMCSimple) dtmc;
|
|
break;
|
|
case CTMC:
|
|
model = sort ? new CTMCSimple(ctmc, permut) : (CTMCSimple) ctmc;
|
|
break;
|
|
case MDP:
|
|
if (buildSparse) {
|
|
model = sort ? new MDPSparse(mdp, true, permut) : new MDPSparse(mdp);
|
|
} else {
|
|
model = sort ? new MDPSimple(mdp, permut) : mdp;
|
|
}
|
|
break;
|
|
case CTMDP:
|
|
model = sort ? new CTMDPSimple(ctmdp, permut) : mdp;
|
|
break;
|
|
}
|
|
model.setStatesList(statesList);
|
|
model.setConstantValues(new Values(modulesFile.getConstantValues()));
|
|
//mainLog.println("Model: " + model);
|
|
}
|
|
|
|
// Discard permutation
|
|
permut = null;
|
|
|
|
return model;
|
|
}
|
|
|
|
/**
|
|
* Test method.
|
|
*/
|
|
public static void main(String[] args)
|
|
{
|
|
try {
|
|
// Simple example: parse a PRISM file from a file, construct the model and export to a .tra file
|
|
PrismLog mainLog = new PrismPrintStreamLog(System.out);
|
|
Prism prism = new Prism(mainLog, mainLog);
|
|
ModulesFile modulesFile = prism.parseModelFile(new File(args[0]));
|
|
UndefinedConstants undefinedConstants = new UndefinedConstants(modulesFile, null);
|
|
if (args.length > 2)
|
|
undefinedConstants.defineUsingConstSwitch(args[2]);
|
|
modulesFile.setUndefinedConstants(undefinedConstants.getMFConstantValues());
|
|
ConstructModel constructModel = new ConstructModel(prism, prism.getSimulator());
|
|
Model model = constructModel.constructModel(modulesFile);
|
|
model.exportToPrismExplicitTra(args[1]);
|
|
} catch (FileNotFoundException e) {
|
|
System.out.println("Error: " + e.getMessage());
|
|
System.exit(1);
|
|
} catch (PrismException e) {
|
|
System.out.println("Error: " + e.getMessage());
|
|
System.exit(1);
|
|
}
|
|
}
|
|
}
|