class ProtectionLegElement {

  public double[] pvAndSense(final ISDACompliantCreditCurve creditCurve) {
    double t = _knots[0];
    double[] htAndSense = creditCurve.getRTandSensitivity(t, _creditCurveKnot);
    double ht0 = htAndSense[0];
    double rt0 = _rt[0];
    double q0 = Math.exp(-ht0);
    double dqdh0 = -htAndSense[1] * q0;

    double p0 = _p[0];
    double b0 = p0 * q0; // risky discount factor

    double pv = 0.0;
    double pvSense = 0.0;
    for (int i = 1; i < _n; ++i) {
      t = _knots[i];
      htAndSense = creditCurve.getRTandSensitivity(t, _creditCurveKnot);
      final double ht1 = htAndSense[0];
      final double rt1 = _rt[i];
      final double q1 = Math.exp(-ht1);
      final double p1 = _p[i];
      final double b1 = p1 * q1;
      final double dqdh1 = -htAndSense[1] * q1;
      final double dht = ht1 - ht0;
      final double drt = rt1 - rt0;
      final double dhrt = dht + drt;

      // The formula has been modified from ISDA (but is equivalent) to avoid log(exp(x)) and explicitly calculating the time
      // step - it also handles the limit
      double dPV;
      double dPVSense;
      if (Math.abs(dhrt) < 1e-5) {
        final double e = epsilon(-dhrt);
        final double eP = epsilonP(-dhrt);
        dPV = dht * b0 * e;
        final double dPVdq0 = p0 * ((1 + dht) * e - dht * eP);
        final double dPVdq1 = -p0 * q0 / q1 * (e - dht * eP);
        dPVSense = dPVdq0 * dqdh0 + dPVdq1 * dqdh1;
      } else {
        final double w1 = (b0 - b1) / dhrt;
        dPV = dht * w1;
        final double w = drt * w1;
        dPVSense = ((w / q0 + dht * p0) / dhrt) * dqdh0 - ((w / q1 + dht * p1) / dhrt) * dqdh1;
      }

      pv += dPV;
      pvSense += dPVSense;
      ht0 = ht1;
      dqdh0 = dqdh1;
      rt0 = rt1;
      p0 = p1;
      q0 = q1;
      b0 = b1;
    }
    return new double[] {pv, pvSense };
  }

  public  ProtectionLegElement(final double start, final double end, final ISDACompliantYieldCurve yieldCurve, final int creditCurveKnot, final double[] knots);

}