| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.datasketches.quantilescommon; |
| |
| import java.lang.reflect.Array; |
| import java.util.Comparator; |
| |
| /** |
| * This class reinserts the min and max values into the sorted view arrays as required. |
| */ |
| public class IncludeMinMax { |
| |
| /** A simple structure to hold a pair of arrays */ |
| public static class DoublesPair { |
| /** the array of quantiles */ |
| public double[] quantiles; |
| /** the array of associated cumulative weights */ |
| public long[] cumWeights; |
| |
| /** |
| * Constructor. |
| * @param quantiles the array of quantiles |
| * @param cumWeights the array of associated cumulative weights |
| */ |
| public DoublesPair(final double[] quantiles, final long[] cumWeights) { |
| this.quantiles = quantiles; |
| this.cumWeights = cumWeights; |
| } |
| } |
| |
| /** A simple structure to hold a pair of arrays */ |
| public static class FloatsPair { |
| /** The array of quantiles */ |
| public float[] quantiles; |
| /** The array of associated cumulative weights */ |
| public long[] cumWeights; |
| |
| /** |
| * Constructor. |
| * @param quantiles the array of quantiles |
| * @param cumWeights the array of associated cumulative weights |
| */ |
| public FloatsPair(final float[] quantiles, final long[] cumWeights) { |
| this.quantiles = quantiles; |
| this.cumWeights = cumWeights; |
| } |
| } |
| |
| /** |
| * A simple structure to hold a pair of arrays |
| * @param <T> the item class type |
| */ |
| public static class ItemsPair<T> { |
| /** The array of quantiles */ |
| public T[] quantiles; |
| /** The array of associated cumulative weights */ |
| public long[] cumWeights; |
| |
| /** |
| * Constructor. |
| * @param quantiles the array of quantiles |
| * @param cumWeights the array of associated cumulative weights |
| */ |
| public ItemsPair(final T[] quantiles, final long[] cumWeights) { |
| this.quantiles = quantiles; |
| this.cumWeights = cumWeights; |
| } |
| } |
| |
| /** |
| * The logic to include the min and max of type double. |
| * @param quantilesIn The array of quantiles |
| * @param cumWeightsIn The array of associated cumulative weights |
| * @param maxItem the maximum item of the stream |
| * @param minItem the minimum item of the stream |
| * @return a DoublesPair |
| */ |
| public static DoublesPair includeDoublesMinMax( |
| final double[] quantilesIn, |
| final long[] cumWeightsIn, |
| final double maxItem, |
| final double minItem) { |
| final int lenIn = cumWeightsIn.length; |
| final boolean adjLow = quantilesIn[0] != minItem; //if true, adjust the low end |
| final boolean adjHigh = quantilesIn[lenIn - 1] != maxItem; //if true, adjust the high end |
| int adjLen = lenIn; //this will be the length of the local copies of quantiles and cumWeights |
| adjLen += adjLow ? 1 : 0; |
| adjLen += adjHigh ? 1 : 0; |
| final double[] adjQuantiles; |
| final long[] adjCumWeights; |
| if (adjLen > lenIn) { //is any adjustment required at all? |
| adjQuantiles = new double[adjLen]; |
| adjCumWeights = new long[adjLen]; |
| final int offset = adjLow ? 1 : 0; |
| System.arraycopy(quantilesIn, 0, adjQuantiles, offset, lenIn); |
| System.arraycopy(cumWeightsIn,0, adjCumWeights, offset, lenIn); |
| |
| //Adjust the low end if required. Don't need to adjust weight of next one because it is cumulative. |
| if (adjLow) { |
| adjQuantiles[0] = minItem; |
| adjCumWeights[0] = 1; |
| } |
| |
| if (adjHigh) { |
| adjQuantiles[adjLen - 1] = maxItem; |
| adjCumWeights[adjLen - 1] = cumWeightsIn[lenIn - 1]; |
| adjCumWeights[adjLen - 2] = cumWeightsIn[lenIn - 1] - 1; |
| } |
| } else { //both min and max are already in place, no adjustments are required. |
| adjQuantiles = quantilesIn; |
| adjCumWeights = cumWeightsIn; |
| |
| } //END of Adjust End Points |
| return new DoublesPair(adjQuantiles, adjCumWeights); |
| } |
| |
| /** |
| * The logic to include the min and max of type float. |
| * @param quantilesIn The array of quantiles |
| * @param cumWeightsIn The array of associated cumulative weights |
| * @param maxItem the maximum item of the stream |
| * @param minItem the minimum item of the stream |
| * @return a FloatsPair |
| */ |
| public static FloatsPair includeFloatsMinMax( |
| final float[] quantilesIn, |
| final long[] cumWeightsIn, |
| final float maxItem, |
| final float minItem) { |
| final int lenIn = cumWeightsIn.length; |
| final boolean adjLow = quantilesIn[0] != minItem; //if true, adjust the low end |
| final boolean adjHigh = quantilesIn[lenIn - 1] != maxItem; //if true, adjust the high end |
| int adjLen = lenIn; //this will be the length of the local copies of quantiles and cumWeights |
| adjLen += adjLow ? 1 : 0; |
| adjLen += adjHigh ? 1 : 0; |
| final float[] adjQuantiles; |
| final long[] adjCumWeights; |
| if (adjLen > lenIn) { //is any adjustment required at all? |
| adjQuantiles = new float[adjLen]; |
| adjCumWeights = new long[adjLen]; |
| final int offset = adjLow ? 1 : 0; |
| System.arraycopy(quantilesIn, 0, adjQuantiles, offset, lenIn); |
| System.arraycopy(cumWeightsIn,0, adjCumWeights, offset, lenIn); |
| |
| //Adjust the low end if required. |
| if (adjLow) { |
| adjQuantiles[0] = minItem; |
| adjCumWeights[0] = 1; |
| } |
| |
| if (adjHigh) { |
| adjQuantiles[adjLen - 1] = maxItem; |
| adjCumWeights[adjLen - 1] = cumWeightsIn[lenIn - 1]; |
| adjCumWeights[adjLen - 2] = cumWeightsIn[lenIn - 1] - 1; |
| } |
| } else { //both min and max are already in place, no adjustments are required. |
| adjQuantiles = quantilesIn; |
| adjCumWeights = cumWeightsIn; |
| |
| } //END of Adjust End Points |
| return new FloatsPair(adjQuantiles, adjCumWeights); |
| } |
| |
| /** |
| * The logic to include the min and max of type T. |
| * @param quantilesIn The array of quantiles |
| * @param cumWeightsIn The array of associated cumulative weights |
| * @param maxItem the maximum item of the stream |
| * @param minItem the minimum item of the stream |
| * @param comparator a comparator for type T |
| * @param <T> the item class type |
| * @return an ItemsPair |
| */ |
| @SuppressWarnings("unchecked") |
| public static <T> ItemsPair<T> includeItemsMinMax( |
| final T[] quantilesIn, |
| final long[] cumWeightsIn, |
| final T maxItem, |
| final T minItem, |
| final Comparator<? super T> comparator) { |
| final int lenIn = cumWeightsIn.length; |
| final boolean adjLow = comparator.compare(quantilesIn[0], minItem) != 0; //if true, adjust the low end |
| final boolean adjHigh = comparator.compare(quantilesIn[lenIn - 1], maxItem) != 0; //if true, adjust the high end |
| int adjLen = lenIn; //this will be the length of the local copies of quantiles and cumWeights |
| adjLen += adjLow ? 1 : 0; |
| adjLen += adjHigh ? 1 : 0; |
| final T[] adjQuantiles; |
| final long[] adjCumWeights; |
| if (adjLen > lenIn) { //is any adjustment required at all? |
| adjQuantiles = (T[]) Array.newInstance(minItem.getClass(), adjLen); |
| adjCumWeights = new long[adjLen]; |
| final int offset = adjLow ? 1 : 0; |
| System.arraycopy(quantilesIn, 0, adjQuantiles, offset, lenIn); |
| System.arraycopy(cumWeightsIn,0, adjCumWeights, offset, lenIn); |
| |
| //Adjust the low end if required. |
| if (adjLow) { |
| adjQuantiles[0] = minItem; |
| adjCumWeights[0] = 1; |
| } |
| |
| if (adjHigh) { |
| adjQuantiles[adjLen - 1] = maxItem; |
| adjCumWeights[adjLen - 1] = cumWeightsIn[lenIn - 1]; |
| adjCumWeights[adjLen - 2] = cumWeightsIn[lenIn - 1] - 1; |
| } |
| } else { //both min and max are already in place, no adjustments are required. |
| adjQuantiles = quantilesIn; |
| adjCumWeights = cumWeightsIn; |
| |
| } //END of Adjust End Points |
| return new ItemsPair<>(adjQuantiles, adjCumWeights); |
| } |
| |
| } |