public MetricBundle(S2CellMetric min, S2CellMetric max, S2CellMetric avg)
 {
     min_ = min;
     max_ = max;
     avg_ = avg;
 }
        public void testMinMaxAvg(String label, int level, double count,
                                  double absError, double minValue, double maxValue, double avgValue,
                                  S2CellMetric minMetric, S2CellMetric maxMetric, S2CellMetric avgMetric)
        {
            // All metrics are minimums, maximums, or averages of differential
            // quantities, and therefore will not be exact for cells at any finite
            // level. The differential minimum is always a lower bound, and the maximum
            // is always an upper bound, but these minimums and maximums may not be
            // achieved for two different reasons. First, the cells at each level are
            // sampled and we may miss the most extreme examples. Second, the actual
            // metric for a cell is obtained by integrating the differential quantity,
            // which is not constant across the cell. Therefore cells at low levels
            // (bigger cells) have smaller variations.
            //
            // The "tolerance" below is an attempt to model both of these effects.
            // At low levels, error is dominated by the variation of differential
            // quantities across the cells, while at high levels error is dominated by
            // the effects of random sampling.
            var tolerance = (maxMetric.GetValue(level) - minMetric.GetValue(level))
                            /Math.Sqrt(Math.Min(count, 0.5*(1L << level)))*10;
            if (tolerance == 0)
            {
                tolerance = absError;
            }

            var minError = minValue - minMetric.GetValue(level);
            var maxError = maxMetric.GetValue(level) - maxValue;
            var avgError = Math.Abs(avgMetric.GetValue(level) - avgValue);
            Console.WriteLine(
                "%-10s (%6.0f samples, tolerance %8.3g) - Min (%9.3g : %9.3g) "
                + "Max (%9.3g : %9.3g), avg (%9.3g : %9.3g)\n", label, count,
                tolerance, minError/minValue, minError/tolerance, maxError
                                                                  /maxValue, maxError/tolerance, avgError/avgValue, avgError
                                                                                                                    /tolerance);

            Assert.True(minMetric.GetValue(level) <= minValue + absError);
            Assert.True(minMetric.GetValue(level) >= minValue - tolerance);
            Console.WriteLine("Level: " + maxMetric.GetValue(level) + " Max " + (maxValue + tolerance));
            Assert.True(maxMetric.GetValue(level) <= maxValue + tolerance);
            Assert.True(maxMetric.GetValue(level) >= maxValue - absError);
            assertDoubleNear(avgMetric.GetValue(level), avgValue, 10*tolerance);
        }