public Distribution Interpolate(double[] coordinates)
        {
            SmartInterpolationBox <SummaryType> box = this.FindNeighborhood(coordinates);
            Distribution result = this.itemCombiner.ConvertToDistribution(box.ItemSummary);

            return(result);
        }
        // Finds a bunch of points that are representative of the inputs that we've observed
        // There will be more points in areas that have more changes, and fewer points in other areas
        public IEnumerable <double[]> FindRepresentativePoints()
        {
            List <double[]> points = new List <double[]>();
            List <SmartInterpolationBox <SummaryType> > boxesToCheck = new List <SmartInterpolationBox <SummaryType> >();

            boxesToCheck.Add(this.root);
            while (boxesToCheck.Count > 0)
            {
                SmartInterpolationBox <SummaryType> box = boxesToCheck.Last();
                boxesToCheck.RemoveAt(boxesToCheck.Count - 1);
                if (this.shouldDescend(box) && box.ChildrenExist())
                {
                    boxesToCheck.Add(box.UpperChild);
                    boxesToCheck.Add(box.LowerChild);
                }
                else
                {
                    if (box.ObservedBoundary != null)
                    {
                        points.Add(box.ObservedBoundary.Middle);
                    }
                }
            }
            return(points);
        }
        public Distribution GetAverage()
        {
            //DateTime start = DateTime.Now;
            SmartInterpolationBox <SummaryType> box = this.root;
            Distribution result = this.itemCombiner.ConvertToDistribution(this.root.ItemSummary);

            //DateTime end = DateTime.Now;
            //System.Diagnostics.Debug.WriteLine("Spent " + end.Subtract(start) + " getting average of interpolation box");
            return(result);
        }
        // tells whether it's worth descending into <child> for more analysis
        private bool shouldDescend(SmartInterpolationBox <SummaryType> child)
        {
            if (child.NumDatapoints <= 1)
            {
                return(false);
            }
            double childScoreSpread = child.GetScoreSpread();

            if (childScoreSpread <= 0)
            {
                return(false);
            }
            return(this.root.GetScoreSpread() * child.NumDatapoints * child.NumDatapoints > this.root.NumDatapoints * childScoreSpread * 4);
        }
        private SmartInterpolationBox <SummaryType> FindNeighborhood(double[] coordinates, int maxNumIterations)
        {
            if (coordinates.Length != this.root.NumDimensions)
            {
                throw new ArgumentException("the number of dimensions is incorrect");
            }

            // figure out how much room there was to start with
            int numSplits = 0;

            if (!this.root.ChildrenExist())
            {
                numSplits++;
            }
            double maxOutputSpread = this.root.GetScoreSpread();
            SmartInterpolationBox <SummaryType> currentBox = this.root;
            SmartInterpolationBox <SummaryType> nextBox;
            SmartInterpolationBox <SummaryType> result = null;

            result = currentBox;
            while (true)
            {
                if (!currentBox.ChildrenExist())
                {
                    numSplits++;
                }
                // consider moving to the child
                nextBox = currentBox.ChooseChild(coordinates);
                // figure out whether it's time to stop splitting
                if (nextBox == null)
                {
                    return(result);
                }
                result = currentBox;
                // the more datapoints we have, the more often that we split
                if (!shouldDescend(nextBox))
                {
                    // if we finally decided that we could split but didn't want to, then return the content of this box
                    return(result);
                }

                if (numSplits == maxNumIterations)
                {
                    // ran out of time; return the content of this box
                    return(result);
                }
                currentBox = nextBox;
            }
        }
        public IEnumerable <IDatapoint <SummaryType> > JustifyInterpolation(double[] coordinates)
        {
            SmartInterpolationBox <SummaryType> box = this.FindNeighborhood(coordinates);

            return(box.Datapoints);
        }
        public HyperBox <SummaryType> FindNeighborhoodCoordinates(double[] coordinates)
        {
            SmartInterpolationBox <SummaryType> box = this.FindNeighborhood(coordinates);

            return(box.ObservedBoundary);
        }