/// <summary>Initializes a new instance of the <see cref="EmpiricalDistribution" /> class.
        /// </summary>
        /// <param name="empiricalDistribution">The empirical distribution.</param>
        /// <param name="densityEstimator">The density estimator.</param>
        protected EmpiricalDistribution(EmpiricalDistribution empiricalDistribution, DensityEstimator densityEstimator)
        {
            m_Median           = empiricalDistribution.m_Median;
            m_Quantile         = empiricalDistribution.m_Quantile;
            m_MomentCalculator = empiricalDistribution.m_MomentCalculator;

            Name                  = empiricalDistribution.Name;
            LongName              = empiricalDistribution.LongName;
            m_DensityEstimator    = densityEstimator.Create(this);
            InfoOutputDetailLevel = empiricalDistribution.InfoOutputDetailLevel;
        }
        /// <summary>Initializes a new instance of the <see cref="EmpiricalDistribution" /> class.
        /// </summary>
        /// <param name="sample">The sample.</param>
        /// <param name="empiricalQuantileMethod">The empirical quantile method.</param>
        /// <param name="isSorted">A value indicating whether the values in the <paramref name="sample"/> are sorted in ascending order.</param>
        /// <param name="densityEstimator">The density estimator.</param>
        /// <param name="empiricalMomentEstimator">A empirical moment estimator, used for example for a bootstrap approach.</param>
        public EmpiricalDistribution(IEnumerable <double> sample, EmpiricalQuantile empiricalQuantileMethod, bool isSorted, DensityEstimator densityEstimator, EmpiricalMomentEstimator empiricalMomentEstimator)
        {
            if (sample == null)
            {
                throw new ArgumentNullException("sample");
            }
            Sample = sample.Skip(0);  // is used to avoid a cast to the original sample!

            InfoOutputDetailLevel = InfoOutputDetailLevel.Middle;
            m_Quantile            = new Lazy <IQuantileFunction>(() => empiricalQuantileMethod.Create(sample, isSorted)); // sorted sample will be computed on demand only!
            m_Median = new Lazy <double>(() => GetSampleMedian(SortedSample));                                            // required sorted sample, i.e. will create quantile calculation before

            m_MomentCalculator = new Lazy <ProbabilityDistributionMoments>(() => empiricalMomentEstimator.Create(sample));
            m_DensityEstimator = densityEstimator.Create(this);

            Name     = new IdentifierString("Empirical distribution");
            LongName = new IdentifierString("Empirical distribution");
        }