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.
 
 
 
 
 
 

435 lines
11 KiB

//==============================================================================
//
// 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 explicit;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import parser.State;
import parser.Values;
import parser.VarList;
import prism.Prism;
import prism.PrismException;
import prism.PrismLog;
/**
* Base class for explicit-state model representations.
*/
public abstract class ModelExplicit implements Model
{
// Basic model information
/** Number of states */
protected int numStates;
/** Which states are initial states */
protected List<Integer> initialStates; // TODO: should be a (linkedhash?) set really
/** States that are/were deadlocks. Where requested and where appropriate (DTMCs/MDPs),
* these states may have been fixed at build time by adding self-loops. */
protected TreeSet<Integer> deadlocks;
// Additional, optional information associated with the model
/** (Optionally) information about the states of this model,
* i.e. the State object corresponding to each state index. */
protected List<State> statesList;
/** (Optionally) a list of values for constants associated with this model. */
protected Values constantValues;
/** (Optionally) the list of variables */
protected VarList varList;
/** (Optionally) some labels (atomic propositions) associated with the model,
* represented as a String->BitSet mapping from their names to the states that satisfy them. */
protected Map<String, BitSet> labels = new TreeMap<String, BitSet>();
/**
* (Optionally) the stored predecessor relation. Becomes inaccurate after the model is changed!
*/
protected PredecessorRelation predecessorRelation = null;
// Mutators
/**
* Copy data from another ModelExplicit (used by superclass copy constructors).
* Assumes that this has already been initialise()ed.
*/
public void copyFrom(ModelExplicit model)
{
numStates = model.numStates;
for (int in : model.initialStates) {
addInitialState(in);
}
for (int dl : model.deadlocks) {
addDeadlockState(dl);
}
// Shallow copy of read-only stuff
statesList = model.statesList;
constantValues = model.constantValues;
labels = model.labels;
varList = model.varList;
}
/**
* Copy data from another ModelExplicit and a state index permutation,
* i.e. state index i becomes index permut[i]
* (used by superclass copy constructors).
* Assumes that this has already been initialise()ed.
* Pointer to states list is NOT copied (since now wrong).
*/
public void copyFrom(ModelExplicit model, int permut[])
{
numStates = model.numStates;
for (int in : model.initialStates) {
addInitialState(permut[in]);
}
for (int dl : model.deadlocks) {
addDeadlockState(permut[dl]);
}
// Shallow copy of (some) read-only stuff
// (i.e. info that is not broken by permute)
statesList = null;
constantValues = model.constantValues;
labels.clear();
varList = model.varList;
}
/**
* Initialise: create new model with fixed number of states.
*/
public void initialise(int numStates)
{
this.numStates = numStates;
initialStates = new ArrayList<Integer>();
deadlocks = new TreeSet<Integer>();
statesList = null;
constantValues = null;
varList = null;
labels = new TreeMap<String, BitSet>();
}
/**
* Add a state to the list of initial states.
*/
public void addInitialState(int i)
{
initialStates.add(i);
}
/**
* Empty the list of initial states.
*/
public void clearInitialStates()
{
initialStates.clear();
}
/**
* Add a state to the list of deadlock states.
*/
public void addDeadlockState(int i)
{
deadlocks.add(i);
}
/**
* Build (anew) from a list of transitions exported explicitly by PRISM (i.e. a .tra file).
* Note that initial states are not configured (since this info is not in the file),
* so this needs to be done separately (using {@link #addInitialState(int)}.
*/
public abstract void buildFromPrismExplicit(String filename) throws PrismException;
/**
* Set the associated (read-only) state list.
*/
public void setStatesList(List<State> statesList)
{
this.statesList = statesList;
}
/**
* Set the associated (read-only) constant values.
*/
public void setConstantValues(Values constantValues)
{
this.constantValues = constantValues;
}
/**
* Sets the VarList for this model (may be {@code null}).
*/
public void setVarList(VarList varList)
{
this.varList = varList;
}
/**
* Adds a label and the set the states that satisfy it.
* Any existing label with the same name is overwritten.
* @param name The name of the label
* @param states The states that satisfy the label
*/
public void addLabel(String name, BitSet states)
{
labels.put(name, states);
}
/**
* Add a label with corresponding state set, ensuring a unique, non-existing label.
* The label will be either "X" or "X_i" where X is the content of the {@code prefix} argument
* and i is a non-negative integer.
* <br>
* Optionally, a set of defined label names can be passed so that those labels
* can be avoided. This can be obtained from the model checker via {@code getDefinedLabelNames()}.
* <br>
* Note that a stored label takes precedence over the on-the-fly calculation
* of an ExpressionLabel, cf. {@link explicit.StateModelChecker#checkExpressionLabel}
*
* @param prefix the prefix for the unique label
* @param labelStates the BitSet with the state set for the label
* @param definedLabelNames set of names (optional, may be {@code null}) to check for existing labels
* @return the generated unique label
*/
public String addUniqueLabel(String prefix, BitSet labelStates, Set<String> definedLabelNames)
{
String label;
int i = 0;
label = prefix; // first, try without appending _i
while (true) {
boolean labelOk = !hasLabel(label); // not directly attached to model
if (definedLabelNames != null) {
labelOk &= !definedLabelNames.contains(label); // not defined
}
if (labelOk) {
break;
}
// prepare next label to try
label = prefix+"_"+i;
if (i == Integer.MAX_VALUE)
throw new UnsupportedOperationException("Integer overflow trying to add unique label");
i++;
}
addLabel(label, labelStates);
return label;
}
// Accessors (for Model interface)
@Override
public int getNumStates()
{
return numStates;
}
@Override
public int getNumInitialStates()
{
return initialStates.size();
}
@Override
public Iterable<Integer> getInitialStates()
{
return initialStates;
}
@Override
public int getFirstInitialState()
{
return initialStates.isEmpty() ? -1 : initialStates.get(0);
}
@Override
public boolean isInitialState(int i)
{
return initialStates.contains(i);
}
@Override
public int getNumDeadlockStates()
{
return deadlocks.size();
}
@Override
public Iterable<Integer> getDeadlockStates()
{
return deadlocks;
}
@Override
public StateValues getDeadlockStatesList()
{
BitSet bs = new BitSet();
for (int dl : deadlocks) {
bs.set(dl);
}
return StateValues.createFromBitSet(bs, this);
}
@Override
public int getFirstDeadlockState()
{
return deadlocks.isEmpty() ? -1 : deadlocks.first();
}
@Override
public boolean isDeadlockState(int i)
{
return deadlocks.contains(i);
}
@Override
public List<State> getStatesList()
{
return statesList;
}
@Override
public Values getConstantValues()
{
return constantValues;
}
@Override
public VarList getVarList()
{
return varList;
}
@Override
public BitSet getLabelStates(String name)
{
return labels.get(name);
}
@Override
public boolean hasLabel(String name)
{
return labels.containsKey(name);
}
@Override
public Set<String> getLabels()
{
return labels.keySet();
}
@Override
public Map<String, BitSet> getLabelToStatesMap()
{
return labels;
}
@Override
public void checkForDeadlocks() throws PrismException
{
checkForDeadlocks(null);
}
@Override
public abstract void checkForDeadlocks(BitSet except) throws PrismException;
@Override
public void exportStates(int exportType, VarList varList, PrismLog log) throws PrismException
{
if (statesList == null)
return;
// Print header: list of model vars
if (exportType == Prism.EXPORT_MATLAB)
log.print("% ");
log.print("(");
int numVars = varList.getNumVars();
for (int i = 0; i < numVars; i++) {
log.print(varList.getName(i));
if (i < numVars - 1)
log.print(",");
}
log.println(")");
if (exportType == Prism.EXPORT_MATLAB)
log.println("states=[");
// Print states
int numStates = statesList.size();
for (int i = 0; i < numStates; i++) {
if (exportType != Prism.EXPORT_MATLAB)
log.println(i + ":" + statesList.get(i).toString());
else
log.println(statesList.get(i).toStringNoParentheses());
}
// Print footer
if (exportType == Prism.EXPORT_MATLAB)
log.println("];");
}
@Override
public boolean equals(Object o)
{
if (o == null || !(o instanceof ModelExplicit))
return false;
ModelExplicit model = (ModelExplicit) o;
if (numStates != model.numStates)
return false;
if (!initialStates.equals(model.initialStates))
return false;
return true;
}
@Override
public boolean hasStoredPredecessorRelation() {
return (predecessorRelation != null);
}
@Override
public PredecessorRelation getPredecessorRelation(prism.PrismComponent parent, boolean storeIfNew) {
if (predecessorRelation != null) {
return predecessorRelation;
}
PredecessorRelation pre = PredecessorRelation.forModel(parent, this);
if (storeIfNew) {
predecessorRelation = pre;
}
return pre;
}
@Override
public void clearPredecessorRelation() {
predecessorRelation = null;
}
}