Browse Source

exact/parametric: support if-the-else expressions in properties

+ test case
master
Joachim Klein 8 years ago
committed by Dave Parker
parent
commit
45ac6e02e8
  1. 10
      prism-tests/functionality/verify/param/param-ite.prism
  2. 2
      prism-tests/functionality/verify/param/param-ite.prism.args
  3. 7
      prism-tests/functionality/verify/param/param-ite.prism.props
  4. 18
      prism/src/param/BoxRegion.java
  5. 18
      prism/src/param/ParamModelChecker.java
  6. 2
      prism/src/param/Region.java
  7. 17
      prism/src/param/RegionIntersection.java
  8. 49
      prism/src/param/RegionValues.java
  9. 24
      prism/src/param/RegionValuesIntersections.java

10
prism-tests/functionality/verify/param/param-ite.prism

@ -0,0 +1,10 @@
dtmc
const double p;
formula outcome = (s>0 ? s-1 : -1);
module M1
s: [0..4] init 0;
[] s=0 -> 1/2:(s'=0) + 1/8:(s'=1) + 1/8:(s'=2) + 1/8:(s'=3) + 1/8:(s'=4);
endmodule

2
prism-tests/functionality/verify/param/param-ite.prism.args

@ -0,0 +1,2 @@
-exact -const p=0
-param p=0:1

7
prism-tests/functionality/verify/param/param-ite.prism.props

@ -0,0 +1,7 @@
// test case: support for if-then-else and formulas in expressions (exact / parametric)
// RESULT: 1/4
P=?[F outcome=2]
// RESULT: 0
P=?[G outcome=-1]

18
prism/src/param/BoxRegion.java

@ -416,6 +416,24 @@ final class BoxRegion extends Region {
return result; return result;
} }
@Override
RegionValues ITE(StateValues valuesI, StateValues valuesT, StateValues valuesE)
{
RegionValues result = new RegionValues(factory);
int numStates = valuesI.getNumStates();
StateValues values = new StateValues(numStates, factory.getInitialState());
for (int state = 0; state < numStates; state++) {
if (valuesI.getStateValueAsBoolean(state)) {
values.setStateValue(state, valuesT.getStateValue(state));
} else {
values.setStateValue(state, valuesE.getStateValue(state));
}
}
result.add(this, values);
return result;
}
/** /**
* Split region in longest dimension. * Split region in longest dimension.
* *

18
prism/src/param/ParamModelChecker.java

@ -70,6 +70,7 @@ import parser.ast.ExpressionFilter.FilterOperator;
import parser.ast.ExpressionForAll; import parser.ast.ExpressionForAll;
import parser.ast.ExpressionFormula; import parser.ast.ExpressionFormula;
import parser.ast.ExpressionFunc; import parser.ast.ExpressionFunc;
import parser.ast.ExpressionITE;
import parser.ast.ExpressionLabel; import parser.ast.ExpressionLabel;
import parser.ast.ExpressionLiteral; import parser.ast.ExpressionLiteral;
import parser.ast.ExpressionProb; import parser.ast.ExpressionProb;
@ -371,6 +372,8 @@ final public class ParamModelChecker extends PrismComponent
res = checkExpressionUnaryOp(model, (ExpressionUnaryOp) expr, needStates); res = checkExpressionUnaryOp(model, (ExpressionUnaryOp) expr, needStates);
} else if (expr instanceof ExpressionBinaryOp) { } else if (expr instanceof ExpressionBinaryOp) {
res = checkExpressionBinaryOp(model, (ExpressionBinaryOp) expr, needStates); res = checkExpressionBinaryOp(model, (ExpressionBinaryOp) expr, needStates);
} else if (expr instanceof ExpressionITE) {
res = checkExpressionITE(model, (ExpressionITE) expr, needStates);
} else if (expr instanceof ExpressionLabel) { } else if (expr instanceof ExpressionLabel) {
res = checkExpressionLabel(model, (ExpressionLabel) expr, needStates); res = checkExpressionLabel(model, (ExpressionLabel) expr, needStates);
} else if (expr instanceof ExpressionFormula) { } else if (expr instanceof ExpressionFormula) {
@ -466,6 +469,21 @@ final public class ParamModelChecker extends PrismComponent
return res1.binaryOp(parserBinaryOpToRegionOp(expr.getOperator()), res2); return res1.binaryOp(parserBinaryOpToRegionOp(expr.getOperator()), res2);
} }
/**
* Model check an If-Then-Else operator.
*/
protected RegionValues checkExpressionITE(ParamModel model, ExpressionITE expr, BitSet needStates) throws PrismException
{
RegionValues resI = checkExpression(model, expr.getOperand1(), needStates);
RegionValues resT = checkExpression(model, expr.getOperand2(), needStates);
RegionValues resE = checkExpression(model, expr.getOperand3(), needStates);
resI.clearNotNeeded(needStates);
resT.clearNotNeeded(needStates);
resE.clearNotNeeded(needStates);
return resI.ITE(resT, resE);
}
/** /**
* Model check a label. * Model check a label.
*/ */

2
prism/src/param/Region.java

@ -94,6 +94,8 @@ abstract class Region {
abstract RegionValues binaryOp(int op, StateValues values1, StateValues values2); abstract RegionValues binaryOp(int op, StateValues values1, StateValues values2);
abstract RegionValues ITE(StateValues valueI, StateValues valueT, StateValues valueE);
/** /**
* Splits this region into several parts. * Splits this region into several parts.
* How this is done exactly depends on the implementation in derived * How this is done exactly depends on the implementation in derived

17
prism/src/param/RegionIntersection.java

@ -30,7 +30,7 @@ package param;
* Maintains the intersection of two regions. * Maintains the intersection of two regions.
* This class is to be used in combination with * This class is to be used in combination with
* {@code RegionValuesIntersections} to iterate over the intersection * {@code RegionValuesIntersections} to iterate over the intersection
* of two {@RegionValues}.
* of two (or three) {@RegionValues}.
* *
* @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford) * @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
* @see RegionValuesIntersections * @see RegionValuesIntersections
@ -39,14 +39,21 @@ final class RegionIntersection {
private Region region; private Region region;
private StateValues values1; private StateValues values1;
private StateValues values2; private StateValues values2;
private StateValues values3;
public RegionIntersection(Region region, StateValues values1, StateValues values2) public RegionIntersection(Region region, StateValues values1, StateValues values2)
{
this(region, values1, values2, null);
}
public RegionIntersection(Region region, StateValues values1, StateValues values2, StateValues values3)
{ {
this.region = region; this.region = region;
this.values1 = values1; this.values1 = values1;
this.values2 = values2; this.values2 = values2;
this.values3 = values3;
} }
public Region getRegion() public Region getRegion()
{ {
return region; return region;
@ -61,4 +68,10 @@ final class RegionIntersection {
{ {
return values2; return values2;
} }
public StateValues getStateValues3()
{
return values3;
}
} }

49
prism/src/param/RegionValues.java

@ -176,6 +176,40 @@ public final class RegionValues implements Iterable<Entry<Region, StateValues>>
other.values = otherNewStateValues; other.values = otherNewStateValues;
} }
public void cosplit(RegionValues other, RegionValues other2)
{
this.simplify();
other.simplify();
other2.simplify();
ArrayList<Region> newRegions = new ArrayList<Region>();
HashMap<Region, StateValues> thisNewStateValues = new HashMap<Region, StateValues>();
HashMap<Region, StateValues> otherNewStateValues = new HashMap<Region, StateValues>();
HashMap<Region, StateValues> other2NewStateValues = new HashMap<Region, StateValues>();
for (Region thisRegion : this.regions) {
for (Region otherRegion : other.regions) {
for (Region other2Region : other2.regions) {
Region newRegion = thisRegion.conjunct(otherRegion);
if (newRegion != null)
newRegion = newRegion.conjunct(other2Region);
if (newRegion != null) {
newRegions.add(newRegion);
thisNewStateValues.put(newRegion, this.values.get(thisRegion));
otherNewStateValues.put(newRegion, other.values.get(otherRegion));
other2NewStateValues.put(newRegion, other2.values.get(other2Region));
}
}
}
}
this.regions = new ArrayList<Region>(newRegions);
this.values = thisNewStateValues;
other.regions = new ArrayList<Region>(newRegions);
other.values = otherNewStateValues;
other2.regions = new ArrayList<Region>(newRegions);
other2.values = other2NewStateValues;
}
@Override @Override
public String toString() public String toString()
{ {
@ -478,4 +512,19 @@ public final class RegionValues implements Iterable<Entry<Region, StateValues>>
} }
return result; return result;
} }
public RegionValues ITE(RegionValues resT, RegionValues resE)
{
RegionValues result = new RegionValues(factory);
RegionValuesIntersections co = new RegionValuesIntersections(this, resT, resE);
for (RegionIntersection inter : co) {
Region region = inter.getRegion();
StateValues valueI = inter.getStateValues1();
StateValues valueT = inter.getStateValues2();
StateValues valueE = inter.getStateValues3();
RegionValues values = region.ITE(valueI, valueT, valueE);
result.addAll(values);
}
return result;
}
} }

24
prism/src/param/RegionValuesIntersections.java

@ -30,28 +30,33 @@ import java.util.Iterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
/** /**
* Computes the intersections of two (or three) regions.
* @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford) * @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
*/ */
final class RegionValuesIntersections implements Iterable<RegionIntersection> { final class RegionValuesIntersections implements Iterable<RegionIntersection> {
final private class RegionIntersectionOperator implements Iterator<RegionIntersection> { final private class RegionIntersectionOperator implements Iterator<RegionIntersection> {
private RegionValues regions1; private RegionValues regions1;
private RegionValues regions2; private RegionValues regions2;
private RegionValues regions3;
private int numRegions1; private int numRegions1;
private int regions1Index; private int regions1Index;
private boolean hasNext; private boolean hasNext;
private Region region; private Region region;
private StateValues stateValues1; private StateValues stateValues1;
private StateValues stateValues2; private StateValues stateValues2;
private StateValues stateValues3;
RegionIntersectionOperator(RegionValues regions1, RegionValues regions2)
RegionIntersectionOperator(RegionValues regions1, RegionValues regions2, RegionValues regions3)
{ {
this.regions1 = regions1; this.regions1 = regions1;
this.regions2 = regions2; this.regions2 = regions2;
this.regions3 = regions3;
regions1Index = 0; regions1Index = 0;
numRegions1 = regions1.getNumRegions(); numRegions1 = regions1.getNumRegions();
region = null; region = null;
stateValues1 = null; stateValues1 = null;
stateValues2 = null; stateValues2 = null;
stateValues3 = null;
findNext(); findNext();
} }
@ -61,7 +66,9 @@ final class RegionValuesIntersections implements Iterable<RegionIntersection> {
region = regions1.getRegion(regions1Index); region = regions1.getRegion(regions1Index);
stateValues1 = regions1.getResult(region); stateValues1 = regions1.getResult(region);
stateValues2 = regions2.getResult(region); stateValues2 = regions2.getResult(region);
found = stateValues2 != null;
stateValues3 = regions3 != null ? regions3.getResult(region) : null;
found = (stateValues2 != null
&& (regions3 == null || stateValues3 != null));
regions1Index++; regions1Index++;
} }
hasNext = found; hasNext = found;
@ -75,7 +82,7 @@ final class RegionValuesIntersections implements Iterable<RegionIntersection> {
@Override @Override
public RegionIntersection next() { public RegionIntersection next() {
if (hasNext) { if (hasNext) {
RegionIntersection result = new RegionIntersection(region, stateValues1, stateValues2);
RegionIntersection result = new RegionIntersection(region, stateValues1, stateValues2, stateValues3);
findNext(); findNext();
return result; return result;
} else { } else {
@ -91,16 +98,25 @@ final class RegionValuesIntersections implements Iterable<RegionIntersection> {
private RegionValues regions1; private RegionValues regions1;
private RegionValues regions2; private RegionValues regions2;
private RegionValues regions3;
public RegionValuesIntersections(RegionValues regions1, RegionValues regions2) { public RegionValuesIntersections(RegionValues regions1, RegionValues regions2) {
regions1.cosplit(regions2); regions1.cosplit(regions2);
this.regions1 = regions1; this.regions1 = regions1;
this.regions2 = regions2; this.regions2 = regions2;
this.regions3 = null;
}
public RegionValuesIntersections(RegionValues regions1, RegionValues regions2, RegionValues regions3) {
regions1.cosplit(regions2, regions3);
this.regions1 = regions1;
this.regions2 = regions2;
this.regions3 = regions3;
} }
@Override @Override
public Iterator<RegionIntersection> iterator() { public Iterator<RegionIntersection> iterator() {
return new RegionIntersectionOperator(regions1, regions2);
return new RegionIntersectionOperator(regions1, regions2, regions3);
} }
} }
Loading…
Cancel
Save