public final String getPerformanceSuggestion() {

    double prob = MCMCOperator.Utils.getAcceptanceProbability(this);
    double targetProb = getTargetAcceptanceProbability();
    double sf = OperatorUtils.optimizeScaleFactor(scaleFactor, prob, targetProb);
    dr.util.NumberFormatter formatter = new dr.util.NumberFormatter(5);
    if (prob < getMinimumGoodAcceptanceLevel()) {
      return "Try setting scaleFactor to about " + formatter.format(sf);
    } else if (prob > getMaximumGoodAcceptanceLevel()) {
      return "Try setting scaleFactor to about " + formatter.format(sf);
    } else return "";
  }
  /**
   * Updates the proposal parameter, based on the target acceptance probability This method relies
   * on the proposal parameter being a decreasing function of acceptance probability.
   *
   * @param op The operator
   * @param logr
   */
  private void coerceAcceptanceProbability(CoercableMCMCOperator op, double logr) {

    if (isCoercable(op)) {
      final double p = op.getCoercableParameter();

      final double i = schedule.getOptimizationTransform(MCMCOperator.Utils.getOperationCount(op));

      final double target = op.getTargetAcceptanceProbability();

      final double newp = p + ((1.0 / (i + 1.0)) * (Math.exp(logr) - target));

      if (newp > -Double.MAX_VALUE && newp < Double.MAX_VALUE) {
        op.setCoercableParameter(newp);
      }
    }
  }