/// <summary>
        /// Combines this CountMinSketch with another. Returns a bool if the merge was
        /// successful. Throws an exception if the matrix width and depth are not equal.
        /// </summary>
        /// <param name="other">The CountMinSketch to merge with the current
        /// instance.</param>
        /// <returns>True if successful.</returns>
        public bool Merge(CountMinSketch other)
        {
            if (this.Depth != other.Depth)
            {
                throw new Exception("Matrix depth must match.");
            }

            if (this.Width != other.Width)
            {
                throw new Exception("Matrix width must match.");
            }

            lock (_lock)
            {
                for (uint i = 0; i < this.Depth; i++)
                {
                    for (int j = 0; j < this.Width; j++)
                    {
                        this.Matrix[i][j] += other.Matrix[i][j];
                    }
                }
            }

            this.count += other.count;
            return(true);
        }
        public CountMinSketch Deserialize(Stream stream)
        {
            using (var br = new BinaryReader(stream))
            {
                int dataFormatMajorVersion = br.ReadUInt16();
                int dataFormatMinorVersion = br.ReadUInt16();

                AssertDataVersionCanBeRead(dataFormatMajorVersion, dataFormatMinorVersion);

                var count   = br.ReadUInt64();
                var epsilon = br.ReadDouble();
                var delta   = br.ReadDouble();

                var width = (uint)(Math.Ceiling(Math.E / epsilon));
                var depth = (uint)(Math.Ceiling(Math.Log(1 / delta)));

                var matrix = new ulong[depth][];

                for (var i = 0; i < depth; i++)
                {
                    matrix[i] = new ulong[width];
                    for (var j = 0; j < width; j++)
                    {
                        var element = br.ReadUInt64();
                        matrix[i][j] = element;
                    }
                }

                var data = new CountMinSketchState
                {
                    Count   = count,
                    Epsilon = epsilon,
                    Delta   = delta,
                    Matrix  = matrix
                };

                var result = new CountMinSketch(data);

                return(result);
            }
        }
        public void Serialize(Stream stream, CountMinSketch estimator)
        {
            using (var bw = new BinaryWriter(stream))
            {
                bw.Write(DataFormatMajorVersion);
                bw.Write(DataFormatMinorVersion);

                var data = estimator.GetState();

                bw.Write(data.Count);
                bw.Write(data.Epsilon);
                bw.Write(data.Delta);

                foreach (var row in data.Matrix)
                {
                    foreach (var col in row)
                    {
                        bw.Write(col);
                    }
                }

                bw.Flush();
            }
        }