public HyperBox(HyperBox <SummaryType> source) { this.Coordinates = new FloatRange[source.NumDimensions]; int i; for (i = 0; i < source.NumDimensions; i++) { this.Coordinates[i] = new FloatRange(source.Coordinates[i]); } }
public bool Intersects(HyperBox <SummaryType> other) { int i; for (i = 0; i < this.NumDimensions; i++) { if (!this.Coordinates[i].Intersects(other.Coordinates[i])) { return(false); } } return(true); }
public SimpleInterpolationBox(HyperBox <ScoreType> boundary, List <int> dimensionSplitOrder, int dimToSort, INumerifier <ScoreType> scoreHandler) { this.scoreHandler = scoreHandler; this.currentBoundary = boundary; this.observedBoundary = null; this.dimensionsToSplit = dimensionSplitOrder; //this.datapointsByInput = new StatList<Datapoint, Datapoint>(new DatapointComparer(dimToSort), this); this.unpropogatedDatapoints = new List <IDatapoint <ScoreType> >(0); this.dimensionToSort = dimToSort; this.numDatapoints = 0; this.splitDimension = dimensionSplitOrder.First(); this.depthFromLeaves = 0; //this.splitDimension_inputs = new Distribution(); }
public SmartInterpolationBox(HyperBox <SummaryType> boundary, INumerifier <SummaryType> scoreHandler, int depthFromRoot = 0) { //int i; this.scoreHandler = scoreHandler; this.currentBoundary = boundary; this.observedBoundary = null; this.splitDimension = -1; this.datapoints = new List <IDatapoint <SummaryType> >(); this.pendingDatapoints = new List <IDatapoint <SummaryType> >(); this.itemSummary = scoreHandler.Default(); this.depthFromRoot = depthFromRoot; #if MIN_SPLIT_COUNTS this.minSplitCounts = new int[boundary.NumDimensions]; #endif #if CACHE_STDDEV this.inputs = new Distribution[boundary.NumDimensions]; for (i = 0; i < this.inputs.Length; i++) { this.inputs[i] = new Distribution(); } #endif }
public void ConsiderSplitting() { // make sure there is a splittable dimension where the spread is nonzero int dimension = -1; foreach (int coordinate in this.dimensionsToSplit) { if (this.observedBoundary.Coordinates[coordinate].IsSplittable) { dimension = coordinate; } } if (dimension < 0) { return; } // now split // compute the coordinates of each child #if true List <double> inputs = new List <double>(this.unpropogatedDatapoints.Count()); foreach (IDatapoint <ScoreType> datapoint in this.unpropogatedDatapoints) { inputs.Add(datapoint.InputCoordinates[dimension]); } double splitValue = MedianUtils.EstimateMedian(inputs); if (splitValue == this.currentBoundary.Coordinates[dimension].HighCoordinate || splitValue == this.currentBoundary.Coordinates[dimension].LowCoordinate) { splitValue = (this.currentBoundary.Coordinates[dimension].LowCoordinate + this.currentBoundary.Coordinates[dimension].HighCoordinate) / 2; } #else //double splitValue = (this.currentBoundary.Coordinates[dimension].LowCoordinate + this.currentBoundary.Coordinates[dimension].HighCoordinate) / 2; double splitValue = (this.observedBoundary.Coordinates[dimension].LowCoordinate + this.observedBoundary.Coordinates[dimension].HighCoordinate) / 2; #endif // TODO: consider splitting at the median, since that might run slightly faster // double splitValue = this.splitDimension_inputs.Mean; HyperBox <ScoreType> lowerBoundary = new HyperBox <ScoreType>(this.currentBoundary); lowerBoundary.Coordinates[dimension].HighCoordinate = splitValue; lowerBoundary.Coordinates[dimension].HighInclusive = true; HyperBox <ScoreType> upperBoundary = new HyperBox <ScoreType>(this.currentBoundary); upperBoundary.Coordinates[dimension].LowCoordinate = splitValue; upperBoundary.Coordinates[dimension].LowInclusive = false; // determine the split order for the children List <int> childSplitOrder = new List <int>(this.dimensionsToSplit); childSplitOrder.RemoveAt(0); childSplitOrder.Add(dimension); // fill data into the children this.lowerChild = new SimpleInterpolationBox <ScoreType>(lowerBoundary, childSplitOrder, this.dimensionToSort, this.scoreHandler); this.upperChild = new SimpleInterpolationBox <ScoreType>(upperBoundary, childSplitOrder, this.dimensionToSort, this.scoreHandler); // skip half of the datapoints because it saves a lot of time (the skipping compounds in grandchildren etc) and shouldn't make much difference in our decision of which dim to split #if false int desiredNumPointsPerChild = this.unpropogatedDatapoints.Count(); #else int desiredNumPointsPerChild = this.unpropogatedDatapoints.Count() / 4; #endif List <IDatapoint <ScoreType> > lowerPoints = new List <IDatapoint <ScoreType> >(desiredNumPointsPerChild); List <IDatapoint <ScoreType> > upperPoints = new List <IDatapoint <ScoreType> >(desiredNumPointsPerChild); foreach (IDatapoint <ScoreType> newDatapoint in this.unpropogatedDatapoints) { if (newDatapoint.InputCoordinates[dimension] >= splitValue) { if (upperPoints.Count < desiredNumPointsPerChild) { upperPoints.Add(newDatapoint); } } else { if (lowerPoints.Count < desiredNumPointsPerChild) { lowerPoints.Add(newDatapoint); } } } this.unpropogatedDatapoints = new List <IDatapoint <ScoreType> >(0); this.lowerChild.AddDatapoints(lowerPoints); this.upperChild.AddDatapoints(upperPoints); }
// SummaryType is the type of object to put in each box (it's a summary of the datapoints that the box represents) public AdaptiveLinearInterpolator(HyperBox <SummaryType> inputBoundary, INumerifier <SummaryType> itemCombiner) { this.itemCombiner = itemCombiner; this.root = new SmartInterpolationBox <SummaryType>(inputBoundary, itemCombiner); }
public void Split(int dimension) { this.splitDimension = dimension; // make sure that datapointsByInput exists, and that it sorts in the correct dimension //this.datapointsByInput = new StatList<Datapoint, Datapoint>(new DatapointComparer(dimension), this); // compute the coordinates of each child #if true List <double> inputs = new List <double>(this.datapoints.Count); foreach (IDatapoint <SummaryType> datapoint in this.datapoints) { inputs.Add(datapoint.InputCoordinates[dimension]); } double splitValue = MedianUtils.EstimateMedian(inputs); // check for the possibility that MedianUtils was unlucky and found something on the edge of observedBoundary if (splitValue >= this.observedBoundary.Coordinates[dimension].HighCoordinate || splitValue <= this.observedBoundary.Coordinates[dimension].LowCoordinate) { splitValue = (this.observedBoundary.Coordinates[dimension].LowCoordinate + this.observedBoundary.Coordinates[dimension].HighCoordinate) / 2; // check for the possibility that rounding error is preventing a split if (splitValue >= this.observedBoundary.Coordinates[dimension].HighCoordinate || splitValue <= this.observedBoundary.Coordinates[dimension].LowCoordinate) { this.lowerChild = this.upperChild = null; return; } } #else double splitValue = (this.observedBoundary.Coordinates[dimension].LowCoordinate + this.observedBoundary.Coordinates[dimension].HighCoordinate) / 2; if (splitValue == this.currentBoundary.Coordinates[dimension].HighCoordinate || splitValue == this.currentBoundary.Coordinates[dimension].LowCoordinate) { splitValue = (this.currentBoundary.Coordinates[dimension].LowCoordinate + this.currentBoundary.Coordinates[dimension].HighCoordinate) / 2; } #endif HyperBox <SummaryType> lowerBoundary = new HyperBox <SummaryType>(this.currentBoundary); lowerBoundary.Coordinates[dimension].HighCoordinate = splitValue; lowerBoundary.Coordinates[dimension].HighInclusive = true; HyperBox <SummaryType> upperBoundary = new HyperBox <SummaryType>(this.currentBoundary); upperBoundary.Coordinates[dimension].LowCoordinate = splitValue; upperBoundary.Coordinates[dimension].LowInclusive = false; //if (this.NumDimensions == 3 && dimension == 0 && splitValue == 900 && this.currentBoundary.Coordinates[0].LowCoordinate == 0) // upperBoundary = upperBoundary; // decide which data goes in which child List <IDatapoint <SummaryType> > lowerPoints = new List <IDatapoint <SummaryType> >(this.datapoints.Count / 2); List <IDatapoint <SummaryType> > upperPoints = new List <IDatapoint <SummaryType> >(this.datapoints.Count / 2); foreach (IDatapoint <SummaryType> datapoint in this.datapoints) { if (lowerBoundary.Contains(datapoint)) { lowerPoints.Add(datapoint); } if (upperBoundary.Contains(datapoint)) { upperPoints.Add(datapoint); } } this.lowerChild = new SmartInterpolationBox <SummaryType>(lowerBoundary, this.scoreHandler, this.depthFromRoot + 1); this.upperChild = new SmartInterpolationBox <SummaryType>(upperBoundary, this.scoreHandler, this.depthFromRoot + 1); // If we're told that we don't yet have to spend a lot of effort choosing a split dimension, then just ask the children to split the next dimension if (this.numPreplannedSplits > 1) { int nextSplitDimension = (this.splitDimension + 1) % this.NumDimensions; this.lowerChild.ForceSplits(nextSplitDimension, this.numPreplannedSplits - 1); this.upperChild.ForceSplits(nextSplitDimension, this.numPreplannedSplits - 1); } this.lowerChild.AddDatapoints(lowerPoints); // this child was constructed all at once using a known size and couldn't have been queried in the meanwhile, // so the child can use all of its points for determining where to split (this won't cause inconsistencies across runs, even as more data gets added) this.lowerChild.PermitSplitting(); this.upperChild.AddDatapoints(upperPoints); // this child was constructed all at once using a known size and couldn't have been queried in the meanwhile, // so the child can use all of its points for determining where to split (this won't cause inconsistencies across runs, even as more data gets added) this.upperChild.PermitSplitting(); #if false this.lowerChild.ApplyPendingPoints(); this.upperChild.ApplyPendingPoints(); #endif #if MIN_SPLIT_COUNTS this.UpdateSplitCounts(); #endif }