diff --git a/prism/src/prism/NonProbModelChecker.java b/prism/src/prism/NonProbModelChecker.java index 8f331cd6..62521795 100644 --- a/prism/src/prism/NonProbModelChecker.java +++ b/prism/src/prism/NonProbModelChecker.java @@ -131,8 +131,7 @@ public class NonProbModelChecker extends StateModelChecker } // Next (EX) if (exprTemp.getOperator() == ExpressionTemporal.P_X) { - // TODO - throw new PrismNotSupportedException("CTL model checking of the E X operator is not yet supported"); + res = checkNext(exprTemp, false); } // Until (EU) else if (exprTemp.getOperator() == ExpressionTemporal.P_U) { @@ -193,16 +192,24 @@ public class NonProbModelChecker extends StateModelChecker } // Next (AX) if (exprTemp.getOperator() == ExpressionTemporal.P_X) { - // TODO - throw new PrismNotSupportedException("CTL model checking of the A X operator is not yet supported"); + res = checkNext(exprTemp, true); } // Until (AU) else if (exprTemp.getOperator() == ExpressionTemporal.P_U) { - throw new PrismNotSupportedException("CTL model checking of the A U operator is not yet supported"); + // Reduce to ENF (i.e. phi1 AU phi2 == !E[!phi2 U !phi1&!phi2] & !EG !phi2) + Expression notPhi1 = Expression.Not(exprTemp.getOperand1().deepCopy()); + Expression notPhi2 = Expression.Not(exprTemp.getOperand2().deepCopy()); + Expression notBoth = Expression.And(notPhi1.deepCopy(), notPhi2.deepCopy()); + Expression lhs = new ExpressionTemporal(ExpressionTemporal.P_U, notPhi2, notBoth); + lhs = Expression.Not(new ExpressionExists(lhs)); + Expression rhs = new ExpressionTemporal(ExpressionTemporal.P_G, null, notPhi2); + rhs = Expression.Not(new ExpressionExists(rhs)); + Expression enf = Expression.And(lhs, rhs); + res = checkExpressionExists(enf); } // Eventually (AF) else if (exprTemp.getOperator() == ExpressionTemporal.P_F) { - // Reduce to EG (AF phi = !AG !phi) + // Reduce to EG (i.e. AF phi == !EG !phi) ExpressionTemporal exprCopy = (ExpressionTemporal) exprTemp.deepCopy(); exprCopy.setOperator(ExpressionTemporal.P_G); exprCopy.setOperand2(Expression.Not(exprCopy.getOperand2())); @@ -221,6 +228,41 @@ public class NonProbModelChecker extends StateModelChecker return res; } + /** + * Model check a CTL exists/forall next (EX/AX) operator. + */ + protected StateValues checkNext(ExpressionTemporal expr, boolean forall) throws PrismException + { + JDDNode b, transRel, pre; + + // Model check operand first + b = checkExpressionDD(expr.getOperand2()); + + // Get transition relation + if (model.getModelType() == ModelType.MDP) { + JDD.Ref(trans01); + transRel = JDD.ThereExists(trans01, ((NondetModel) model).getAllDDNondetVars()); + } else { + JDD.Ref(trans01); + transRel = trans01; + } + + // Find predecessors + JDD.Ref(b); + JDD.Ref(transRel); + if (forall) { + pre = JDD.ForAll(JDD.Implies(transRel, JDD.PermuteVariables(b, allDDRowVars, allDDColVars)), allDDColVars); + } else { + pre = JDD.ThereExists(JDD.And(JDD.PermuteVariables(b, allDDRowVars, allDDColVars), transRel), allDDColVars); + } + + // Derefs + JDD.Deref(b); + JDD.Deref(transRel); + + return new StateValuesMTBDD(pre, model); + } + /** * Model check a CTL exists until (EU) operator. */