public AbcdCoeffHolder(double?a,
                               double?b,
                               double?c,
                               double?d,
                               bool aIsFixed,
                               bool bIsFixed,
                               bool cIsFixed,
                               bool dIsFixed)
        {
            a_               = a;
            b_               = b;
            c_               = c;
            d_               = d;
            aIsFixed_        = false;
            bIsFixed_        = false;
            cIsFixed_        = false;
            dIsFixed_        = false;
            k_               = new List <double>();
            error_           = null;
            maxError_        = null;
            abcdEndCriteria_ = EndCriteria.Type.None;

            if (a_ != null)
            {
                aIsFixed_ = aIsFixed;
            }
            else
            {
                a_ = -0.06;
            }
            if (b_ != null)
            {
                bIsFixed_ = bIsFixed;
            }
            else
            {
                b_ = 0.17;
            }
            if (c_ != null)
            {
                cIsFixed_ = cIsFixed;
            }
            else
            {
                c_ = 0.54;
            }
            if (d_ != null)
            {
                dIsFixed_ = dIsFixed;
            }
            else
            {
                d_ = 0.17;
            }

            AbcdMathFunction.validate(a_.Value, b_.Value, c_.Value, d_.Value);
        }
        // to constrained <- from unconstrained
        public AbcdCalibration(List <double> t,
                               List <double> blackVols,
                               double aGuess             = -0.06,
                               double bGuess             = 0.17,
                               double cGuess             = 0.54,
                               double dGuess             = 0.17,
                               bool aIsFixed             = false,
                               bool bIsFixed             = false,
                               bool cIsFixed             = false,
                               bool dIsFixed             = false,
                               bool vegaWeighted         = false,
                               EndCriteria endCriteria   = null,
                               OptimizationMethod method = null)
        {
            aIsFixed_        = aIsFixed;
            bIsFixed_        = bIsFixed;
            cIsFixed_        = cIsFixed;
            dIsFixed_        = dIsFixed;
            a_               = aGuess;
            b_               = bGuess;
            c_               = cGuess;
            d_               = dGuess;
            abcdEndCriteria_ = QLCore.EndCriteria.Type.None;
            endCriteria_     = endCriteria;
            optMethod_       = method;
            weights_         = new InitializedList <double>(blackVols.Count, 1.0 / blackVols.Count);
            vegaWeighted_    = vegaWeighted;
            times_           = t;
            blackVols_       = blackVols;


            AbcdMathFunction.validate(aGuess, bGuess, cGuess, dGuess);

            Utils.QL_REQUIRE(blackVols.Count == t.Count, () =>
                             "mismatch between number of times (" + t.Count + ") and blackVols (" + blackVols.Count + ")");

            // if no optimization method or endCriteria is provided, we provide one
            if (optMethod_ == null)
            {
                double epsfcn = 1.0e-8;
                double xtol   = 1.0e-8;
                double gtol   = 1.0e-8;
                bool   useCostFunctionsJacobian = false;
                optMethod_ = new LevenbergMarquardt(epsfcn, xtol, gtol, useCostFunctionsJacobian);
            }

            if (endCriteria_ == null)
            {
                int    maxIterations = 10000;
                int    maxStationaryStateIterations = 1000;
                double rootEpsilon         = 1.0e-8;
                double functionEpsilon     = 0.3e-4; // Why 0.3e-4 ?
                double gradientNormEpsilon = 0.3e-4; // Why 0.3e-4 ?
                endCriteria_ = new EndCriteria(maxIterations, maxStationaryStateIterations, rootEpsilon, functionEpsilon,
                                               gradientNormEpsilon);
            }
        }