Browse Source

Begin support for simple accumulation trafo

accumulation
Sascha Wunderlich 7 years ago
parent
commit
0fd6f9ac5c
  1. 241
      prism/src/explicit/AccumulationProduct.java
  2. 270
      prism/src/explicit/AccumulationProductComplex.java
  3. 18
      prism/src/explicit/AccumulationProductComplexCounting.java
  4. 18
      prism/src/explicit/AccumulationProductComplexRegular.java
  5. 89
      prism/src/explicit/AccumulationTransformation.java
  6. 115
      prism/src/parser/visitor/ReplaceAccumulationExpression.java
  7. 9
      prism/src/prism/PrismSettings.java

241
prism/src/explicit/AccumulationProduct.java

@ -7,7 +7,6 @@ import java.util.Map;
import parser.ast.ExpressionAccumulation;
import parser.ast.AccumulationFactor;
import parser.ast.Expression;
import prism.IntegerBound;
import prism.PrismException;
@ -27,10 +26,6 @@ public abstract class AccumulationProduct<M extends Model,Component> extends Pro
{
protected final StoragePool<AccumulationTracker<Component>> trackers;
protected final StoragePool<AccumulationState<Component>> accStates;
protected final ArrayList<BitSet> initStates;
protected final ArrayList<BitSet> runStates;
protected final ArrayList<BitSet> goalStates;
protected final ArrayList<BitSet> labels;
@ -42,106 +37,68 @@ public abstract class AccumulationProduct<M extends Model,Component> extends Pro
trackers = new StoragePool<>();
accStates = new StoragePool<>();
initStates = new ArrayList<>();
runStates = new ArrayList<>();
goalStates = new ArrayList<>();
labels = new ArrayList<BitSet>();
}
public final int getNumberOfTracks() {
return numberOfTracks;
}
public final BitSet getInitStates(int track) {
return initStates.get(track);
}
public final BitSet getRunStates(int track) {
return runStates.get(track);
}
public final BitSet getGoalStates(int track) {
return goalStates.get(track);
}
protected abstract void generateTrackInfo(ProductState state, Integer index, ExpressionAccumulation accexp, ProbModelChecker mc) throws PrismException;
protected void generateTrackInfo(ProductState state, Integer index, ExpressionAccumulation accexp, ProbModelChecker mc) throws PrismException {
AccumulationState<Component> accState = accStates.getById(state.getSecondState());
AccumulationTracker<Component> tracker = accState.getTracker(trackers);
for(int trackIdx=0; trackIdx<tracker.getTracks().size(); trackIdx++) {
AccumulationTrack<Component> track = tracker.getTracks().get(trackIdx);
// Is this an initial
if (trackIdx==accState.lastRestartNr) {
initStates.get(trackIdx).set(index);
}
// Is this a running track?
if (track != null) {
runStates.get(trackIdx).set(index);
}
// Is this a goal track?
if (isGoalTrack(track, accexp, mc)) {
goalStates.get(trackIdx).set(index);
}
}
}
/** Checks whether a track is good.
*
* Tracks are good, if they are final and fulfill the constraint in the accumulation expression with context mc.
* @param track
* @param accexp
* @param mc
* @return
* @throws PrismException
*/
protected final boolean isGoalTrack(final AccumulationTrack<Component> track, final ExpressionAccumulation accexp, final ProbModelChecker mc)
throws PrismException {
// Only final tracks can be good
if (!isFinalTrack(track,accexp,mc)) { return false; }
boolean isGood = false;
//TODO: these should be double later on
// Collect the weight linear combination, factor*weight+...
int lhs = 0;
int factorNr = 0;
for (AccumulationFactor factor : accexp.getConstraint().getFactors()) {
lhs += factor.getFactor().evaluateInt(mc.getConstantValues())
* track.getWeight(factorNr);
}
// Check the bound
IntegerBound rhs = IntegerBound.fromTemporalOperatorBound(accexp.getConstraint().getBound(), mc.getConstantValues(), true);
// For DIA operators, we just check the bound.
// For BOX operators, we check the INVERTED bound.
// TODO: THIS MAY BE BROKEN
switch(accexp.getSymbol()) {
case ACCBOXMINUS:
case ACCBOXPLUS:
if (!rhs.isInBounds(lhs)) {
isGood = true;
}
mc.getLog().println("WARNING: This may be wrong.");
break;
case ACCDIAMINUS:
case ACCDIAPLUS:
case ACCUNTIL:
if (rhs.isInBounds(lhs)) {
isGood = true;
}
break;
default:
throw new RuntimeException("Accumulation symbol cannot be handled...");
}
//if(isGood) {mc.getLog().print("+");} else {mc.getLog().print("-");}
return isGood;
}
/** Checks whether a track is good.
*
* Tracks are good, if they are final and fulfill the constraint in the accumulation expression with context mc.
* @param track
* @param accexp
* @param mc
* @return
* @throws PrismException
*/
protected final boolean isGoalTrack(final AccumulationTrack<Component> track, final ExpressionAccumulation accexp, final ProbModelChecker mc)
throws PrismException {
// Only final tracks can be good
if (!isFinalTrack(track,accexp,mc)) { return false; }
boolean isGood = false;
//TODO: these should be double later on
// Collect the weight linear combination, factor*weight+...
int lhs = 0;
int factorNr = 0;
for (AccumulationFactor factor : accexp.getConstraint().getFactors()) {
lhs += factor.getFactor().evaluateInt(mc.getConstantValues())
* track.getWeight(factorNr);
}
// Check the bound
IntegerBound rhs = IntegerBound.fromTemporalOperatorBound(accexp.getConstraint().getBound(), mc.getConstantValues(), true);
// For DIA operators, we just check the bound.
// For BOX operators, we check the INVERTED bound.
// TODO: THIS MAY BE BROKEN
switch(accexp.getSymbol()) {
case ACCBOXMINUS:
case ACCBOXPLUS:
if (!rhs.isInBounds(lhs)) {
isGood = true;
}
mc.getLog().println("WARNING: This may be wrong.");
break;
case ACCDIAMINUS:
case ACCDIAPLUS:
case ACCUNTIL:
if (rhs.isInBounds(lhs)) {
isGood = true;
}
break;
default:
throw new RuntimeException("Accumulation symbol cannot be handled...");
}
//if(isGood) {mc.getLog().print("+");} else {mc.getLog().print("-");}
return isGood;
}
@ -181,21 +138,8 @@ public abstract class AccumulationProduct<M extends Model,Component> extends Pro
* @param mc
* @return
*/
protected final AccumulationTrack<Component> updateTrack(Integer modelFromStateId, final AccumulationTrack<Component> track,
final ExpressionAccumulation accexp, final double[] weights, final StateModelChecker mc) {
Component nextComponent = updateComponent(modelFromStateId, track, accexp, mc);
// If we are done, return null-Track
if (nextComponent == null) { return null; }
// Otherwise, we update the weights and increase the step.
double[] newweights = new double[weights.length];
for (int i = 0; i < weights.length; i++) {
newweights[i] = weights[i] + track.getWeights()[i];
}
return new AccumulationTrack<Component>(newweights, nextComponent);
}
protected abstract AccumulationTrack<Component> updateTrack(Integer modelFromStateId, final AccumulationTrack<Component> track,
final ExpressionAccumulation accexp, final double[] weights, final StateModelChecker mc);
/** Generates a new accumulation state from an old one.
*
@ -209,66 +153,9 @@ public abstract class AccumulationProduct<M extends Model,Component> extends Pro
* @return
* @throws PrismException
*/
protected final AccumulationState<Component> updateAccumulationState(final int modelFromStateId,
protected abstract AccumulationState<Component> updateAccumulationState(final int modelFromStateId,
final AccumulationState<Component> accstate, final ExpressionAccumulation accexp,
final double[] weights, final ProbModelChecker mc) throws PrismException {
// Check if we even need to fire here.
if(accexp.hasFireOn()) {
boolean stutter = true;
for(Expression f : accexp.getFireOn()) {
if(mc.checkExpression(originalModel, f, null).getBitSet().get(modelFromStateId)) {
//mc.getLog().println("f:" + f);
stutter = false;
break;
}
}
// If this is a stutter action, we can return the same accstate. Copies are made on modification.
if(stutter) { return accstate; }
}
// ...otherwise proceed.
// Get the old tracker and tracks.
AccumulationTracker<Component> oldTracker = accstate.getTracker(trackers);
ArrayList<AccumulationTrack<Component>> oldTracks = oldTracker.getTracks();
// This restart will be...
int newLastRestartNr = accstate.getNextRestartNr();
//mc.getLog().print(newLastRestartNr);
// Build the new tracks and determine their goodness;
ArrayList<AccumulationTrack<Component>> newTracks = new ArrayList<>();
int trackNr = 0;
for(AccumulationTrack<Component> oldTrack : oldTracks) {
AccumulationTrack<Component> newTrack;
// restart or advance
if(trackNr == newLastRestartNr) {
// If we have a restart, we produce an initial track and let it advance.
AccumulationTrack<Component> freshTrack = new AccumulationTrack<Component>(numberOfWeights, getInitialComponent());
//newTrack = updateTrack(modelFromStateId, freshTrack, accexp, weights, mc);
newTrack = freshTrack;
} else if (oldTrack == null) {
// If the old track is undefined, the new track is as well.
newTrack = null;
} else {
// Otherwise, the track is defined and advances.
assert oldTrack != null;
newTrack = updateTrack(modelFromStateId, oldTrack, accexp, weights, mc);
}
newTracks.add(newTrack);
trackNr++;
}
//Create a new tracker with the right tracks and add it to storage.
AccumulationTracker<Component> newTracker = new AccumulationTracker<>(newTracks);
int newTrackerId = trackers.findOrAdd(newTracker);
return new AccumulationState<>(newTrackerId, newLastRestartNr, numberOfTracks);
}
final double[] weights, final ProbModelChecker mc) throws PrismException;
/**
* Creates the initial state for the accumulation part of this of this accumulation product. Returns its ID.
@ -292,19 +179,7 @@ public abstract class AccumulationProduct<M extends Model,Component> extends Pro
return initialAccStateId;
}
private String labelString(Integer stateId) {
StringBuffer result = new StringBuffer();
for(int t=0; t<numberOfTracks; t++) {
result.append(" " + t);
if(initStates.get(t).get(stateId)) { result.append("I"); continue; }
if(goalStates.get(t).get(stateId)) { result.append("G"); continue; }
if(runStates.get(t).get(stateId)) { result.append("R"); continue; }
result.append("_");
}
return result.toString();
}
protected abstract String labelString(Integer stateId);
@Override
public String toDot() {

270
prism/src/explicit/AccumulationProductComplex.java

@ -0,0 +1,270 @@
package explicit;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import parser.ast.ExpressionAccumulation;
import parser.ast.Expression;
import prism.PrismException;
import common.Dottable;
import explicit.rewards.MCRewards;
import explicit.rewards.Rewards;
/**
* An AccumulationProduct has ProductStates, where the first component is the
* stateId in the original model, and the second component is the index of an
* AccumulationTracker.
*
* @author Sascha Wunderlich
*
* @param <M>
*/
public abstract class AccumulationProductComplex<M extends Model,Component> extends AccumulationProduct<M,Component> implements Dottable
{
protected final ArrayList<BitSet> initStates;
protected final ArrayList<BitSet> runStates;
protected final ArrayList<BitSet> goalStates;
public AccumulationProductComplex(M originalModel) {
super(originalModel);
initStates = new ArrayList<>();
runStates = new ArrayList<>();
goalStates = new ArrayList<>();
}
public final BitSet getInitStates(int track) {
return initStates.get(track);
}
public final BitSet getRunStates(int track) {
return runStates.get(track);
}
public final BitSet getGoalStates(int track) {
return goalStates.get(track);
}
protected void generateTrackInfo(ProductState state, Integer index, ExpressionAccumulation accexp, ProbModelChecker mc) throws PrismException {
AccumulationState<Component> accState = accStates.getById(state.getSecondState());
AccumulationTracker<Component> tracker = accState.getTracker(trackers);
for(int trackIdx=0; trackIdx<tracker.getTracks().size(); trackIdx++) {
AccumulationTrack<Component> track = tracker.getTracks().get(trackIdx);
// Is this an initial
if (trackIdx==accState.lastRestartNr) {
initStates.get(trackIdx).set(index);
}
// Is this a running track?
if (track != null) {
runStates.get(trackIdx).set(index);
}
// Is this a goal track?
if (isGoalTrack(track, accexp, mc)) {
goalStates.get(trackIdx).set(index);
}
}
}
/** Checks whether a track is final according to the bound in the accumulation expression and the context in mc.
* @param track
* @param accexp
* @param mc
* @return
* @throws PrismException
*/
protected abstract boolean isFinalTrack(final AccumulationTrack<Component> track, final ExpressionAccumulation accexp, final ProbModelChecker mc)
throws PrismException;
/** Get the initial Component of the accumulation monitor.
* @return
*/
protected abstract Component getInitialComponent();
/** Update the Component of the accumulation monitor when leaving modelFromStateId.
* @param modelFromStateId
* @param track
* @param accexp
* @param mc
* @return
*/
protected abstract Component updateComponent(Integer modelFromStateId, final AccumulationTrack<Component> track,
final ExpressionAccumulation accexp, final StateModelChecker mc);
/** Updates a single AccumulationTrack. Used in updateAccumulationState.
*
* Uses updateComponent to get the next Component, accumulates the current weights
* and makes a new track.
* @param modelFromStateId
* @param track
* @param accexp
* @param weights
* @param mc
* @return
*/
protected final AccumulationTrack<Component> updateTrack(Integer modelFromStateId, final AccumulationTrack<Component> track,
final ExpressionAccumulation accexp, final double[] weights, final StateModelChecker mc) {
Component nextComponent = updateComponent(modelFromStateId, track, accexp, mc);
// If we are done, return null-Track
if (nextComponent == null) { return null; }
// Otherwise, we update the weights and increase the step.
double[] newweights = new double[weights.length];
for (int i = 0; i < weights.length; i++) {
newweights[i] = weights[i] + track.getWeights()[i];
}
return new AccumulationTrack<Component>(newweights, nextComponent);
}
/** Generates a new accumulation state from an old one.
*
* To do so, it reads the necessary information from the model and its rewards
* and updates all tracks and their goodness accordingly.
* @param modelFromStateId
* @param accstate
* @param accexp
* @param weights
* @param mc
* @return
* @throws PrismException
*/
protected final AccumulationState<Component> updateAccumulationState(final int modelFromStateId,
final AccumulationState<Component> accstate, final ExpressionAccumulation accexp,
final double[] weights, final ProbModelChecker mc) throws PrismException {
// Check if we even need to fire here.
if(accexp.hasFireOn()) {
boolean stutter = true;
for(Expression f : accexp.getFireOn()) {
if(mc.checkExpression(originalModel, f, null).getBitSet().get(modelFromStateId)) {
//mc.getLog().println("f:" + f);
stutter = false;
break;
}
}
// If this is a stutter action, we can return the same accstate. Copies are made on modification.
if(stutter) { return accstate; }
}
// ...otherwise proceed.
// Get the old tracker and tracks.
AccumulationTracker<Component> oldTracker = accstate.getTracker(trackers);
ArrayList<AccumulationTrack<Component>> oldTracks = oldTracker.getTracks();
// This restart will be...
int newLastRestartNr = accstate.getNextRestartNr();
//mc.getLog().print(newLastRestartNr);
// Build the new tracks and determine their goodness;
ArrayList<AccumulationTrack<Component>> newTracks = new ArrayList<>();
int trackNr = 0;
for(AccumulationTrack<Component> oldTrack : oldTracks) {
AccumulationTrack<Component> newTrack;
// restart or advance
if(trackNr == newLastRestartNr) {
// If we have a restart, we produce an initial track and let it advance.
AccumulationTrack<Component> freshTrack = new AccumulationTrack<Component>(numberOfWeights, getInitialComponent());
//newTrack = updateTrack(modelFromStateId, freshTrack, accexp, weights, mc);
newTrack = freshTrack;
} else if (oldTrack == null) {
// If the old track is undefined, the new track is as well.
newTrack = null;
} else {
// Otherwise, the track is defined and advances.
assert oldTrack != null;
newTrack = updateTrack(modelFromStateId, oldTrack, accexp, weights, mc);
}
newTracks.add(newTrack);
trackNr++;
}
//Create a new tracker with the right tracks and add it to storage.
AccumulationTracker<Component> newTracker = new AccumulationTracker<>(newTracks);
int newTrackerId = trackers.findOrAdd(newTracker);
return new AccumulationState<>(newTrackerId, newLastRestartNr, numberOfTracks);
}
protected String labelString(Integer stateId) {
StringBuffer result = new StringBuffer();
for(int t=0; t<numberOfTracks; t++) {
result.append(" " + t);
if(initStates.get(t).get(stateId)) { result.append("I"); continue; }
if(goalStates.get(t).get(stateId)) { result.append("G"); continue; }
if(runStates.get(t).get(stateId)) { result.append("R"); continue; }
result.append("_");
}
return result.toString();
}
@Override
public String toDot() {
StringBuffer result = new StringBuffer();
result.append("digraph " + originalModel.getModelType() + " {\n");
for(int i = 0; i < prod_states.size(); i++) {
ProductState fromState = prod_states.get(i);
AccumulationState<Component> accState = accStates.getById(fromState.getSecondState());
AccumulationTracker<Component> tracker = accState.getTracker(trackers);
result.append(""
+ i
+ "[shape=box, color=black"
+ " label= < <TABLE BORDER=\"0\">"
+ "<TR>"
+ "<TD>" + i + "=" + fromState + "</TD>"
+ "</TR><TR>"
+ "<TD> " + accState + "</TD>"
+ "</TR><TR>"
+ "<TD> " + labelString(i) + "</TD>"
+ "</TR><TR>"
+ "<TD>\"" + Dottable.quoteForDot(tracker.toString()) + "\"</TD>"
+ "</TR>"
+ " </TABLE> >]\n");
switch(productModel.getModelType()) {
case DTMC:
DTMCExplicit castDTMC = (DTMCExplicit)productModel;
Iterator<Map.Entry<Integer, Double>> dtmcIter = castDTMC.getTransitionsIterator(i);
while (dtmcIter.hasNext()) {
Map.Entry<Integer, Double> e = dtmcIter.next();
result.append(i + " -> " + e.getKey() + " [ label=\"");
result.append(e.getValue() + "\" ];\n");
}
break;
case MDP:
MDPExplicit castMDP = (MDPExplicit)productModel;
for(int c = 0; c < castMDP.getNumChoices(i); c++) {
Iterator<Map.Entry<Integer, Double>> mdpIter = castMDP.getTransitionsIterator(i, c);
while (mdpIter.hasNext()) {
Map.Entry<Integer, Double> e = mdpIter.next();
result.append(i + " -> " + e.getKey() + " [ label=\"");
result.append(c + "," + e.getValue() + "\" ];\n");
}
}
break;
default:
break;
}
}
result.append("}");
return result.toString();
}
}

18
prism/src/explicit/AccumulationProductCounting.java → prism/src/explicit/AccumulationProductComplexCounting.java

@ -20,27 +20,27 @@ import prism.PrismException;
* @param <M>
*/
public class AccumulationProductCounting<M extends Model> extends AccumulationProduct<M,Integer>
public class AccumulationProductComplexCounting<M extends Model> extends AccumulationProductComplex<M,Integer>
{
public AccumulationProductCounting(M originalModel) {
public AccumulationProductComplexCounting(M originalModel) {
super(originalModel);
}
@SuppressWarnings("unchecked")
public static <T extends Model, R extends Rewards> AccumulationProductCounting<T> generate(final Model graph, final ExpressionAccumulation accexp, final Vector<R> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
public static <T extends Model, R extends Rewards> AccumulationProductComplexCounting<T> generate(final Model graph, final ExpressionAccumulation accexp, final Vector<R> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
switch(graph.getModelType()) {
case DTMC:
return (AccumulationProductCounting<T>)generate((DTMC) graph, accexp, (Vector<MCRewards>) rewards, mc, statesOfInterest);
return (AccumulationProductComplexCounting<T>)generate((DTMC) graph, accexp, (Vector<MCRewards>) rewards, mc, statesOfInterest);
case MDP:
return (AccumulationProductCounting<T>)generate((MDP) graph, accexp, (Vector<MDPRewards>) rewards, mc, statesOfInterest);
return (AccumulationProductComplexCounting<T>)generate((MDP) graph, accexp, (Vector<MDPRewards>) rewards, mc, statesOfInterest);
default:
throw new PrismException("Can't handle accumulation product for " + graph.getModelType());
}
}
public static AccumulationProductCounting<DTMC> generate(final DTMC graph, final ExpressionAccumulation accexp, final Vector<MCRewards> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
final AccumulationProductCounting<DTMC> result = new AccumulationProductCounting<DTMC>(graph);
public static AccumulationProductComplexCounting<DTMC> generate(final DTMC graph, final ExpressionAccumulation accexp, final Vector<MCRewards> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
final AccumulationProductComplexCounting<DTMC> result = new AccumulationProductComplexCounting<DTMC>(graph);
// Create auxiliary data
result.createAuxData(graph, accexp, rewards, mc);
@ -98,9 +98,9 @@ public class AccumulationProductCounting<M extends Model> extends AccumulationPr
return result;
}
public static AccumulationProductCounting<MDP> generate(final MDP graph, final ExpressionAccumulation accexp, final Vector<MDPRewards> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
public static AccumulationProductComplexCounting<MDP> generate(final MDP graph, final ExpressionAccumulation accexp, final Vector<MDPRewards> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
// This is basically the same thing as for DTMCs
final AccumulationProductCounting<MDP> result = new AccumulationProductCounting<MDP>(graph);
final AccumulationProductComplexCounting<MDP> result = new AccumulationProductComplexCounting<MDP>(graph);
// Create auxiliary data
result.createAuxData(graph, accexp, rewards, mc);

18
prism/src/explicit/AccumulationProductRegular.java → prism/src/explicit/AccumulationProductComplexRegular.java

@ -26,28 +26,28 @@ import prism.PrismSettings;
* @param <M>
*/
public class AccumulationProductRegular<M extends Model> extends AccumulationProduct<M,State>
public class AccumulationProductComplexRegular<M extends Model> extends AccumulationProductComplex<M,State>
{
protected DeterministicFiniteAutomaton<String> automaton;
public AccumulationProductRegular(M originalModel) {
public AccumulationProductComplexRegular(M originalModel) {
super(originalModel);
}
@SuppressWarnings("unchecked")
public static <T extends Model, R extends Rewards> AccumulationProductRegular<T> generate(final Model graph, final ExpressionAccumulation accexp, final Vector<R> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
public static <T extends Model, R extends Rewards> AccumulationProductComplexRegular<T> generate(final Model graph, final ExpressionAccumulation accexp, final Vector<R> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
switch(graph.getModelType()) {
case DTMC:
return (AccumulationProductRegular<T>)generate((DTMC) graph, accexp, (Vector<MCRewards>) rewards, mc, statesOfInterest);
return (AccumulationProductComplexRegular<T>)generate((DTMC) graph, accexp, (Vector<MCRewards>) rewards, mc, statesOfInterest);
case MDP:
return (AccumulationProductRegular<T>)generate((MDP) graph, accexp, (Vector<MDPRewards>) rewards, mc, statesOfInterest);
return (AccumulationProductComplexRegular<T>)generate((MDP) graph, accexp, (Vector<MDPRewards>) rewards, mc, statesOfInterest);
default:
throw new PrismException("Can't handle accumulation product for " + graph.getModelType());
}
}
public static AccumulationProductRegular<DTMC> generate(final DTMC graph, final ExpressionAccumulation accexp, final Vector<MCRewards> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
final AccumulationProductRegular<DTMC> result = new AccumulationProductRegular<DTMC>(graph);
public static AccumulationProductComplexRegular<DTMC> generate(final DTMC graph, final ExpressionAccumulation accexp, final Vector<MCRewards> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
final AccumulationProductComplexRegular<DTMC> result = new AccumulationProductComplexRegular<DTMC>(graph);
// Create auxiliary data
result.createAuxData(graph, accexp, rewards, mc);
@ -105,9 +105,9 @@ public class AccumulationProductRegular<M extends Model> extends AccumulationPro
return result;
}
public static AccumulationProductRegular<MDP> generate(final MDP graph, final ExpressionAccumulation accexp, final Vector<MDPRewards> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
public static AccumulationProductComplexRegular<MDP> generate(final MDP graph, final ExpressionAccumulation accexp, final Vector<MDPRewards> rewards, final ProbModelChecker mc, BitSet statesOfInterest) throws PrismException {
// This is basically the same thing as for DTMCs
final AccumulationProductRegular<MDP> result = new AccumulationProductRegular<MDP>(graph);
final AccumulationProductComplexRegular<MDP> result = new AccumulationProductComplexRegular<MDP>(graph);
// Create auxiliary data
result.createAuxData(graph, accexp, rewards, mc);

89
prism/src/explicit/AccumulationTransformation.java

@ -63,19 +63,15 @@ public class AccumulationTransformation<M extends Model> implements ModelExpress
return product.projectToOriginalModel(svTransformedModel);
}
@SuppressWarnings("unchecked")
private void doTransformation() throws PrismException {
private void doTransformation() throws PrismException {
mc.getLog().println("Performing accumulation transformation...");
// We work on a copy
transformedExpression = originalExpression.deepCopy();
// Get the first ExpressionAccumulation
ExpressionAccumulation accexp = transformedExpression.getFirstAccumulationExpression();
mc.getLog().println(" [AT] for " + accexp);
if (accexp.isNullary() && !accexp.hasFireOn()) {
mc.getLog().println(" ... a simple expression.");
}
// Get the rewards and build the product
Vector<Rewards> rewards = new Vector<Rewards>();
@ -86,13 +82,27 @@ public class AccumulationTransformation<M extends Model> implements ModelExpress
ConstructRewards constructRewards = new ConstructRewards();
constructRewards.allowNegativeRewards();
Rewards dtmc_reward = constructRewards.buildRewardStructure(originalModel, rewStruct, mc.getConstantValues());
rewards.add(i,dtmc_reward);
Rewards reward = constructRewards.buildRewardStructure(originalModel, rewStruct, mc.getConstantValues());
rewards.add(i,reward);
}
boolean isComplex = mc.getSettings().getBoolean(PrismSettings.ACC_FORCE_COMPLEX) || accexp.hasFireOn() || !accexp.isNullary();
if (isComplex) {
mc.getLog().println(" ... which is COMPLEX.");
doTransformationComplex(accexp, rewards);
} else {
mc.getLog().println(" ... which is SIMPLE.");
doTransformationSimple(accexp, rewards);
}
}
@SuppressWarnings("unchecked")
private void doTransformationComplex(ExpressionAccumulation accexp, Vector<Rewards> rewards) throws PrismException {
// Build the product
if(accexp.hasRegularExpression()) {
product = (AccumulationProductRegular<M>) AccumulationProductRegular.generate(originalModel, accexp, rewards, mc, statesOfInterest);
product = (AccumulationProductComplexRegular<M>) AccumulationProductComplexRegular.generate(originalModel, accexp, rewards, mc, statesOfInterest);
} else if (accexp.hasBoundExpression()) {
product = (AccumulationProductCounting<M>) AccumulationProductCounting.generate(originalModel, accexp, rewards, mc, statesOfInterest);
product = (AccumulationProductComplexCounting<M>) AccumulationProductComplexCounting.generate(originalModel, accexp, rewards, mc, statesOfInterest);
} else {
throw new PrismException("Accumulation Expression has no valid monitor!");
}
@ -106,33 +116,70 @@ public class AccumulationTransformation<M extends Model> implements ModelExpress
ArrayList<String> runLabels = new ArrayList<String>();
ArrayList<String> goalLabels = new ArrayList<String>();
for(int track=0; track < product.getNumberOfTracks(); track++) {
BitSet initStates = product.getInitStates(track);
BitSet runStates = product.getRunStates(track);
BitSet goalStates = product.getGoalStates(track);
AccumulationProductComplex<M,?> productComplex = (AccumulationProductComplex<M,?>) product;
for(int track=0; track < productComplex.getNumberOfTracks(); track++) {
BitSet initStates = productComplex.getInitStates(track);
BitSet runStates = productComplex.getRunStates(track);
BitSet goalStates = productComplex.getGoalStates(track);
String initLabel = ((ModelExplicit)product.getTransformedModel()).addUniqueLabel("init" + track, initStates, product.getTransformedModel().getLabels());
String initLabel = ((ModelExplicit)productComplex.getTransformedModel()).addUniqueLabel("init" + track, initStates, productComplex.getTransformedModel().getLabels());
initLabels.add(initLabel);
String runLabel = ((ModelExplicit)product.getTransformedModel()).addUniqueLabel("run" + track, runStates, product.getTransformedModel().getLabels());
String runLabel = ((ModelExplicit)productComplex.getTransformedModel()).addUniqueLabel("run" + track, runStates, productComplex.getTransformedModel().getLabels());
runLabels.add(runLabel);
String goalLabel = ((ModelExplicit)product.getTransformedModel()).addUniqueLabel("goal" + track, goalStates, product.getTransformedModel().getLabels());
String goalLabel = ((ModelExplicit)productComplex.getTransformedModel()).addUniqueLabel("goal" + track, goalStates, productComplex.getTransformedModel().getLabels());
goalLabels.add(goalLabel);
//mc.getLog().println(initStates + " | " + initLabel);
//mc.getLog().println(runStates + " | " + runLabel);
//mc.getLog().println(goalStates + " | " + goalLabel);
}
// Transform the expression
mc.getLog().println(" [AT] replacing the formula...");
ReplaceAccumulationExpression replace = new ReplaceAccumulationExpression(accexp, mc, initLabels, runLabels, goalLabels, product.getNumberOfTracks()-1);
transformedExpression = (Expression)transformedExpression.accept(replace);
mc.getLog().println(" [AT] " + originalExpression.toString() + "\n" +
" -> " + transformedExpression.toString());
if(mc.getSettings().getBoolean(PrismSettings.ACC_GENERATE_DOTS)) {
product.exportToDotFile("DEBUG-product.dot");
}
}
@SuppressWarnings("unchecked")
private void doTransformationSimple(ExpressionAccumulation accexp, Vector<Rewards> rewards) throws PrismException {
throw new PrismException("Stop, Hammer Time!");
/*
AccumulationProductSimple<M,?> productSimple = (AccumulationProductSimple<M,?>) product;
// Build the product
if(accexp.hasRegularExpression()) {
productSimple = (AccumulationProductSimpleRegular<M>) AccumulationProductSimpleRegular.generate(originalModel, accexp, rewards, mc, statesOfInterest);
} else if (accexp.hasBoundExpression()) {
productSimple = (AccumulationProductSimpleCounting<M>) AccumulationProductSimpleCounting.generate(originalModel, accexp, rewards, mc, statesOfInterest);
} else {
throw new PrismException("Accumulation Expression has no valid monitor!");
}
mc.getLog().println(" [AT] finished product construction: " + productSimple.getTransformedModel().getNumStates());
// Transform the model
mc.getLog().println(" [AT] getting the init/run/goal states: ");
mc.getLog().println(" [AT] model transformation done. " + product.trackers.size() + " trackers.");
ArrayList<String> goalLabels = new ArrayList<String>();
BitSet goodStates = productSimple.getGoodStates();
String goalLabel = ((ModelExplicit)productSimple.getTransformedModel()).addUniqueLabel("good", goodStates, productSimple.getTransformedModel().getLabels());
goalLabels.add(goalLabel);
// Transform the expression
mc.getLog().println(" [AT] replacing the formula...");
ReplaceAccumulationExpression replace = new ReplaceAccumulationExpression(accexp, initLabels, runLabels, goalLabels, product.getNumberOfTracks()-1);
ReplaceAccumulationExpression replace = new ReplaceAccumulationExpression(accexp, mc, null, null, goalLabels, productSimple.getNumberOfTracks()-1);
transformedExpression = (Expression)transformedExpression.accept(replace);
mc.getLog().println(" [AT] " + originalExpression.toString() + "\n" +
" -> " + transformedExpression.toString());
if(mc.getSettings().getBoolean(PrismSettings.ACC_GENERATE_DOTS)) {
product.exportToDotFile("DEBUG-product.dot");
productSimple.exportToDotFile("DEBUG-product.dot");
}
*/
}
}

115
prism/src/parser/visitor/ReplaceAccumulationExpression.java

@ -2,6 +2,7 @@ package parser.visitor;
import java.util.ArrayList;
import explicit.ProbModelChecker;
import parser.ast.AccumulationSymbol;
import parser.ast.Expression;
import parser.ast.ExpressionAccumulation;
@ -9,76 +10,104 @@ import parser.ast.ExpressionBinaryOp;
import parser.ast.ExpressionLabel;
import parser.ast.ExpressionTemporal;
import parser.ast.ExpressionUnaryOp;
import parser.ast.TemporalOperatorBound;
import parser.ast.TemporalOperatorBounds;
import prism.IntegerBound;
import prism.PrismLangException;
import prism.PrismSettings;
public class ReplaceAccumulationExpression extends ASTTraverseModify {
private ExpressionAccumulation accexp;
private ProbModelChecker mc;
private ArrayList<String> initLabels;
private ArrayList<String> runLabels;
private ArrayList<String> goalLabels;
private int accLength;
public ReplaceAccumulationExpression(ExpressionAccumulation accexp, ArrayList<String> initLabels, ArrayList<String> runLabels, ArrayList<String> goalLabels, int accLength) {
public ReplaceAccumulationExpression(ExpressionAccumulation accexp, ProbModelChecker mc, ArrayList<String> initLabels, ArrayList<String> runLabels, ArrayList<String> goalLabels, int accLength) {
super();
this.accexp = accexp;
this.mc = mc;
this.initLabels = initLabels;
this.runLabels = runLabels;
this.goalLabels = goalLabels;
this.accLength = accLength;
}
public Object visit(ExpressionAccumulation expr) throws PrismLangException
{
if (expr == accexp) {
AccumulationSymbol sym = expr.getSymbol();
private Object replaceWithUntil(ExpressionAccumulation accexpr) throws PrismLangException {
// This expression is of the form OR{0..(l-1)}(init_i AND (run_i UNTIL goal_i))
// Build all the subexpressions...
ArrayList<ExpressionBinaryOp> clauses = new ArrayList<>();
Expression result = null;
for(int i=0; i<accLength; i++) {
Expression init = new ExpressionLabel(initLabels.get(i));
Expression run = new ExpressionLabel(runLabels.get(i));
Expression goal = new ExpressionLabel(goalLabels.get(i));
if (sym.isMinus()) {
throw(new PrismLangException("Accumulation with past is not supported."));
// if this is until:
// append first operand to run
// append second operand to goal
if(accexp.getOperand1() != null) {
run = new ExpressionBinaryOp(ExpressionBinaryOp.AND, run, accexp.getOperand1());
}
if(accexp.getOperand2() != null) {
goal = new ExpressionBinaryOp(ExpressionBinaryOp.AND, goal, accexp.getOperand2());
}
// This expression is of the form OR{0..(l-1)}(init_i AND (run_i UNTIL goal_i))
// Build all the subexpressions...
ArrayList<ExpressionBinaryOp> clauses = new ArrayList<>();
Expression result = null;
// until: (run_i UNTIL goal_i)
ExpressionTemporal until = new ExpressionTemporal(ExpressionTemporal.P_U, run, goal);
// and: (init_i AND until)
ExpressionBinaryOp and = new ExpressionBinaryOp(ExpressionBinaryOp.AND, init, until);
for(int i=0; i<accLength; i++) {
Expression init = new ExpressionLabel(initLabels.get(i));
Expression run = new ExpressionLabel(runLabels.get(i));
Expression goal = new ExpressionLabel(goalLabels.get(i));
// if this is until:
// append first operand to run
// append second operand to goal
if(accexp.getOperand1() != null) {
run = new ExpressionBinaryOp(ExpressionBinaryOp.AND, run, accexp.getOperand1());
}
if(accexp.getOperand2() != null) {
goal = new ExpressionBinaryOp(ExpressionBinaryOp.AND, goal, accexp.getOperand2());
}
// until: (run_i UNTIL goal_i)
ExpressionTemporal until = new ExpressionTemporal(ExpressionTemporal.P_U, run, goal);
// and: (init_i AND until)
ExpressionBinaryOp and = new ExpressionBinaryOp(ExpressionBinaryOp.AND, init, until);
clauses.add(and);
if(i==0) {
result = and;
} else {
result = new ExpressionBinaryOp(ExpressionBinaryOp.OR, result, and);
}
clauses.add(and);
if(i==0) {
result = and;
} else {
result = new ExpressionBinaryOp(ExpressionBinaryOp.OR, result, and);
}
}
return result;
}
private Object replaceWithReach(ExpressionAccumulation expr) throws PrismLangException {
AccumulationSymbol sym = accexp.getSymbol();
ExpressionLabel label = new ExpressionLabel(goalLabels.get(0));
if (sym.isPlus()) {
ExpressionTemporal fExpr = new ExpressionTemporal(ExpressionTemporal.P_F, null, label);
TemporalOperatorBounds fBounds = new TemporalOperatorBounds();
TemporalOperatorBound fBound = IntegerBound.fromEqualBounds(accLength).toTemporalOperatorBound();
fBounds.setDefaultBound(fBound);
fExpr.setBounds(fBounds);
// If its a BOX, negate it
if (sym.isBox()) {
return new ExpressionUnaryOp(ExpressionUnaryOp.NOT, result);
return new ExpressionUnaryOp(ExpressionUnaryOp.NOT, fExpr);
} else {
return fExpr;
}
} else { //isMinus
if (sym.isBox()) {
return new ExpressionUnaryOp(ExpressionUnaryOp.NOT, label);
} else {
return label;
}
}
}
public Object visit(ExpressionAccumulation expr) throws PrismLangException
{
if (expr == accexp) {
if (mc.getSettings().getBoolean(PrismSettings.ACC_FORCE_COMPLEX) || accexp.hasFireOn() || !accexp.isNullary()) {
// This is a complex accumulation expression. Rewrite to until formula.
return replaceWithUntil(expr);
} else {
return result;
// This is a simple accumulation expression. Rewrite to F=....
return replaceWithReach(expr);
}
} else {
return expr;

9
prism/src/prism/PrismSettings.java

@ -160,6 +160,7 @@ public class PrismSettings implements Observer
//Accumulation
public static final String ACC_GENERATE_DOTS = "accumulation.generateDots";
public static final String ACC_FORCE_COMPLEX = "accumulation.forceComplex";
//GUI Model
public static final String MODEL_AUTO_PARSE = "model.autoParse";
@ -414,7 +415,8 @@ public class PrismSettings implements Observer
"File specifying the network profile used by the distributed PRISM simulator." }
},
{
{ BOOLEAN_TYPE, ACC_GENERATE_DOTS, "Accumulation: generate DOT files", "4.3", false, "", "Generate DOT files for accumulation monitors and products"}
{ BOOLEAN_TYPE, ACC_GENERATE_DOTS, "Accumulation: generate DOT files", "4.4", false, "", "Generate DOT files for accumulation monitors and products"},
{ BOOLEAN_TYPE, ACC_FORCE_COMPLEX, "Accumulation: force U-construction", "4.4", false, "", "Force compxe accumulation construction"}
},
{
{ BOOLEAN_TYPE, MODEL_AUTO_PARSE, "Auto parse", "2.1", new Boolean(true), "", "Parse PRISM models automatically as they are loaded/edited in the text editor." },
@ -1694,6 +1696,11 @@ public class PrismSettings implements Observer
boolean b = Boolean.parseBoolean(args[++i]);
set(ACC_GENERATE_DOTS, b);
}
else if (sw.equals("accforcecomplex")) {
boolean b = Boolean.parseBoolean(args[++i]);
set(ACC_FORCE_COMPLEX, b);
}
// HIDDEN OPTIONS

Loading…
Cancel
Save