Browse Source

Property.checkAgainstExpectedResultString: handle complex expressions

Instead of before, where only
// RESULT: integer
or
// RESULT: numerator/denominator
were allowed for result expressions, we now support arbitrary expressions
over the model/property parameters, e.g.,

// RESULT: 4.3*floor(q*3)

Caveat: Currently, there can be no whitespace in the expression...

Additionally, when model checking in exact mode, the expected value is
also computed using Expression.evaluateExact.



git-svn-id: https://www.prismmodelchecker.org/svn/prism/prism/trunk@11557 bbc10eb1-c90d-0410-af57-cb519fbb1720
master
Joachim Klein 10 years ago
parent
commit
e1105ab74a
  1. 73
      prism/src/parser/ast/Property.java

73
prism/src/parser/ast/Property.java

@ -41,6 +41,7 @@ import prism.PrismLangException;
import prism.PrismNotSupportedException; import prism.PrismNotSupportedException;
import prism.PrismUtils; import prism.PrismUtils;
import prism.Point; import prism.Point;
import prism.Prism;
import prism.TileList; import prism.TileList;
/** /**
@ -140,7 +141,7 @@ public class Property extends ASTElement
public boolean checkAgainstExpectedResult(Object result, Values constValues) throws PrismException public boolean checkAgainstExpectedResult(Object result, Values constValues) throws PrismException
{ {
String strExpected = getExpectedResultString(constValues); String strExpected = getExpectedResultString(constValues);
return checkAgainstExpectedResultString(strExpected, result);
return checkAgainstExpectedResultString(strExpected, constValues, result);
} }
/** /**
@ -254,7 +255,7 @@ public class Property extends ASTElement
* @param result The actual result * @param result The actual result
* @return Whether or not the check was performed * @return Whether or not the check was performed
*/ */
private boolean checkAgainstExpectedResultString(String strExpected, Object result) throws PrismException
private boolean checkAgainstExpectedResultString(String strExpected, Values constValues, Object result) throws PrismException
{ {
// Check for special "don't case" case // Check for special "don't case" case
if (strExpected.equals("?")) { if (strExpected.equals("?")) {
@ -295,30 +296,53 @@ public class Property extends ASTElement
if (type instanceof TypeBool) { if (type instanceof TypeBool) {
// Parse expected result // Parse expected result
boolean boolExp; boolean boolExp;
boolean simple = true; // is the expectation string a simple expression?
strExpected = strExpected.toLowerCase(); strExpected = strExpected.toLowerCase();
if (strExpected.equals("true")) if (strExpected.equals("true"))
boolExp = true; boolExp = true;
else if (strExpected.equals("false")) else if (strExpected.equals("false"))
boolExp = false; boolExp = false;
else
throw new PrismException("Invalid RESULT specification \"" + strExpected + "\" for boolean-valued property");
else {
// complex expression?
Expression expectedExpr = null;
try {
expectedExpr = Prism.parseSingleExpressionString(strExpected);
expectedExpr.findAllConstants(new ConstantList(constValues));
expectedExpr.typeCheck();
boolExp = expectedExpr.evaluateBoolean(constValues);
simple = false; // complex expression
} catch (PrismLangException e2) {
throw new PrismException("Invalid RESULT specification \"" + strExpected + "\" for boolean-valued property: " + e2.getMessage());
}
}
// Parse actual result // Parse actual result
boolean boolRes; boolean boolRes;
if (!(result instanceof Boolean)) if (!(result instanceof Boolean))
throw new PrismException("Result is wrong type for (boolean-valued) property"); throw new PrismException("Result is wrong type for (boolean-valued) property");
boolRes = ((Boolean) result).booleanValue(); boolRes = ((Boolean) result).booleanValue();
if (boolRes != boolExp) if (boolRes != boolExp)
throw new PrismException("Wrong result (expected " + boolExp + ", got " + boolRes + ")");
throw new PrismException("Wrong result (expected " + (simple ? "" : strExpected + " = ") + boolExp + ", got " + boolRes + ")");
} }
// Integer-valued properties // Integer-valued properties
else if (type instanceof TypeInt) { else if (type instanceof TypeInt) {
// Parse expected result // Parse expected result
int intExp; int intExp;
boolean simple = true; // is the expectation string a simple expression?
try { try {
intExp = Integer.parseInt(strExpected); intExp = Integer.parseInt(strExpected);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new PrismException("Invalid RESULT specification \"" + strExpected + "\" for integer-valued property");
// complex expression?
Expression expectedExpr = null;
try {
expectedExpr = Prism.parseSingleExpressionString(strExpected);
expectedExpr.findAllConstants(new ConstantList(constValues));
expectedExpr.typeCheck();
intExp = expectedExpr.evaluateInt(constValues);
simple = false; // complex expression
} catch (PrismLangException e2) {
throw new PrismException("Invalid RESULT specification \"" + strExpected + "\" for integer-valued property: " + e2.getMessage());
}
} }
// Parse actual result // Parse actual result
int intRes; int intRes;
@ -326,13 +350,14 @@ public class Property extends ASTElement
throw new PrismException("Result is wrong type for (integer-valued) property"); throw new PrismException("Result is wrong type for (integer-valued) property");
intRes = ((Integer) result).intValue(); intRes = ((Integer) result).intValue();
if (intRes != intExp) if (intRes != intExp)
throw new PrismException("Wrong result (expected " + intExp + ", got " +intRes + ")");
throw new PrismException("Wrong result (expected " + (simple ? "" : strExpected + " = ") + intExp + ", got " +intRes + ")");
} }
// Double-valued properties (non-exact mode) // Double-valued properties (non-exact mode)
else if (type instanceof TypeDouble && !(result instanceof BigRational)) { else if (type instanceof TypeDouble && !(result instanceof BigRational)) {
// Parse expected result // Parse expected result
double doubleExp; double doubleExp;
boolean simple = true; // is the expectation string a simple expression?
try { try {
// See if it's NaN // See if it's NaN
if (strExpected.equals("NaN")) { if (strExpected.equals("NaN")) {
@ -343,13 +368,24 @@ public class Property extends ASTElement
int numer = Integer.parseInt(strExpected.substring(0, strExpected.indexOf('/'))); int numer = Integer.parseInt(strExpected.substring(0, strExpected.indexOf('/')));
int denom = Integer.parseInt(strExpected.substring(strExpected.indexOf('/') + 1)); int denom = Integer.parseInt(strExpected.substring(strExpected.indexOf('/') + 1));
doubleExp = ((double) numer) / denom; doubleExp = ((double) numer) / denom;
simple = false; // complex expression
} }
// Otherwise, just a double
// Otherwise, see if it's just a double
else { else {
doubleExp = Double.parseDouble(strExpected); doubleExp = Double.parseDouble(strExpected);
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new PrismException("Invalid RESULT specification \"" + strExpected + "\" for double-valued property");
// complex expression?
Expression expectedExpr = null;
try {
expectedExpr = Prism.parseSingleExpressionString(strExpected);
expectedExpr.findAllConstants(new ConstantList(constValues));
expectedExpr.typeCheck();
doubleExp = expectedExpr.evaluateDouble(constValues);
simple = false; // complex expression
} catch (PrismLangException e2) {
throw new PrismException("Invalid RESULT specification \"" + strExpected + "\" for double-valued property: " + e2.getMessage());
}
} }
// Parse actual result // Parse actual result
if (!(result instanceof Double)) if (!(result instanceof Double))
@ -358,10 +394,10 @@ public class Property extends ASTElement
// Compare results // Compare results
if (Double.isNaN(doubleRes)) { if (Double.isNaN(doubleRes)) {
if (!Double.isNaN(doubleExp)) if (!Double.isNaN(doubleExp))
throw new PrismException("Wrong result (expected " + doubleExp + ", got NaN)");
throw new PrismException("Wrong result (expected " + (simple ? "" : strExpected + " = ") + doubleExp + ", got NaN)");
} else { } else {
if (!PrismUtils.doublesAreCloseRel(doubleExp, doubleRes, 1e-5)) if (!PrismUtils.doublesAreCloseRel(doubleExp, doubleRes, 1e-5))
throw new PrismException("Wrong result (expected " + doubleExp + ", got " + doubleRes + ")");
throw new PrismException("Wrong result (expected " + (simple ? "" : strExpected + " = ") + doubleExp + ", got " + doubleRes + ")");
} }
} }
@ -370,6 +406,7 @@ public class Property extends ASTElement
// Parse expected result // Parse expected result
BigRational rationalRes = (BigRational) result; BigRational rationalRes = (BigRational) result;
BigRational rationalExp = null; BigRational rationalExp = null;
boolean simple = true; // is the expectation string a simple expression?
try { try {
// See if it's NaN // See if it's NaN
if (strExpected.equals("NaN")) { if (strExpected.equals("NaN")) {
@ -381,11 +418,21 @@ public class Property extends ASTElement
rationalExp = new BigRational(strExpected); rationalExp = new BigRational(strExpected);
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new PrismException("Invalid RESULT specification \"" + strExpected + "\" for rational-valued property");
// complex expression?
Expression expectedExpr = null;
try {
expectedExpr = Prism.parseSingleExpressionString(strExpected);
expectedExpr.findAllConstants(new ConstantList(constValues));
expectedExpr.typeCheck();
rationalExp = expectedExpr.evaluateExact(constValues);
simple = false; // complex expression
} catch (PrismLangException e2) {
throw new PrismException("Invalid RESULT specification \"" + strExpected + "\" for rational-valued property: " + e2.getMessage());
}
} }
// Compare results // Compare results
if (!rationalRes.equals(rationalExp)) if (!rationalRes.equals(rationalExp))
throw new PrismException("Wrong result (expected " + rationalExp + ", got " + rationalRes + ")");
throw new PrismException("Wrong result (expected " + (simple ? "" : strExpected + " = ") + rationalExp + ", got " + rationalRes + ")");
} }
else if (type instanceof TypeVoid && result instanceof TileList) { //Pareto curve else if (type instanceof TypeVoid && result instanceof TileList) { //Pareto curve

Loading…
Cancel
Save