//-------------------------------------------------------------------------

        /**
         * The sensitivity of the PV of a CDS to the zero hazard rates at the knots of the credit curve.
         *
         * @param cds  the CDS
         * @param coupon  the coupon
         * @param creditCurve  the credit Curve
         * @param yieldCurve  the yield curve
         * @return vector of sensitivities
         */
        public double[] getCurveSensitivities(
            CDS cds,
            double coupon,
            PiecewiseconstantHazardRate creditCurve,
            YieldTermStructure yieldCurve)
        {
            int n = creditCurve.getNumberOfKnots();

            double[] CurveSen = new double[n];
            for (int i = 0; i < n; i++)
            {
                CurveSen[i] = _pricer.pvCreditSensitivity(cds, yieldCurve, creditCurve, coupon, i);
            }
            return(CurveSen);
        }
        /**
         * The sensitivity of a set of CDSs to the zero hazard rates at the knots of the credit curve.
         * The element (i,j) is the sensitivity of the PV of the jth CDS to the ith knot.
         *
         * @param cds  the set of CDSs
         * @param coupons  the coupons of the CDSs
         * @param creditCurve  the credit Curve
         * @param yieldCurve  the yield curve
         * @return matrix of sensitivities
         */
        public double[,] getCurveSensitivities(
            CDS[] cds,
            double[] coupons,
            PiecewiseconstantHazardRate creditCurve,
            YieldTermStructure yieldCurve)
        {
            int nCDS   = cds.Length;
            int nKnots = creditCurve.getNumberOfKnots();

            double[,] sense = new double[nKnots, nCDS];

            for (int i = 0; i < nCDS; i++)
            {
                for (int j = 0; j < nKnots; j++)
                {
                    sense[j, i] = _pricer.pvCreditSensitivity(cds[i], yieldCurve, creditCurve, coupons[i], j);
                }
            }
            return(sense);
        }
        /**
         * The sensitivity of the PV of the protection leg to the zero rate of a given node (knot) of the yield curve.
         *
         * @param cds  the analytic description of a CDS traded at a certain time
         * @param yieldCurve  the yield (or discount) curve
         * @param creditCurve  the credit (or survival) curve
         * @param yieldCurveNode  the yield curve node
         * @return the sensitivity (on a unit notional)
         */
        public double protectionLegYieldSensitivity(
            CDS cds,
            YieldTermStructure yieldCurve,
            PiecewiseconstantHazardRate creditCurve,
            int yieldCurveNode)
        {
            if ((yieldCurveNode != 0 && cds.getProtectionEnd() <= yieldCurve.t[yieldCurveNode - 1]) ||
                (yieldCurveNode != creditCurve.getNumberOfKnots() - 1 &&
                 cds.getEffectiveProtectionStart() >= yieldCurve.t[yieldCurveNode + 1]))
            {
                return(0.0); // can't have any sensitivity in this case
            }
            if (cds.getProtectionEnd() <= 0.0)
            { //short cut already expired CDSs
                return(0.0);
            }

            double[] integrationSchedule = DoublesScheduleGenerator.getIntegrationsPoints(
                cds.getEffectiveProtectionStart(), cds.getProtectionEnd(), yieldCurve, creditCurve);

            double t       = integrationSchedule[0];
            double ht0     = creditCurve.getRT_(t);
            double rt0     = yieldCurve.getRT_(t);
            double dpdr0   = yieldCurve.getSingleNodeDiscountFactorSensitivity(t, yieldCurveNode);
            double q0      = Math.Exp(-ht0);
            double p0      = Math.Exp(-rt0);
            double pvSense = 0.0;
            int    n       = integrationSchedule.Length;

            for (int i = 1; i < n; ++i)
            {
                t = integrationSchedule[i];
                double ht1   = creditCurve.getRT_(t);
                double dpdr1 = yieldCurve.getSingleNodeDiscountFactorSensitivity(t, yieldCurveNode);
                double rt1   = yieldCurve.getRT_(t);
                double q1    = Math.Exp(-ht1);
                double p1    = Math.Exp(-rt1);

                if (dpdr0 == 0.0 && dpdr1 == 0.0)
                {
                    ht0 = ht1;
                    rt0 = rt1;
                    p0  = p1;
                    q0  = q1;
                    continue;
                }

                double hBar  = ht1 - ht0;
                double fBar  = rt1 - rt0;
                double fhBar = hBar + fBar;

                double dPVSense;
                double e      = Maths.Epsilon.epsilon(-fhBar);
                double eP     = Maths.Epsilon.epsilonP(-fhBar);
                double dPVdp0 = q0 * hBar * (e - eP);
                double dPVdp1 = hBar * p0 * q0 / p1 * eP;
                dPVSense = dPVdp0 * dpdr0 + dPVdp1 * dpdr1;

                pvSense += dPVSense;

                ht0   = ht1;
                dpdr0 = dpdr1;
                rt0   = rt1;
                p0    = p1;
                q0    = q1;
            }
            pvSense *= cds.getLGD();

            // Compute the discount factor discounting the upfront payment made on the cash settlement date back to the valuation date
            double df = Math.Exp(-yieldCurve.getRT_(cds.getCashSettleTime()));

            pvSense /= df;

            //TODO this was put in quickly the get the right sensitivity to the first node
            double dfSense = yieldCurve.getSingleNodeDiscountFactorSensitivity(cds.getCashSettleTime(), yieldCurveNode);

            if (dfSense != 0.0)
            {
                double pro = protectionLeg(cds, yieldCurve, creditCurve);
                pvSense -= pro / df * dfSense;
            }

            return(pvSense);
        }