@Override
  public double evaluate(final double dblLeftSlope) throws java.lang.Exception {
    if (null == _ssb || !_ssb.calibStartingSegment(dblLeftSlope) || !_ssb.calibSegmentSequence(1))
      throw new java.lang.Exception(
          "CalibratableMultiSegmentSequence::evaluate => cannot set up segments!");

    org.drip.spline.stretch.BoundarySettings bs = _ssb.getCalibrationBoundaryCondition();

    int iBC = bs.boundaryCondition();

    if (org.drip.spline.stretch.BoundarySettings.BOUNDARY_CONDITION_NATURAL == iBC)
      return calcRightEdgeDerivative(bs.rightDerivOrder());

    if (org.drip.spline.stretch.BoundarySettings.BOUNDARY_CONDITION_FINANCIAL == iBC)
      return calcRightEdgeDerivative(bs.rightDerivOrder());

    if (org.drip.spline.stretch.BoundarySettings.BOUNDARY_CONDITION_NOT_A_KNOT == iBC)
      return calcRightEdgeDerivative(bs.rightDerivOrder())
          - calcLeftEdgeDerivative(bs.leftDerivOrder());

    throw new java.lang.Exception(
        "CalibratableMultiSegmentSequence::evaluate => Boundary Condition " + iBC + " unknown");
  }
  /**
   * Construct NonlinearDiscountFactorDiscountCurve instance from an array of dates and forward
   * rates
   *
   * @param dtStart Epoch Date
   * @param strCurrency Currency
   * @param collatParams Collateralization Parameters
   * @param adblDate Array of Dates
   * @param adblRate Array of Forward Rates
   * @throws java.lang.Exception Thrown if the curve cannot be created
   */
  public NonlinearDiscountFactorDiscountCurve(
      final org.drip.analytics.date.JulianDate dtStart,
      final java.lang.String strCurrency,
      final org.drip.param.valuation.CollateralizationParams collatParams,
      final double[] adblDate,
      final double[] adblRate)
      throws java.lang.Exception {
    super(dtStart.julian(), strCurrency, collatParams);

    if (null == adblDate
        || 0 == adblDate.length
        || null == adblRate
        || adblDate.length != adblRate.length
        || null == dtStart)
      throw new java.lang.Exception("NonlinearDiscountFactorDiscountCurve ctr: Invalid inputs");

    _dblEpochDate = dtStart.julian();

    org.drip.spline.params.SegmentCustomBuilderControl sbp =
        new org.drip.spline.params.SegmentCustomBuilderControl(
            org.drip.spline.stretch.MultiSegmentSequenceBuilder.BASIS_SPLINE_POLYNOMIAL,
            new org.drip.spline.basis.PolynomialFunctionSetParams(2),
            org.drip.spline.params.SegmentInelasticDesignControl.Create(0, 2),
            null,
            null);

    int iNumSegment = adblDate.length;
    _adblDate = new double[iNumSegment];
    double[] adblDF = new double[iNumSegment];
    org.drip.spline.params.SegmentCustomBuilderControl[] aSBP =
        new org.drip.spline.params.SegmentCustomBuilderControl[adblDate.length - 1];

    for (int i = 0; i < iNumSegment; ++i) {
      _adblDate[i] = adblDate[i];

      if (0 == i)
        adblDF[0] = java.lang.Math.exp(adblRate[0] * (_dblEpochDate - _adblDate[0]) / 365.25);
      else {
        aSBP[i - 1] = sbp;

        adblDF[i] =
            java.lang.Math.exp(adblRate[i] * (_adblDate[i - 1] - _adblDate[i]) / 365.25)
                * adblDF[i - 1];
      }
    }

    _dblLeftFlatForwardRate =
        -365.25 * java.lang.Math.log(adblDF[0]) / (_adblDate[0] - _dblEpochDate);

    _dblRightFlatForwardRate =
        -365.25
            * java.lang.Math.log(adblDF[iNumSegment - 1])
            / (_adblDate[iNumSegment - 1] - _dblEpochDate);

    _msr =
        org.drip.spline.stretch.MultiSegmentSequenceBuilder.CreateCalibratedStretchEstimator(
            "POLY_SPLINE_DF_REGIME",
            adblDate,
            adblDF,
            aSBP,
            null,
            org.drip.spline.stretch.BoundarySettings.NaturalStandard(),
            org.drip.spline.stretch.MultiSegmentSequence.CALIBRATE);
  }