blob: 101c26cddc98f67608526ccb6cea42ccde5c3d7f [file] [log] [blame]
/*
* 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.quantiles;
import static org.apache.datasketches.quantilescommon.LinearRanksAndQuantiles.getTrueDoubleQuantile;
import static org.apache.datasketches.quantilescommon.LinearRanksAndQuantiles.getTrueDoubleRank;
import static org.apache.datasketches.quantilescommon.QuantileSearchCriteria.EXCLUSIVE;
import static org.apache.datasketches.quantilescommon.QuantileSearchCriteria.INCLUSIVE;
import static org.apache.datasketches.quantilescommon.QuantilesUtil.getNaturalRank;
import static org.testng.Assert.assertEquals;
import org.apache.datasketches.quantilescommon.DoublesSketchSortedView;
import org.testng.annotations.Test;
public class CustomQuantilesTest {
/**
* Currently, this test only exercises the classic DoublesSketch, but all the quantiles
* sketches use the same code for getQuantile() and getRank() anyway.
* This same pattern is also part of the CrossCheckQuantilesTest.
* This structure of this test allows more detailed analysis for troubleshooting.
*/
@Test
public void checkQuantilesV400() {
println("org.apache.datasketches.quantiles.CustomQuantilesTest:");
println("Classic DoubleSketch, Version 4.0.0, k=4, N=12");
println("");
//The following for loop creates the following pattern for the sorted view:
// Quantiles: {10,10,20,20,30,30,40,40}
// Weights : { 2, 1, 2, 1, 2, 1, 2, 1}
//This is easy to create from the classic quantiles sketch directly, but for the other
//quantiles sketches it is easier to create by loading the sorted view directly via
//a package-private constructor.
int k = 4;
UpdateDoublesSketch sk = DoublesSketch.builder().setK(k).build();
for (int i = 1; i <= 3; i++) {
for (int q = 10; q <= k * 10; q += 10) {
sk.update(q);
}
}
long N = sk.getN();
DoublesSketchSortedView sv = sk.getSortedView();
double[] quantilesArr = sv.getQuantiles();
long[] cumWtsArr = sv.getCumulativeWeights();
int lenQ = quantilesArr.length;
println("Sorted View:");
printf("%13s %13s %13s\n", "QuantilesArr", "CumWtsArr", "NormRanks");
double normRank;
for (int i = 0; i < lenQ; i++) {
normRank = (double)cumWtsArr[i] / N;
printf("%12.1f%12d%12.4f\n", quantilesArr[i], cumWtsArr[i], normRank);
}
println("");
println("GetRanks, EXCLUSIVE:");
println(" R of the largest Q at the highest index that is < q. If q <= smallest Q => 0");
printf("%12s %12s\n", "Quantiles", "NormRanks");
for (int q = 0; q <= (k * 10) + 5; q += 5) { //create a range of quantiles for input
double normRankEst = sk.getRank(q, EXCLUSIVE);
double normRankTrue = getTrueDoubleRank(cumWtsArr, quantilesArr, q, EXCLUSIVE);
assertEquals(normRankEst, normRankTrue);
printf("%12.1f %12.3f", (double)q, normRankEst);
if (normRankEst != normRankTrue) { println(" " + normRankEst + " != " + normRankTrue); } else { println(""); }
}
println("");
println("GetQuantiles, EXCLUSIVE (round down)");
println(" Q of the smallest rank > r. If r = 1.0 => null or NaN");
printf("%22s %22s %22s %13s\n", "NormRanksIn", "RawNaturalRank", "TrimmedNatRank", "QuantilesEst");
long limit = 4 * N;
double inc = 1.0 / limit;
for (long j = 0; j <= limit; j++) {
double normRankIn = (j * inc);
double qEst = sk.getQuantile(normRankIn, EXCLUSIVE);
double qTrue = getTrueDoubleQuantile(cumWtsArr, quantilesArr, normRankIn, EXCLUSIVE);
assertEquals(qEst, qTrue);
double rawNatRank = normRankIn * N;
double trimNatRank = getNaturalRank(normRankIn, N, EXCLUSIVE);
printf("%22.18f %22.18f %22.18f %13.1f", normRankIn, rawNatRank, trimNatRank, qEst);
if (qEst != qTrue) { println(" " + qEst + " != " +qTrue); } else { println(""); }
}
println("");
println("GetRanks, INCLUSIVE:");
println(" R of the largest Q at the highest index that is <= q. If q < smallest Q => 0");
printf("%12s %12s\n", "Quantiles", "NormRanks");
for (int q = 0; q <= (k * 10) + 5; q += 5) {
double nr = sk.getRank(q, INCLUSIVE);
double nrTrue = getTrueDoubleRank(cumWtsArr, quantilesArr, q, INCLUSIVE);
assertEquals(nr, nrTrue);
printf("%12.1f %12.3f", (double)q, nr);
if (nr != nrTrue) { println(" " + nr + " != " +nrTrue); } else { println(""); }
}
println("");
println("GetQuantiles, INCLUSIVE (round up)");
println(" Q of the smallest rank >= r.");
printf("%22s %22s %22s %13s\n", "NormRanksIn", "RawNaturalRank", "TrimmedNatRank", "QuantilesEst");
inc = 1.0 / limit;
for (long j = 0; j <= limit; j++) {
double normRankIn = (j * inc);
double qEst = sk.getQuantile(normRankIn, INCLUSIVE);
double qTrue = getTrueDoubleQuantile(cumWtsArr, quantilesArr, normRankIn, INCLUSIVE);
assertEquals(qEst, qTrue);
double rawNatRank = normRankIn * N;
double trimNatRank = getNaturalRank(normRankIn, N, INCLUSIVE);
printf("%22.18f %22.18f %22.18f %13.1f", normRankIn, rawNatRank, trimNatRank, qEst);
if (qEst != qTrue) { println(" " + qEst + " != " +qTrue); } else { println(""); }
}
println("");
}
private final static boolean enablePrinting = false;
/**
* @param o the Object to print
*/
static final void print(final Object o) {
if (enablePrinting) { System.out.print(o.toString()); }
}
/**
* @param o the Object to println
*/
static final void println(final Object o) {
if (enablePrinting) { System.out.println(o.toString()); }
}
/**
* @param format the format
* @param args the args
*/
static final void printf(final String format, final Object ...args) {
if (enablePrinting) { System.out.printf(format, args); }
}
}