private static SamplerBoolean createSamplerForProbPathPropertySimple(
      Expression expr, ModulesFile mf) throws PrismException {
    // Negation/parentheses
    if (expr instanceof ExpressionUnaryOp) {
      ExpressionUnaryOp exprUnary = (ExpressionUnaryOp) expr;
      // Parentheses
      if (exprUnary.getOperator() == ExpressionUnaryOp.PARENTH) {
        // Recurse
        return createSamplerForProbPathPropertySimple(exprUnary.getOperand(), mf);
      }
      // Negation
      else if (exprUnary.getOperator() == ExpressionUnaryOp.NOT) {
        // Recurse, then negate meaning
        SamplerBoolean sampler = createSamplerForProbPathPropertySimple(exprUnary.getOperand(), mf);
        sampler.negate();
        return sampler;
      }
    }
    // Temporal operators
    else if (expr instanceof ExpressionTemporal) {
      ExpressionTemporal exprTemp = (ExpressionTemporal) expr;
      // Next
      if (exprTemp.getOperator() == ExpressionTemporal.P_X) {
        return new SamplerNext(exprTemp);
      }
      // Until
      else if (exprTemp.getOperator() == ExpressionTemporal.P_U) {
        if (exprTemp.hasBounds()) {
          if (mf.getModelType().continuousTime()) {
            // Continuous-time bounded until
            return new SamplerBoundedUntilCont(exprTemp);
          } else {
            // Discrete-time bounded until
            return new SamplerBoundedUntilDisc(exprTemp);
          }
        } else {
          // Unbounded until
          return new SamplerUntil(exprTemp);
        }
      }
      // Anything else - convert to until and recurse
      else {
        return createSamplerForProbPathPropertySimple(exprTemp.convertToUntilForm(), mf);
      }
    }

    throw new PrismException("Can't create sampler for property \"" + expr + "\"");
  }
  /** Compute probabilities for a simple, non-LTL path operator. */
  protected StateValues checkProbPathFormulaSimple(
      Model model, Expression expr, boolean min1, boolean min2) throws PrismException {
    StateValues probs = null;

    // Negation/parentheses
    if (expr instanceof ExpressionUnaryOp) {
      ExpressionUnaryOp exprUnary = (ExpressionUnaryOp) expr;
      // Parentheses
      if (exprUnary.getOperator() == ExpressionUnaryOp.PARENTH) {
        // Recurse
        probs = checkProbPathFormulaSimple(model, exprUnary.getOperand(), min1, min2);
      }
      // Negation
      else if (exprUnary.getOperator() == ExpressionUnaryOp.NOT) {
        // Compute, then subtract from 1
        probs = checkProbPathFormulaSimple(model, exprUnary.getOperand(), !min1, !min2);
        probs.timesConstant(-1.0);
        probs.plusConstant(1.0);
      }
    }
    // Temporal operators
    else if (expr instanceof ExpressionTemporal) {
      ExpressionTemporal exprTemp = (ExpressionTemporal) expr;
      // Next
      if (exprTemp.getOperator() == ExpressionTemporal.P_X) {
        probs = checkProbNext(model, exprTemp, min1, min2);
      }
      // Until
      else if (exprTemp.getOperator() == ExpressionTemporal.P_U) {
        if (exprTemp.hasBounds()) {
          probs = checkProbBoundedUntil(model, exprTemp, min1, min2);
        } else {
          probs = checkProbUntil(model, exprTemp, min1, min2);
        }
      }
      // Anything else - convert to until and recurse
      else {
        probs = checkProbPathFormulaSimple(model, exprTemp.convertToUntilForm(), min1, min2);
      }
    }

    if (probs == null) throw new PrismException("Unrecognised path operator in P operator");

    return probs;
  }