/// <summary>
        /// Compress the hybrid estimator.
        /// </summary>
        /// <param name="inPlace"></param>
        /// <returns></returns>
        public IHybridEstimator <TEntity, int, TCount> Compress(bool inPlace)
        {
            IHybridEstimator <TEntity, int, TCount> self = this;
            var res = FullExtract().Compress(_configuration);

            if (inPlace)
            {
                self.Rehydrate(res);
                return(this);
            }
            IHybridEstimator <TEntity, int, TCount> estimator = new HybridEstimator <TEntity, TId, TCount>(
                res.StrataEstimator.BlockSize,
                res.StrataEstimator.StrataCount,
                _configuration);

            if (res.BitMinwiseEstimator != null)
            {
                estimator.Initialize(
                    res.BitMinwiseEstimator.Capacity + res.ItemCount,
                    res.BitMinwiseEstimator.BitSize,
                    res.BitMinwiseEstimator.HashCount);
            }
            estimator.Rehydrate(res);
            return(estimator);
        }
        /// <summary>
        /// Approximate the size of the set difference based upon an estimator and a (subset) of the other set
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="TId"></typeparam>
        /// <typeparam name="TCount"></typeparam>
        /// <param name="estimator">The hybrid estimator</param>
        /// <param name="bloomFilterSizeConfiguration"></param>
        /// <param name="otherSetSample">A (sub)set to compare against</param>
        /// <param name="otherSetSize">Total set of the size to compare against (when not given, the set sample size is used)</param>
        /// <returns>An estimate for the number of differences, or <c>null</c> when a reasonable estimate is not possible.</returns>
        /// <remarks>Not an ideal solution, due to the potentially high false positive rate of the estimator. But useful when you do not have a local estimator, but you do have a (sub)set of the data and know the total size of the data. Known issue is that small differences on very large sets are either grossly over estimated (when there is a count difference between the two sets) or not recognized at all (under estimated, when both sets have the same count, but different values). The estimate can be rather inexact. See 'Exact Set Reconciliation Based on Bloom Filters', Dafang Zhang, Kun Xie, 2011 International Conference on Computer Science and Network Technology, page 2001-2009 </remarks>
        public static long?QuasiDecode <TEntity, TId, TCount>(
            this IHybridEstimator <TEntity, TId, TCount> estimator,
            IBloomFilterSizeConfiguration bloomFilterSizeConfiguration,
            IEnumerable <TEntity> otherSetSample,
            long?otherSetSize = null)
            where TId : struct
            where TCount : struct
        {
            if (estimator == null)
            {
                return(otherSetSize ?? otherSetSample?.LongCount() ?? 0L);
            }
            //compensate for extremely high error rates that can occur with estimators. Without this, the difference goes to infinity.
            var factors = QuasiEstimator.GetAdjustmentFactor(
                bloomFilterSizeConfiguration,
                estimator.VirtualBlockSize,
                estimator.ItemCount,
                estimator.HashFunctionCount,
                estimator.ErrorRate);

            return(QuasiEstimator.Decode(
                       estimator.ItemCount,
                       factors.Item1,
                       estimator.Contains,
                       otherSetSample,
                       otherSetSize,
                       factors.Item2));
        }
        /// <summary>
        /// Intersect with the estimator.
        /// </summary>
        /// <param name="estimator"></param>
        public void Intersect(IHybridEstimatorFullData <int, TCount> estimator)
        {
            IHybridEstimator <TEntity, int, TCount> self = this;

            Rehydrate(self
                      .FullExtract()
                      .Intersect(_configuration, estimator));
        }
 /// <summary>
 /// Decode the given hybrid estimator.
 /// </summary>
 /// <param name="estimator">The estimator for the other set.</param>
 /// <param name="destructive">When <c>true</c> the values in this estimator will be altered and rendered useless, else <c>false</c>.</param>
 /// <returns>An estimate of the number of differences between the two sets that the estimators are based upon.</returns>
 public long?Decode(IHybridEstimator <TEntity, int, TCount> estimator,
                    bool destructive = false)
 {
     if (estimator == null)
     {
         return(ItemCount);
     }
     return(Decode(estimator.Extract(), destructive));
 }
        /// <summary>
        /// Decode the given hybrid estimator data.
        /// </summary>
        /// <param name="estimator">The estimator for the other set.</param>
        /// <param name="destructive">When <c>true</c> the values in this estimator will be altered and rendered useless, else <c>false</c>.</param>
        /// <returns>An estimate of the number of differences between the two sets that the estimators are based upon.</returns>
        public long?Decode(IHybridEstimatorData <int, TCount> estimator,
                           bool destructive = false)
        {
            if (estimator == null)
            {
                return(ItemCount);
            }
            IHybridEstimator <TEntity, int, TCount> self = this;

            return(self
                   .Extract()
                   .Decode(estimator, _configuration));
        }
 /// <summary>
 /// intersect with the estimator
 /// </summary>
 /// <param name="estimator"></param>
 public void Intersect(IHybridEstimator <TEntity, int, TCount> estimator)
 {
     Intersect(estimator.FullExtract());
 }