mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2026-10-12 09:24:52 -05:00
rename sampler
This commit is contained in:
14 files changed
+192
-255
No files matched your search
+5
-1
@@ -240,8 +240,12 @@ Allows for easy branching over multiple functions with specific weights.
|
||||
|
||||
@see [Wikipedia: Zipf's Law](https://en.wikipedia.org/wiki/Zipf's_law) @see [Jim Gray et al.: Quickly Generating Billion-Record Synthetic Databases](https://doi.org/10.1145/191843.191886)
|
||||
|
||||
Uses Jim Gray's constant-time pseudo-sampling approximation after O(numberOfElements)
|
||||
initialization. `numberOfElements` must be at least one, and `exponent` (Gray's theta
|
||||
parameter) must be in `[0.0, 1.0)`. The sampler's internal uniform input is in
|
||||
`[0.0, 1.0)`; an input of exactly `1.0` is converted with `Math.nextDown(1.0)`.
|
||||
|
||||
- int -> Zipf(int: numberOfElements, double: exponent, java.lang.String[]...: modslist) -> int
|
||||
- int -> Zipf(int: numberOfElements, double: exponent, java.lang.String[]...: modslist) -> long
|
||||
- long -> Zipf(int: numberOfElements, double: exponent, java.lang.String[]...: modslist) -> int
|
||||
- long -> Zipf(int: numberOfElements, double: exponent, java.lang.String[]...: modslist) -> long
|
||||
|
||||
+4
-2
@@ -52,7 +52,10 @@ way simply by changing parameters of your testing distributions.
|
||||
Zipf uses the constant-time pseudo-sampling approximation from Jim Gray et al.,
|
||||
with exact weights for its first two ranks. Its normalization constant still
|
||||
requires one pass over the configured elements during initialization, while
|
||||
each sample thereafter takes constant time.
|
||||
each sample thereafter takes constant time. `numberOfElements` must be at least
|
||||
one, and `exponent` (Gray's theta parameter) must be in the range `[0.0, 1.0)`.
|
||||
The sampler accepts uniform input in `[0.0, 1.0]` and converts the exact upper
|
||||
endpoint to `Math.nextDown(1.0)` before evaluating Gray's formula over `[0.0, 1.0)`.
|
||||
|
||||
### Interpolated Samples
|
||||
|
||||
@@ -98,4 +101,3 @@ is used in mathematics and statistics, but more tailored to modern system capabi
|
||||
interval, we simply use the interval of all positive longs. This provides more compatibility with other functions in
|
||||
VirtData, including hashing functions. Internally, this value is automatically converted to a unit interval variate as
|
||||
needed to work well with the distributions from Apache Math.
|
||||
|
||||
@@ -36,16 +36,16 @@ public class IntegratedCurvesTest {
|
||||
|
||||
@Test
|
||||
public void testZipf() {
|
||||
DataMapper<Long> mapper = VirtData.getMapper("Zipf(1000,2) -> long", long.class);
|
||||
DataMapper<Long> mapper = VirtData.getMapper("Zipf(1000,0.99) -> long", long.class);
|
||||
RunData runData = iterateMapperLong(mapper, 10000);
|
||||
logger.debug(runData);
|
||||
|
||||
assertThat(runData.getStats().getPercentile(0.1d)).isCloseTo(1.0, Offset.offset(0.01d));
|
||||
assertThat(runData.getStats().getPercentile(1.0d)).isCloseTo(1.0, Offset.offset(0.01d));
|
||||
assertThat(runData.getStats().getPercentile(10.0d)).isCloseTo(1.0, Offset.offset(0.01d));
|
||||
assertThat(runData.getStats().getPercentile(90.0d)).isCloseTo(6.0, Offset.offset(0.01d));
|
||||
assertThat(runData.getStats().getPercentile(99.0d)).isCloseTo(55.989, Offset.offset(0.01d));
|
||||
assertThat(runData.getStats().getPercentile(99.9d)).isCloseTo(202.999, Offset.offset(0.01d));
|
||||
assertThat(runData.getStats().getPercentile(90.0d)).isBetween(400.0d, 700.0d);
|
||||
assertThat(runData.getStats().getPercentile(99.0d)).isBetween(800.0d, 1000.0d);
|
||||
assertThat(runData.getStats().getPercentile(99.9d)).isBetween(900.0d, 1000.0d);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -69,12 +69,12 @@ public class IntegratedTemporalExamplesTest {
|
||||
@Test
|
||||
public void timeuuidSkewExample() {
|
||||
DataMapper<UUID> uuidgen = VirtData.getMapper(
|
||||
"Zipf(10,2); ToEpochTimeUUID('2017-01-01 23:59:59') -> java.util.UUID;",
|
||||
"Zipf(10,0.99); ToEpochTimeUUID('2017-01-01 23:59:59') -> java.util.UUID;",
|
||||
UUID.class
|
||||
);
|
||||
UUID uuid1 = uuidgen.get(1L);
|
||||
System.out.println(uuid1);
|
||||
assertThat(uuid1).isEqualTo(UUID.fromString("7a4637a0-ee50-1398-8000-000000000000"));
|
||||
assertThat(uuid1).isEqualTo(UUID.fromString("7a4685c0-ee50-1398-8000-000000000000"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,12 +159,12 @@ public class IntegratedTemporalExamplesTest {
|
||||
@Test
|
||||
public void manualOffsetAndSkewedDateTimeExample() {
|
||||
DataMapper<DateTime> dateTimeMapper = VirtData.getMapper(
|
||||
"Zipf(10,2); StartingEpochMillis('2015-01-01'); ToDateTime()-> org.joda.time.DateTime;",
|
||||
"Zipf(10,0.99); StartingEpochMillis('2015-01-01'); ToDateTime()-> org.joda.time.DateTime;",
|
||||
DateTime.class
|
||||
);
|
||||
DateTime dt = dateTimeMapper.get(6L);
|
||||
assertThat(dt).isEqualTo(
|
||||
new DateTime(2015, 1, 1, 0, 0, 0, 2,
|
||||
new DateTime(2015, 1, 1, 0, 0, 0, 4,
|
||||
DateTimeZone.UTC)
|
||||
);
|
||||
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) nosqlbench
|
||||
*
|
||||
* Licensed 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 io.nosqlbench.virtdata.library.curves4.discrete.common;
|
||||
|
||||
import java.util.function.DoubleToIntFunction;
|
||||
|
||||
/**
|
||||
* The constant-time approximate inverse Zipf sampler described by Jim Gray et al. in
|
||||
* <a href="https://doi.org/10.1145/191843.191886">Quickly Generating Billion-Record
|
||||
* Synthetic Databases</a>.
|
||||
*
|
||||
* <p>The first two ranks use their exact cumulative weights. The remaining ranks use
|
||||
* the paper's corrected continuous approximation. Parameter calculation takes one pass
|
||||
* over the ranks ({@code O(numberOfElements)}); each subsequent sample takes constant
|
||||
* time ({@code O(1)}).</p>
|
||||
*
|
||||
* <p>This implementation uses the parameter range defined by Gray's algorithm:
|
||||
* {@code numberOfElements >= 1} and {@code 0.0 <= exponent < 1.0}. The sampler accepts
|
||||
* a uniform variate in {@code [0.0, 1.0]}; the upper endpoint is converted to
|
||||
* {@code Math.nextDown(1.0)} before evaluating Gray's formula over {@code [0.0, 1.0)}.</p>
|
||||
*/
|
||||
public final class FastZipfSampler implements DoubleToIntFunction {
|
||||
|
||||
private final int numberOfElements;
|
||||
private final double alpha;
|
||||
private final double[] cdf;
|
||||
private final double eta;
|
||||
|
||||
/**
|
||||
* Creates a sampler for a finite Zipf domain.
|
||||
*
|
||||
* @param numberOfElements the number of ranks, starting at rank one
|
||||
* @param exponent Gray's theta parameter
|
||||
* @throws IllegalArgumentException if {@code numberOfElements < 1}, or if
|
||||
* {@code exponent} is not in {@code [0.0, 1.0)}
|
||||
*/
|
||||
public FastZipfSampler(int numberOfElements, double exponent) {
|
||||
if (numberOfElements <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"numberOfElements must be greater than zero: " + numberOfElements);
|
||||
}
|
||||
if (!Double.isFinite(exponent) || exponent < 0.0d || exponent >= 1.0d) {
|
||||
throw new IllegalArgumentException(
|
||||
"exponent must be in the range [0.0, 1.0): " + exponent);
|
||||
}
|
||||
|
||||
this.numberOfElements = numberOfElements;
|
||||
|
||||
double zetan = exponent == 0.0d
|
||||
? numberOfElements
|
||||
: generalizedHarmonic(numberOfElements, exponent);
|
||||
double zeta2 = numberOfElements == 1
|
||||
? 1.0d
|
||||
: 1.0d + Math.pow(0.5d, exponent);
|
||||
|
||||
this.cdf = new double[]{1.0d / zetan, zeta2 / zetan};
|
||||
this.alpha = 1.0d / (1.0d - exponent);
|
||||
|
||||
if (numberOfElements <= 2) {
|
||||
this.eta = 0.0d;
|
||||
} else {
|
||||
double oneMinusExponent = 1.0d - exponent;
|
||||
double numerator = -Math.expm1(
|
||||
oneMinusExponent * Math.log(2.0d / numberOfElements));
|
||||
this.eta = numerator / (1.0d - cdf[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a rank using a uniform variate.
|
||||
*
|
||||
* @param uniform a finite value in {@code [0.0, 1.0]}
|
||||
* @return a rank in {@code [1, numberOfElements]}
|
||||
* @throws IllegalArgumentException if {@code uniform} is not in {@code [0.0, 1.0]}
|
||||
*/
|
||||
@Override
|
||||
public int applyAsInt(double uniform) {
|
||||
if (!Double.isFinite(uniform) || uniform < 0.0d || uniform > 1.0d) {
|
||||
throw new IllegalArgumentException(
|
||||
"uniform must be in the range [0.0, 1.0]: " + uniform);
|
||||
}
|
||||
|
||||
if (uniform == 1.0d) {
|
||||
uniform = Math.nextDown(uniform);
|
||||
}
|
||||
|
||||
for (int i = 0; i < cdf.length; i++) {
|
||||
if (uniform < cdf[i]) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
double rank = (double) numberOfElements * Math.exp(
|
||||
alpha * Math.log1p(eta * (uniform - 1.0d)));
|
||||
long sample = 1L + (long) rank;
|
||||
|
||||
return (int) Math.max(3L, Math.min(numberOfElements, sample));
|
||||
}
|
||||
|
||||
private static double generalizedHarmonic(int numberOfElements, double exponent) {
|
||||
double sum = 0.0d;
|
||||
for (int rank = numberOfElements; rank >= 1; rank--) {
|
||||
sum += Math.pow(rank, -exponent);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) nosqlbench
|
||||
*
|
||||
* Licensed 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 io.nosqlbench.virtdata.library.curves4.discrete.common;
|
||||
|
||||
import java.util.function.DoubleToIntFunction;
|
||||
|
||||
/**
|
||||
* The constant-time approximate inverse Zipf sampler described by Jim Gray et al. in
|
||||
* <a href="https://doi.org/10.1145/191843.191886">Quickly Generating Billion-Record
|
||||
* Synthetic Databases</a>.
|
||||
*
|
||||
* <p>The first two ranks use their exact cumulative weights. The remaining ranks use
|
||||
* the paper's corrected continuous approximation. Parameter calculation takes one pass
|
||||
* over the ranks; each subsequent sample takes constant time. The limiting form is used
|
||||
* when the exponent is one, and the same finite-domain approximation is retained for
|
||||
* larger exponents to preserve the existing Zipf mapper parameter range.</p>
|
||||
*/
|
||||
public final class GrayZipfSampler implements DoubleToIntFunction {
|
||||
|
||||
private final int numberOfElements;
|
||||
private final double exponent;
|
||||
private final double zetan;
|
||||
private final double zeta2;
|
||||
private final double eta;
|
||||
|
||||
public GrayZipfSampler(int numberOfElements, double exponent) {
|
||||
if (numberOfElements <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"numberOfElements must be greater than zero: " + numberOfElements);
|
||||
}
|
||||
if (!Double.isFinite(exponent) || exponent < 0.0d) {
|
||||
throw new IllegalArgumentException(
|
||||
"exponent must be finite and non-negative: " + exponent);
|
||||
}
|
||||
|
||||
this.numberOfElements = numberOfElements;
|
||||
this.exponent = exponent;
|
||||
this.zetan = exponent == 0.0d
|
||||
? numberOfElements
|
||||
: generalizedHarmonic(numberOfElements, exponent);
|
||||
this.zeta2 = numberOfElements == 1 ? 1.0d : 1.0d + Math.pow(0.5d, exponent);
|
||||
|
||||
if (numberOfElements <= 2 || exponent == 1.0d || zetan == zeta2) {
|
||||
this.eta = 0.0d;
|
||||
} else {
|
||||
double oneMinusExponent = 1.0d - exponent;
|
||||
double numerator = -Math.expm1(
|
||||
oneMinusExponent * Math.log(2.0d / numberOfElements));
|
||||
this.eta = numerator / (1.0d - zeta2 / zetan);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int applyAsInt(double uniform) {
|
||||
if (uniform <= 0.0d || numberOfElements == 1) {
|
||||
return 1;
|
||||
}
|
||||
if (uniform >= 1.0d) {
|
||||
return numberOfElements;
|
||||
}
|
||||
if (exponent == 0.0d) {
|
||||
return 1 + (int) (uniform * numberOfElements);
|
||||
}
|
||||
|
||||
double weighted = uniform * zetan;
|
||||
if (weighted < 1.0d) {
|
||||
return 1;
|
||||
}
|
||||
if (weighted < zeta2 || numberOfElements == 2) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
double approximatedRank;
|
||||
if (exponent == 1.0d) {
|
||||
double harmonicTailScale = Math.log(numberOfElements / 2.0d)
|
||||
* zetan / (zetan - zeta2);
|
||||
approximatedRank = numberOfElements
|
||||
* Math.exp(harmonicTailScale * (uniform - 1.0d));
|
||||
} else {
|
||||
double oneMinusExponent = 1.0d - exponent;
|
||||
approximatedRank = numberOfElements * Math.exp(
|
||||
Math.log1p(eta * (uniform - 1.0d)) / oneMinusExponent);
|
||||
}
|
||||
|
||||
long sample = 1L + (long) approximatedRank;
|
||||
return (int) Math.max(3L, Math.min(numberOfElements, sample));
|
||||
}
|
||||
|
||||
private static double generalizedHarmonic(int numberOfElements, double exponent) {
|
||||
double sum = 0.0d;
|
||||
for (int rank = numberOfElements; rank >= 1; rank--) {
|
||||
sum += Math.pow(rank, -exponent);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
+8
-4
@@ -19,18 +19,22 @@ package io.nosqlbench.virtdata.library.curves4.discrete.int_int;
|
||||
import io.nosqlbench.virtdata.api.annotations.Categories;
|
||||
import io.nosqlbench.virtdata.api.annotations.Category;
|
||||
import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper;
|
||||
import io.nosqlbench.virtdata.library.curves4.discrete.common.GrayZipfSampler;
|
||||
import io.nosqlbench.virtdata.library.curves4.discrete.common.FastZipfSampler;
|
||||
|
||||
/**
|
||||
* Jim Gray's constant-time approximate Zipf sampler.
|
||||
*
|
||||
* <p>{@code numberOfElements} must be at least one and {@code exponent}, Gray's theta
|
||||
* parameter, must be in {@code [0.0, 1.0)}. Initialization is O(numberOfElements) and
|
||||
* each computed sample is O(1).</p>
|
||||
*
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Zipf's_law">Wikipedia: Zipf's Law</a>
|
||||
*
|
||||
* @see <a href="https://doi.org/10.1145/191843.191886">Jim Gray et al.: Quickly Generating Billion-Record Synthetic Databases</a>
|
||||
*
|
||||
*/
|
||||
@ThreadSafeMapper
|
||||
@Categories({Category.distributions})
|
||||
public class Zipf extends IntToIntDiscreteCurve {
|
||||
public Zipf(int numberOfElements, double exponent, String... modslist) {
|
||||
super(new GrayZipfSampler(numberOfElements, exponent), modslist);
|
||||
super(new FastZipfSampler(numberOfElements, exponent), modslist);
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -19,12 +19,21 @@ package io.nosqlbench.virtdata.library.curves4.discrete.int_long;
|
||||
import io.nosqlbench.virtdata.api.annotations.Categories;
|
||||
import io.nosqlbench.virtdata.api.annotations.Category;
|
||||
import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper;
|
||||
import io.nosqlbench.virtdata.library.curves4.discrete.common.GrayZipfSampler;
|
||||
import io.nosqlbench.virtdata.library.curves4.discrete.common.FastZipfSampler;
|
||||
|
||||
/**
|
||||
* Jim Gray's constant-time approximate Zipf sampler.
|
||||
*
|
||||
* <p>{@code numberOfElements} must be at least one and {@code exponent}, Gray's theta
|
||||
* parameter, must be in {@code [0.0, 1.0)}. Initialization is O(numberOfElements) and
|
||||
* each computed sample is O(1).</p>
|
||||
*
|
||||
* @see <a href="https://doi.org/10.1145/191843.191886">Jim Gray et al.: Quickly Generating Billion-Record Synthetic Databases</a>
|
||||
*/
|
||||
@ThreadSafeMapper
|
||||
@Categories({Category.distributions})
|
||||
public class Zipf extends IntToLongDiscreteCurve {
|
||||
public Zipf(int numberOfElements, double exponent, String... modslist) {
|
||||
super(new GrayZipfSampler(numberOfElements, exponent), modslist);
|
||||
super(new FastZipfSampler(numberOfElements, exponent), modslist);
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -19,12 +19,21 @@ package io.nosqlbench.virtdata.library.curves4.discrete.long_int;
|
||||
import io.nosqlbench.virtdata.api.annotations.Categories;
|
||||
import io.nosqlbench.virtdata.api.annotations.Category;
|
||||
import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper;
|
||||
import io.nosqlbench.virtdata.library.curves4.discrete.common.GrayZipfSampler;
|
||||
import io.nosqlbench.virtdata.library.curves4.discrete.common.FastZipfSampler;
|
||||
|
||||
/**
|
||||
* Jim Gray's constant-time approximate Zipf sampler.
|
||||
*
|
||||
* <p>{@code numberOfElements} must be at least one and {@code exponent}, Gray's theta
|
||||
* parameter, must be in {@code [0.0, 1.0)}. Initialization is O(numberOfElements) and
|
||||
* each computed sample is O(1).</p>
|
||||
*
|
||||
* @see <a href="https://doi.org/10.1145/191843.191886">Jim Gray et al.: Quickly Generating Billion-Record Synthetic Databases</a>
|
||||
*/
|
||||
@ThreadSafeMapper
|
||||
@Categories({Category.distributions})
|
||||
public class Zipf extends LongToIntDiscreteCurve {
|
||||
public Zipf(int numberOfElements, double exponent, String... modslist) {
|
||||
super(new GrayZipfSampler(numberOfElements, exponent), modslist);
|
||||
super(new FastZipfSampler(numberOfElements, exponent), modslist);
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -19,12 +19,21 @@ package io.nosqlbench.virtdata.library.curves4.discrete.long_long;
|
||||
import io.nosqlbench.virtdata.api.annotations.Categories;
|
||||
import io.nosqlbench.virtdata.api.annotations.Category;
|
||||
import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper;
|
||||
import io.nosqlbench.virtdata.library.curves4.discrete.common.GrayZipfSampler;
|
||||
import io.nosqlbench.virtdata.library.curves4.discrete.common.FastZipfSampler;
|
||||
|
||||
/**
|
||||
* Jim Gray's constant-time approximate Zipf sampler.
|
||||
*
|
||||
* <p>{@code numberOfElements} must be at least one and {@code exponent}, Gray's theta
|
||||
* parameter, must be in {@code [0.0, 1.0)}. Initialization is O(numberOfElements) and
|
||||
* each computed sample is O(1).</p>
|
||||
*
|
||||
* @see <a href="https://doi.org/10.1145/191843.191886">Jim Gray et al.: Quickly Generating Billion-Record Synthetic Databases</a>
|
||||
*/
|
||||
@ThreadSafeMapper
|
||||
@Categories({Category.distributions})
|
||||
public class Zipf extends LongToLongDiscreteCurve {
|
||||
public Zipf(int numberOfElements, double exponent, String... modslist) {
|
||||
super(new GrayZipfSampler(numberOfElements, exponent), modslist);
|
||||
super(new FastZipfSampler(numberOfElements, exponent), modslist);
|
||||
}
|
||||
}
|
||||
+10
-12
@@ -22,7 +22,6 @@ import org.apache.commons.math4.legacy.stat.descriptive.DescriptiveStatistics;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.assertj.core.data.Offset;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
|
||||
@@ -38,33 +37,32 @@ public class IntegerDistributionsValuesTest {
|
||||
private final static Logger logger = LogManager.getLogger(IntegerDistributionsValuesTest.class);
|
||||
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
public void testComputedZipf() {
|
||||
RunData runData = iterateMapperLong(new Zipf(10000,2.0), 10000);
|
||||
RunData runData = iterateMapperLong(new Zipf(10000, 0.99, "compute"), 10000);
|
||||
logger.debug(runData);
|
||||
assertThat(runData.getFractionalPercentile(0.6D))
|
||||
.isCloseTo(1.0D, Offset.offset(0.0001D));
|
||||
.isBetween(150.0D, 260.0D);
|
||||
assertThat(runData.getFractionalPercentile(0.7D))
|
||||
.isCloseTo(2.0D, Offset.offset(0.0001D));
|
||||
.isBetween(430.0D, 660.0D);
|
||||
assertThat(runData.getFractionalPercentile(0.8D))
|
||||
.isCloseTo(3.0D, Offset.offset(0.0001D));
|
||||
.isBetween(1150.0D, 1750.0D);
|
||||
assertThat(runData.getFractionalPercentile(0.9D))
|
||||
.isCloseTo(5.0D, Offset.offset(0.0001D));
|
||||
.isBetween(3000.0D, 4600.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterpolatedZipf() {
|
||||
RunData runData = iterateMapperLong(new Zipf(10000,2.0), 10000);
|
||||
RunData runData = iterateMapperLong(new Zipf(10000, 0.99), 10000);
|
||||
logger.debug(runData);
|
||||
assertThat(runData.getFractionalPercentile(0.6D))
|
||||
.isCloseTo(1.0D, Offset.offset(0.0001D));
|
||||
.isBetween(150.0D, 260.0D);
|
||||
assertThat(runData.getFractionalPercentile(0.7D))
|
||||
.isCloseTo(2.0D, Offset.offset(0.0001D));
|
||||
.isBetween(430.0D, 660.0D);
|
||||
assertThat(runData.getFractionalPercentile(0.8D))
|
||||
.isCloseTo(3.0D, Offset.offset(0.0001D));
|
||||
.isBetween(1150.0D, 1750.0D);
|
||||
assertThat(runData.getFractionalPercentile(0.9D))
|
||||
.isCloseTo(5.0D, Offset.offset(0.0001D));
|
||||
.isBetween(3000.0D, 4600.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) nosqlbench
|
||||
*
|
||||
* Licensed 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 io.nosqlbench.virtdata.library.curves4.discrete.common;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
@Tag("unit")
|
||||
class GrayZipfSamplerTest {
|
||||
|
||||
@Test
|
||||
void usesGrayApproximationAfterFirstTwoRanks() {
|
||||
GrayZipfSampler sampler = new GrayZipfSampler(10_000, 0.5d);
|
||||
|
||||
assertThat(sampler.applyAsInt(0.1d)).isEqualTo(111);
|
||||
assertThat(sampler.applyAsInt(0.5d)).isEqualTo(2_529);
|
||||
assertThat(sampler.applyAsInt(0.9d)).isEqualTo(8_111);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givesFirstTwoRanksTheirExactWeights() {
|
||||
int elements = 1_000;
|
||||
double exponent = 0.75d;
|
||||
GrayZipfSampler sampler = new GrayZipfSampler(elements, exponent);
|
||||
double zetan = generalizedHarmonic(elements, exponent);
|
||||
double firstCutoff = 1.0d / zetan;
|
||||
double secondCutoff = (1.0d + Math.pow(0.5d, exponent)) / zetan;
|
||||
|
||||
assertThat(sampler.applyAsInt(Math.nextDown(firstCutoff))).isEqualTo(1);
|
||||
assertThat(sampler.applyAsInt(firstCutoff)).isEqualTo(2);
|
||||
assertThat(sampler.applyAsInt(Math.nextDown(secondCutoff))).isEqualTo(2);
|
||||
assertThat(sampler.applyAsInt(secondCutoff)).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void supportsExponentOneAndLargerExistingExponents() {
|
||||
GrayZipfSampler exponentOne = new GrayZipfSampler(10_000, 1.0d);
|
||||
GrayZipfSampler exponentTwo = new GrayZipfSampler(10_000, 2.0d);
|
||||
|
||||
assertThat(exponentOne.applyAsInt(0.5d)).isEqualTo(66);
|
||||
assertThat(exponentOne.applyAsInt(0.9d)).isEqualTo(3_658);
|
||||
assertThat(exponentTwo.applyAsInt(0.7d)).isEqualTo(2);
|
||||
assertThat(exponentTwo.applyAsInt(0.9d)).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void staysMonotonicAndWithinBounds() {
|
||||
for (double exponent : new double[]{0.0d, 0.5d, 0.99d, 1.0d, 2.0d, 5.0d}) {
|
||||
GrayZipfSampler sampler = new GrayZipfSampler(10_000, exponent);
|
||||
int previous = 1;
|
||||
for (int point = 0; point <= 10_000; point++) {
|
||||
int sample = sampler.applyAsInt(point / 10_000.0d);
|
||||
assertThat(sample).isBetween(1, 10_000).isGreaterThanOrEqualTo(previous);
|
||||
previous = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void handlesSmallDomainsAndUnitIntervalBounds() {
|
||||
GrayZipfSampler oneElement = new GrayZipfSampler(1, 0.99d);
|
||||
GrayZipfSampler twoElements = new GrayZipfSampler(2, 0.99d);
|
||||
GrayZipfSampler manyElements = new GrayZipfSampler(10_000, 0.99d);
|
||||
GrayZipfSampler maximumUniformDomain = new GrayZipfSampler(Integer.MAX_VALUE, 0.0d);
|
||||
|
||||
assertThat(oneElement.applyAsInt(0.0d)).isEqualTo(1);
|
||||
assertThat(oneElement.applyAsInt(1.0d)).isEqualTo(1);
|
||||
assertThat(twoElements.applyAsInt(0.0d)).isEqualTo(1);
|
||||
assertThat(twoElements.applyAsInt(1.0d)).isEqualTo(2);
|
||||
assertThat(manyElements.applyAsInt(0.0d)).isEqualTo(1);
|
||||
assertThat(manyElements.applyAsInt(1.0d)).isEqualTo(10_000);
|
||||
assertThat(maximumUniformDomain.applyAsInt(1.0d)).isEqualTo(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidParameters() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new GrayZipfSampler(0, 0.5d));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new GrayZipfSampler(10, -0.5d));
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new GrayZipfSampler(10, Double.NaN));
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new GrayZipfSampler(10, Double.POSITIVE_INFINITY));
|
||||
}
|
||||
|
||||
private static double generalizedHarmonic(int elements, double exponent) {
|
||||
double sum = 0.0d;
|
||||
for (int rank = elements; rank >= 1; rank--) {
|
||||
sum += Math.pow(rank, -exponent);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -27,10 +27,10 @@ public class ZipfTest {
|
||||
@Disabled
|
||||
public void testZipfMatrix() {
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
for (int i = 1; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int elements = (int) Math.pow(10,j);
|
||||
double exponent = (double) i+1;
|
||||
double exponent = i / 10.0d;
|
||||
System.out.println("i:" + i + " j:" + j + " elements:" + elements + " exp:" + exponent);
|
||||
long startAt = System.nanoTime();
|
||||
Zipf z = new Zipf(elements, exponent, "compute", "map");
|
||||
|
||||
@@ -81,7 +81,7 @@ bindings:
|
||||
poisson: Poisson(5.0)
|
||||
# https://en.wikipedia.org/wiki/Zipf%27s_law
|
||||
# (int elements, double exponent)
|
||||
zipf: Zipf(10,5.0)
|
||||
zipf: Zipf(10,0.99)
|
||||
# https://en.wikipedia.org/wiki/Binomial_distribution
|
||||
# (int trials, double probability)
|
||||
binomial: Binomial(8,0.5)
|
||||
|
||||
Reference in new issue
Block a user