From 57e8229ceb457d1ecab8aa03403e8e1e6fc96360 Mon Sep 17 00:00:00 2001 From: Joachim Klein Date: Fri, 12 Oct 2018 14:26:13 +0200 Subject: [PATCH] imported patch min-max-new-min-max-check.patch --- prism/src/explicit/MinMax.java | 18 +++++++++ prism/src/param/ParamModelChecker.java | 13 +++++-- prism/src/parser/ast/ExpressionProb.java | 25 +++++++----- prism/src/parser/ast/ExpressionQuant.java | 26 +++++++++++++ prism/src/parser/ast/ExpressionReward.java | 12 ++++-- prism/src/parser/ast/ExpressionSS.java | 4 +- prism/src/parser/ast/RelOp.java | 44 ---------------------- prism/src/parser/visitor/CheckValid.java | 4 +- prism/src/prism/MultiObjModelChecker.java | 3 +- prism/src/prism/NondetModelChecker.java | 19 ++++++---- prism/src/prism/OpRelOpBound.java | 15 +++++++- prism/src/prism/ProbModelChecker.java | 4 +- prism/src/pta/PTAModelChecker.java | 4 +- 13 files changed, 114 insertions(+), 77 deletions(-) diff --git a/prism/src/explicit/MinMax.java b/prism/src/explicit/MinMax.java index c38371bf..7ee2ccab 100644 --- a/prism/src/explicit/MinMax.java +++ b/prism/src/explicit/MinMax.java @@ -82,6 +82,24 @@ public class MinMax return neg; } + public String toString() + { + if (min) { + return "min"; + } else { + return "max"; + } + } + + public MinMax clone() + { + MinMax result = new MinMax(); + result.min = min; + result.min1 = min1; + result.min2 = min2; + return result; + } + // Utility methods to create instances of this class public static MinMax blank() diff --git a/prism/src/param/ParamModelChecker.java b/prism/src/param/ParamModelChecker.java index d05f5a62..86640c90 100644 --- a/prism/src/param/ParamModelChecker.java +++ b/prism/src/param/ParamModelChecker.java @@ -91,6 +91,7 @@ import parser.type.TypeInt; import parser.type.TypePathBool; import parser.type.TypePathDouble; import prism.ModelType; +import prism.OpRelOpBound; import prism.PrismComponent; import prism.PrismException; import prism.PrismSettings; @@ -918,7 +919,9 @@ final public class ParamModelChecker extends PrismComponent if (p.compareTo(0) == -1 || p.compareTo(1) == 1) throw new PrismException("Invalid probability bound " + p + " in P operator"); } - min = relOp.isLowerBound() || relOp.isMin(); + // Get info from P operator + OpRelOpBound opInfo = expr.getRelopBoundInfo(constantValues); + min = opInfo.getMinMax(modelType).isMin(); // Compute probabilities if (!expr.getExpression().isSimplePathFormula()) { @@ -1029,7 +1032,9 @@ final public class ParamModelChecker extends PrismComponent if (r.compareTo(0) == -1) throw new PrismException("Invalid reward bound " + r + " in R[] formula"); } - min = relOp.isLowerBound() || relOp.isMin(); + // Get info from R operator + OpRelOpBound opInfo = expr.getRelopBoundInfo(constantValues); + min = opInfo.getMinMax(model.getModelType()).isMin(); ParamRewardStruct rew = constructRewards(model, rewStruct, constantValues); mainLog.println("Building reward structure..."); @@ -1186,7 +1191,9 @@ final public class ParamModelChecker extends PrismComponent if (p.compareTo(0) == -1 || p.compareTo(1) == 1) throw new PrismException("Invalid probability bound " + p + " in P operator"); } - min = relOp.isLowerBound() || relOp.isMin(); + // Get info from SS operator + OpRelOpBound opInfo = expr.getRelopBoundInfo(constantValues); + min = opInfo.getMinMax(modelType).isMin(); // Compute probabilities probs = checkProbSteadyState(model, expr.getExpression(), min, needStates); diff --git a/prism/src/parser/ast/ExpressionProb.java b/prism/src/parser/ast/ExpressionProb.java index 515ce219..5254a0b0 100644 --- a/prism/src/parser/ast/ExpressionProb.java +++ b/prism/src/parser/ast/ExpressionProb.java @@ -86,9 +86,9 @@ public class ExpressionProb extends ExpressionQuant double boundVal = getBound().evaluateDouble(constantValues); if (boundVal < 0 || boundVal > 1) throw new PrismLangException("Invalid probability bound " + boundVal + " in P operator"); - return new OpRelOpBound("P", getRelOp(), boundVal); + return new OpRelOpBound("P", minMax, getRelOp(), boundVal); } else { - return new OpRelOpBound("P", getRelOp(), null); + return new OpRelOpBound("P", minMax, getRelOp(), null); } } @@ -123,12 +123,16 @@ public class ExpressionProb extends ExpressionQuant { if (getBound() != null) return "Result"; - else if (getRelOp() == RelOp.MIN) - return "Minimum probability"; - else if (getRelOp() == RelOp.MAX) - return "Maximum probability"; - else - return "Probability"; + else if (getRelOp() == RelOp.EQ) { + if (minMax != null) { + if (minMax.isMin()) { + return "Minimum probability"; + } else { + return "Maximum probability"; + } + } + } + return "Probability"; } @Override @@ -150,6 +154,7 @@ public class ExpressionProb extends ExpressionQuant { ExpressionProb expr = new ExpressionProb(); expr.setExpression(getExpression() == null ? null : getExpression().deepCopy()); + expr.setMinMax(minMax != null ? minMax.clone() : null); expr.setRelOp(getRelOp()); expr.setBound(getBound() == null ? null : getBound().deepCopy()); expr.setFilter(getFilter() == null ? null : (Filter)getFilter().deepCopy()); @@ -165,7 +170,9 @@ public class ExpressionProb extends ExpressionQuant { String s = ""; - s += "P" + getModifierString() + getRelOp(); + s += "P" + getModifierString(); + s += (minMax != null ? minMax : ""); + s+= getRelOp(); s += (getBound() == null) ? "?" : getBound().toString(); s += " [ " + getExpression(); if (getFilter() != null) diff --git a/prism/src/parser/ast/ExpressionQuant.java b/prism/src/parser/ast/ExpressionQuant.java index 20d2c904..8d6056e3 100644 --- a/prism/src/parser/ast/ExpressionQuant.java +++ b/prism/src/parser/ast/ExpressionQuant.java @@ -26,6 +26,7 @@ package parser.ast; +import explicit.MinMax; import parser.Values; import prism.OpRelOpBound; import prism.PrismException; @@ -38,6 +39,8 @@ public abstract class ExpressionQuant extends Expression { /** Optional "modifier" to specify variants of the P/R/S operator */ protected String modifier = null; + /** The attached min/max operator, if it exists */ + protected MinMax minMax = null; /** The attached relational operator (e.g. "<" in "P<0.1"). */ protected RelOp relOp = null; /** The attached (probability/reward) bound, as an expression (e.g. "p" in "P<p"). Null if absent (e.g. "P=?"). */ @@ -58,6 +61,23 @@ public abstract class ExpressionQuant extends Expression this.modifier = modifier; } + public void setMinMax(MinMax minMax) + { + this.minMax = minMax; + } + + /** Set the attached min/max operator */ + public void setMinMax(String minMaxString) throws PrismException + { + if (minMaxString.equals("min")) { + minMax = MinMax.min(); + } else if (minMaxString.equals("max")) { + minMax = MinMax.max(); + } else { + throw new PrismException("Min/Max has to be either min or max"); + } + } + /** * Set the attached relational operator (e.g. "<" in "P<0.1"). * Uses the enum {@link RelOp}. For example: {@code setRelOp(RelOp.GT);} @@ -119,6 +139,12 @@ public abstract class ExpressionQuant extends Expression return modifier == null ? "" : "(" + modifier + ")"; } + /** Get the optional MinMax operator */ + public MinMax getMinMax() + { + return minMax; + } + /** * Get the attached relational operator (e.g. "<" in "P<0.1"), as a {@link RelOp}. */ diff --git a/prism/src/parser/ast/ExpressionReward.java b/prism/src/parser/ast/ExpressionReward.java index 9a5b8251..788ab3eb 100644 --- a/prism/src/parser/ast/ExpressionReward.java +++ b/prism/src/parser/ast/ExpressionReward.java @@ -197,9 +197,9 @@ public class ExpressionReward extends ExpressionQuant { if (getBound() != null) { double boundValue = getBound().evaluateDouble(constantValues); - return new OpRelOpBound("R", getRelOp(), boundValue); + return new OpRelOpBound("R", minMax, getRelOp(), boundValue); } else { - return new OpRelOpBound("R", getRelOp(), null); + return new OpRelOpBound("R", minMax, getRelOp(), null); } } @@ -246,8 +246,10 @@ public class ExpressionReward extends ExpressionQuant // For R=? properties, use name of reward structure where applicable if (getBound() == null) { String s = "E"; - if (getRelOp() == RelOp.MIN) s = "Minimum e"; - else if (getRelOp() == RelOp.MAX) s = "Maximum e"; + if (minMax != null) { + if (minMax.isMin()) s = "Minimum e"; + else s = "Maximum e"; + } else s = "E"; if (rewardStructIndex instanceof String) { if (rewardStructIndexDiv instanceof String) @@ -287,6 +289,7 @@ public class ExpressionReward extends ExpressionQuant ExpressionReward expr = new ExpressionReward(); expr.setExpression(getExpression() == null ? null : getExpression().deepCopy()); expr.setRelOp(getRelOp()); + expr.setMinMax(minMax == null ? null : minMax.clone() ); expr.setBound(getBound() == null ? null : getBound().deepCopy()); if (rewardStructIndex != null && rewardStructIndex instanceof Expression) expr.setRewardStructIndex(((Expression)rewardStructIndex).deepCopy()); else expr.setRewardStructIndex(rewardStructIndex); @@ -315,6 +318,7 @@ public class ExpressionReward extends ExpressionQuant else if (rewardStructIndexDiv instanceof String) s += "{\""+rewardStructIndexDiv+"\"}"; } } + s += (getMinMax()==null) ? "" : getMinMax(); s += getRelOp(); s += (getBound()==null) ? "?" : getBound().toString(); s += " [ " + getExpression(); diff --git a/prism/src/parser/ast/ExpressionSS.java b/prism/src/parser/ast/ExpressionSS.java index 5a3bd4b3..7d224d20 100644 --- a/prism/src/parser/ast/ExpressionSS.java +++ b/prism/src/parser/ast/ExpressionSS.java @@ -80,9 +80,9 @@ public class ExpressionSS extends ExpressionQuant double boundValue = getBound().evaluateDouble(constantValues); if (boundValue < 0 || boundValue > 1) throw new PrismException("Invalid probability bound " + boundValue + " in P operator"); - return new OpRelOpBound("S", getRelOp(), boundValue); + return new OpRelOpBound("S", minMax, getRelOp(), boundValue); } else { - return new OpRelOpBound("S", getRelOp(), null); + return new OpRelOpBound("S", minMax, getRelOp(), null); } } diff --git a/prism/src/parser/ast/RelOp.java b/prism/src/parser/ast/RelOp.java index b38897cd..4c112798 100644 --- a/prism/src/parser/ast/RelOp.java +++ b/prism/src/parser/ast/RelOp.java @@ -39,19 +39,6 @@ public enum RelOp return (keepStrictness ? LEQ : LT); } }, - MIN("min=") { - @Override - public boolean isMin() - { - return true; - } - - @Override - public RelOp negate(boolean keepStrictness) throws PrismLangException - { - return MAX; - } - }, LT("<") { @Override public boolean isUpperBound() @@ -84,19 +71,6 @@ public enum RelOp return (keepStrictness ? GEQ : GT); } }, - MAX("max=") { - @Override - public boolean isMax() - { - return true; - } - - @Override - public RelOp negate(boolean keepStrictness) throws PrismLangException - { - return MIN; - } - }, EQ("=") { @Override public RelOp negate(boolean keepStrictness) throws PrismLangException @@ -120,7 +94,6 @@ public enum RelOp /** * Returns true if this corresponds to a lower bound (i.e. >, >=). - * NB: "min=?" does not return true for this. */ public boolean isLowerBound() { @@ -129,7 +102,6 @@ public enum RelOp /** * Returns true if this corresponds to an upper bound (i.e. <, <=). - * NB: "max=?" does not return true for this. */ public boolean isUpperBound() { @@ -144,22 +116,6 @@ public enum RelOp return false; } - /** - * Returns true if this corresponds to minimum (min=?). - */ - public boolean isMin() - { - return false; - } - - /** - * Returns true if this corresponds to maximum (max=?). - */ - public boolean isMax() - { - return false; - } - /** * Returns the negated form of this operator. *
diff --git a/prism/src/parser/visitor/CheckValid.java b/prism/src/parser/visitor/CheckValid.java index a5adb299..be07a016 100644 --- a/prism/src/parser/visitor/CheckValid.java +++ b/prism/src/parser/visitor/CheckValid.java @@ -99,13 +99,13 @@ public class CheckValid extends ASTTraverse public void visitPost(ExpressionProb e) throws PrismLangException { - if (modelType.nondeterministic() && e.getRelOp() == RelOp.EQ) + if (modelType.nondeterministic() && e.getRelOp() == RelOp.EQ && e.getMinMax() == null) throw new PrismLangException("Can't use \"P=?\" for nondeterministic models; use \"Pmin=?\" or \"Pmax=?\""); } public void visitPost(ExpressionReward e) throws PrismLangException { - if (modelType.nondeterministic() && e.getRelOp() == RelOp.EQ) + if (modelType.nondeterministic() && e.getRelOp() == RelOp.EQ && e.getMinMax() == null) throw new PrismLangException("Can't use \"R=?\" for nondeterministic models; use \"Rmin=?\" or \"Rmax=?\""); if (e.getRewardStructIndexDiv() != null) throw new PrismLangException("No support for ratio reward objectives yet"); diff --git a/prism/src/prism/MultiObjModelChecker.java b/prism/src/prism/MultiObjModelChecker.java index b06b5ac7..823dae6e 100644 --- a/prism/src/prism/MultiObjModelChecker.java +++ b/prism/src/prism/MultiObjModelChecker.java @@ -42,6 +42,7 @@ import jdd.JDDVars; import mtbdd.PrismMTBDD; import parser.ast.Expression; import parser.ast.RelOp; +import explicit.MinMax; import sparse.NDSparseMatrix; import sparse.PrismSparse; import acceptance.AcceptanceRabin; @@ -271,7 +272,7 @@ public class MultiObjModelChecker extends PrismComponent opsAndBounds.getProbStepBound(i), i); } } - tmpOpsAndBounds.add(new OpRelOpBound("R", RelOp.MAX, -1.0), Operator.R_MAX, -1.0, -1, opsAndBounds.probSize()); + tmpOpsAndBounds.add(new OpRelOpBound("R", MinMax.max(), RelOp.EQ, -1.0), Operator.R_MAX, -1.0, -1, opsAndBounds.probSize()); ArrayList tmprewards = new ArrayList(1); tmprewards.add(rtarget); diff --git a/prism/src/prism/NondetModelChecker.java b/prism/src/prism/NondetModelChecker.java index 8788d971..20f299c6 100644 --- a/prism/src/prism/NondetModelChecker.java +++ b/prism/src/prism/NondetModelChecker.java @@ -838,16 +838,21 @@ public class NondetModelChecker extends NonProbModelChecker if (relOp.isStrict()) { throw new PrismException("Multi-objective properties can not use strict inequalities on P/R operators"); } - Operator op; - if (relOp == RelOp.MAX) { - op = (exprProb != null) ? Operator.P_MAX : Operator.R_MAX; + Operator op = null; + if (relOp == RelOp.EQ) { + if (exprQuant.getMinMax() != null) { + if (exprQuant.getMinMax().isMax()) { + op = (exprProb != null) ? Operator.P_MAX : Operator.R_MAX; + } else { + op = (exprProb != null) ? Operator.P_MIN : Operator.R_MIN; + } + } } else if (relOp == RelOp.GEQ) { op = (exprProb != null) ? Operator.P_GE : Operator.R_GE; - } else if (relOp == RelOp.MIN) { - op = (exprProb != null) ? Operator.P_MIN : Operator.R_MIN; } else if (relOp == RelOp.LEQ) { op = (exprProb != null) ? Operator.P_LE : Operator.R_LE; - } else { + } + if (op == null) { throw new PrismException("Multi-objective properties can only contain P/R operators with max/min=? or lower/upper probability bounds"); } // Find bound @@ -876,7 +881,7 @@ public class NondetModelChecker extends NonProbModelChecker for (JDDNode set : tmpecs) acceptingStates = JDD.Or(acceptingStates, set); targetDDs.add(acceptingStates); - OpRelOpBound opInfo = new OpRelOpBound("P", RelOp.GEQ, 0.0); + OpRelOpBound opInfo = new OpRelOpBound("P", null, RelOp.GEQ, 0.0); opsAndBounds.add(opInfo, Operator.P_GE, 0.0, -1, -1); } diff --git a/prism/src/prism/OpRelOpBound.java b/prism/src/prism/OpRelOpBound.java index b22398ae..fb4b14b6 100644 --- a/prism/src/prism/OpRelOpBound.java +++ b/prism/src/prism/OpRelOpBound.java @@ -36,12 +36,14 @@ public class OpRelOpBound { protected String op; protected RelOp relOp; + protected MinMax minMax; protected boolean numeric; protected double bound; - public OpRelOpBound(String op, RelOp relOp, Double boundObject) + public OpRelOpBound(String op, MinMax minMax, RelOp relOp, Double boundObject) { this.op = op; + this.minMax = minMax; this.relOp = relOp; numeric = (boundObject == null); if (boundObject != null) @@ -73,6 +75,11 @@ public class OpRelOpBound return bound; } + public boolean hasExplicitMinMax() + { + return minMax != null; + } + public boolean isQualitative() { return !isNumeric() && op.equals("P") && (bound == 0 || bound == 1); @@ -111,7 +118,12 @@ public class OpRelOpBound public MinMax getMinMax(ModelType modelType, boolean forAll) throws PrismLangException { + if (this.minMax != null) { + return this.minMax; + } + MinMax minMax = MinMax.blank(); + if (modelType.nondeterministic()) { if (!(modelType == ModelType.MDP || modelType == ModelType.POMDP || modelType == ModelType.CTMDP)) { throw new PrismLangException("Don't know how to model check " + getTypeOfOperator() + " properties for " + modelType + "s"); @@ -120,7 +132,6 @@ public class OpRelOpBound if (relOp == RelOp.EQ) { throw new PrismLangException("Can't use \"" + op + "=?\" for nondeterministic models; use e.g. \"" + op + "min=?\" or \"" + op + "max=?\""); } - minMax = relOp.isMin() ? MinMax.min() : MinMax.max(); } else { if (forAll) { minMax = (relOp.isLowerBound() ) ? MinMax.min() : MinMax.max(); diff --git a/prism/src/prism/ProbModelChecker.java b/prism/src/prism/ProbModelChecker.java index 4e775e73..8017a2fa 100644 --- a/prism/src/prism/ProbModelChecker.java +++ b/prism/src/prism/ProbModelChecker.java @@ -187,7 +187,7 @@ public class ProbModelChecker extends NonProbModelChecker } // Print a warning if Pmin/Pmax used - if (opInfo.getRelOp() == RelOp.MIN || opInfo.getRelOp() == RelOp.MAX) { + if (opInfo.hasExplicitMinMax()) { mainLog.printWarning("\"Pmin=?\" and \"Pmax=?\" operators are identical to \"P=?\" for DTMCs/CTMCs"); } @@ -235,7 +235,7 @@ public class ProbModelChecker extends NonProbModelChecker JDDNode transRewards = getTransitionRewardsByIndexObject(rs, model, constantValues); // Print a warning if Rmin/Rmax used - if (opInfo.getRelOp() == RelOp.MIN || opInfo.getRelOp() == RelOp.MAX) { + if (opInfo.hasExplicitMinMax()) { mainLog.printWarning("\"Rmin=?\" and \"Rmax=?\" operators are identical to \"R=?\" for DTMCs/CTMCs"); } diff --git a/prism/src/pta/PTAModelChecker.java b/prism/src/pta/PTAModelChecker.java index 9e31d670..cc2a80fe 100644 --- a/prism/src/pta/PTAModelChecker.java +++ b/prism/src/pta/PTAModelChecker.java @@ -194,7 +194,9 @@ public class PTAModelChecker extends PrismComponent if (expr.getProb() != null) { throw new PrismException("PTA model checking currently only supports Pmin=? and Pmax=? properties (try the digital clocks engine instead)"); } - min = relOp.isLowerBound() || relOp.isMin(); + // Get info from P operator + OpRelOpBound opInfo = expr.getRelopBoundInfo(constantValues); + min = opInfo.getMinMax(ModelType.PTA).isMin(); // Check this is a F path property (only case allowed at the moment) if (!(expr.getExpression() instanceof ExpressionTemporal))