more function in and out types

This commit is contained in:
Jonathan Shook 2025-02-18 17:56:38 -06:00
parent 1f45d0b850
commit cb4553eb40
6 changed files with 272 additions and 38 deletions

View File

@ -0,0 +1,78 @@
package io.nosqlbench.virtdata.library.basics.shared.from_double.to_long;
/*
* 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.
*/
import io.nosqlbench.virtdata.api.annotations.Categories;
import io.nosqlbench.virtdata.api.annotations.Category;
import io.nosqlbench.virtdata.api.annotations.Example;
import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper;
import io.nosqlbench.virtdata.api.bindings.VirtDataFunctions;
import io.nosqlbench.virtdata.library.basics.core.stathelpers.AliasSamplerDoubleLong;
import io.nosqlbench.virtdata.library.basics.core.stathelpers.EvProbLongDouble;
import io.nosqlbench.virtdata.library.basics.shared.from_long.to_double.EmpiricalDistribution;
import io.nosqlbench.virtdata.library.basics.shared.from_long.to_double.HashRange;
import java.util.ArrayList;
import java.util.List;
import java.util.function.DoubleToLongFunction;
import java.util.function.LongToDoubleFunction;
import java.util.function.LongUnaryOperator;
@ThreadSafeMapper
@Categories(Category.distributions)
public class IntervalHistribution implements LongUnaryOperator {
private final UnitHistribution sampler;
private final LongToDoubleFunction samplePointF;
@Example({"IntervalHistribution('50 25 13 12')", "implied frequencies of 0:50 1:25 2:13 3:12"})
@Example({
"IntervalHistribution('234:50 33:25 17:13 3:12')",
"labeled frequencies; 234,33,17,3 are labels, and 50,25,13,12 are weights"
})
public IntervalHistribution(String freqs, Object samplePointFunc) {
this.sampler = new UnitHistribution(freqs);
this.samplePointF = VirtDataFunctions.adapt(
samplePointFunc,
LongToDoubleFunction.class,
double.class,
false
);
}
public IntervalHistribution(String freqs) {
this(freqs,new HashRange(0.0d,1.0d));
}
private static List<EvProbLongDouble> genEvents(long[] freqs) {
ArrayList<EvProbLongDouble> events = new ArrayList<>();
for (int i = 0; i < freqs.length; i++) {
events.add(new EvProbLongDouble(i, freqs[i]));
}
return events;
}
@Override
public long applyAsLong(long operand) {
double samplePoint = this.samplePointF.applyAsDouble(operand);
return this.sampler.applyAsLong(samplePoint);
}
}

View File

@ -1,4 +1,4 @@
package io.nosqlbench.virtdata.library.basics.shared.from_long.to_double;
package io.nosqlbench.virtdata.library.basics.shared.from_double.to_long;
/*
* Copyright (c) nosqlbench
@ -18,16 +18,17 @@ package io.nosqlbench.virtdata.library.basics.shared.from_long.to_double;
*/
import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.virtdata.api.annotations.Categories;
import io.nosqlbench.virtdata.api.annotations.Category;
import io.nosqlbench.virtdata.api.annotations.Example;
import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper;
import io.nosqlbench.virtdata.library.basics.core.stathelpers.AliasSamplerDoubleLong;
import io.nosqlbench.virtdata.library.basics.core.stathelpers.EvProbLongDouble;
import io.nosqlbench.virtdata.library.basics.shared.from_long.to_double.EmpiricalDistribution;
import java.util.ArrayList;
import java.util.List;
import java.util.function.DoubleToLongFunction;
/// Empirical Histribution is a portmanteau name to capture the
/// concept of an empirical distribution based on a discrete histogram.
@ -38,14 +39,14 @@ import java.util.List;
/// want to represent accurately.
@ThreadSafeMapper
@Categories(Category.distributions)
public class EmpiricalHistribution extends AliasSamplerDoubleLong {
public class UnitHistribution extends AliasSamplerDoubleLong implements DoubleToLongFunction {
@Example({"EmpiricalHistribution('50 25 13 12')", "implied frequencies of 0:50 1:25 2:13 3:12"})
@Example({"UnitHistribution('50 25 13 12')", "implied frequencies of 0:50 1:25 2:13 3:12"})
@Example({
"EmpiricalHistribution('234:50 33:25 17:13 3:12')",
"UnitHistribution('234:50 33:25 17:13 3:12')",
"labeled frequencies; 234,33,17,3 are labels, and 50,25,13,12 are weights"
})
public EmpiricalHistribution(String freqs) {
public UnitHistribution(String freqs) {
List<EvProbLongDouble> events = new ArrayList<>();
boolean labeled = (freqs.contains(":"));
@ -57,20 +58,21 @@ public class EmpiricalHistribution extends AliasSamplerDoubleLong {
"If any elements are labeled, all elements must be:" + freqs);
}
long id = labeled ? Long.parseLong(parts[0]) : i;
events.add(new EvProbLongDouble(id, Long.parseLong(parts[1])));
long weight = Long.parseLong(parts[labeled ? 1 : 0]);
events.add(new EvProbLongDouble(id, weight));
}
super(events);
}
public EmpiricalHistribution(long... freqs) {
super(genEvents(freqs));
}
private static List<EvProbLongDouble> genEvents(long[] freqs) {
ArrayList<EvProbLongDouble> events = new ArrayList<>();
for (int i = 0; i < freqs.length; i++) {
events.add(new EvProbLongDouble(i, freqs[i]));
}
return events;
}
// public UnitHistribution(long... freqs) {
// super(genEvents(freqs));
// }
//
// private static List<EvProbLongDouble> genEvents(long[] freqs) {
// ArrayList<EvProbLongDouble> events = new ArrayList<>();
// for (int i = 0; i < freqs.length; i++) {
// events.add(new EvProbLongDouble(i, freqs[i]));
// }
// return events;
// }
}

View File

@ -2,13 +2,13 @@ package io.nosqlbench.virtdata.library.basics.shared.from_long.to_double;
/*
* 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

View File

@ -0,0 +1,122 @@
package io.nosqlbench.virtdata.library.basics.shared.from_long.to_long;
/*
* 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.
*/
import io.nosqlbench.virtdata.api.annotations.Categories;
import io.nosqlbench.virtdata.api.annotations.Category;
import io.nosqlbench.virtdata.api.annotations.Example;
import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper;
import java.util.function.LongToDoubleFunction;
import java.util.function.LongUnaryOperator;
/// Blends two functions with a domain of 0..Long.MAX_VALUE as the input interval,
/// and a double output. The output value is interpolated between the output value
/// of the two according to the mix function. When the mix function yields a value
/// of 0.0, then the mix is turned _fully counter-clockwise_., or fully on the first provided
/// function. When the value is 1.0, the mix is turned all the clockwise, or fully on the second
/// provided function.
///
/// If there are only two inner functions provided to HashMix, then it will default to
/// sampling random mixes at a randomized sample point. In other words, the variates
/// provided will be somewhere between the two curves on the unit interval. This is a simple way
/// to sample between two curves by default. The yielded value will be greater than or equal to
/// the lower of the two values at any point, and less than or equal to the greater of either.
///
/// If a third parameter is provided to control the mix, then the mix can be set directly as a
/// unit interval. (The dial goes from 0.0 to 1.0). Any double or float value here will suffice.
/// You can use this when you want to have a test parameter that slews between two modeled
/// shapes. You can alternately provide any other function which can be coerced to a LongToDouble
/// function as a dynamic mix control. IFF such a function is provided, it must also be responsible
/// for hashing the input value if pseudo-randomness is desired.
///
/// If a fourth parameter is provided, the sample point can also be controlled. By default, the
/// values on the provided curves will be sampled pseudo-randomly. However, a fourth parameter
/// can override this just like the mix ratio. As well, if you provide a value or function
/// to control the sample point, you are also responsible for any hashing needed to sample across
/// the whole space of possible values.
///
/// The flexibility of these two parameters provides a substantial amount of flexibility. You
/// can, for example:
///
/// - sample variates between two curves
/// - sample variates at a selected morphing step between the curves
/// - sample variates between two curves on a subsection of the unit interval
/// - sample variates within a defined band gap of the two curves
@ThreadSafeMapper
@Categories(Category.functional)
public class HashMix implements LongUnaryOperator {
private io.nosqlbench.virtdata.library.basics.shared.from_long.to_double.HashMix mixer;
@Example({
"IntervalHashMix(Func1(),Func2())",
"yield samples between func1 and func2 values at some random random sample point x"
})
@Example({
"IntervalHashMix(Func1(),Func2(),0.25d)",
"yield samples which are 25% from the sample values for func1 and func2 at some random "
+ "sample point x"
})
@Example({
"IntervalHashMix(Func1(),Func2(),HashRange(0.25d,0.75d)",
"yield samples between 25% and 75% from func1 to func2 values at some random sample point x"
})
@Example({
"IntervalHashMix(Func1(),Func2(),0.0d,ScaledDouble())",
"access Func1 values as if it were the only one provided. ScaledDouble adds no "
+ "randomization the input value, but it does map it to the sample domain of 0.0d-0.1d."
})
public HashMix(Object curve1F, Object curve2F, Object mixPointF, Object samplePointF) {
this.mixer = new io.nosqlbench.virtdata.library.basics.shared.from_long.to_double.HashMix(curve1F, curve2F, mixPointF, samplePointF);
}
public HashMix(Object curve1F, Object curve2F, Object mixPointF) {
this(
curve1F,
curve2F,
mixPointF,
new HashRange(Long.MAX_VALUE)
);
}
public HashMix(Object curve1F, Object curve2F) {
this(
curve1F,
curve2F,
new io.nosqlbench.virtdata.library.basics.shared.from_long.to_double.HashRange(0.0d, 1.0d),
new HashRange(Long.MAX_VALUE)
);
}
public HashMix(LongToDoubleFunction f1, LongToDoubleFunction f2) {
this(
f1,
f2,
new io.nosqlbench.virtdata.library.basics.shared.from_long.to_double.HashRange(0.0d, 1.0d),
new HashRange(Long.MAX_VALUE)
);
}
@Override
public long applyAsLong(long value) {
return (long) mixer.applyAsDouble(value);
}
}

View File

@ -2,13 +2,13 @@ package io.nosqlbench.virtdata.library.basics.shared.from_long.to_double;
/*
* 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
@ -22,6 +22,7 @@ import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Test;
import java.util.function.LongToDoubleFunction;
import java.util.function.LongUnaryOperator;
import static org.assertj.core.api.Assertions.assertThat;
@ -33,12 +34,16 @@ public class HashMixTest {
@Test
public void testLinearMix() {
HashMix um1 = new HashMix(TO_UNIT_INTERVAL, TO_UNIT_INTERVAL);
for (long i = 1; i < (Long.MAX_VALUE >> 1); i *= 2) {
assertThat(um1.applyAsDouble(i)).isEqualTo(
TO_UNIT_INTERVAL.applyAsDouble(i),
Offset.offset(0.0000001d)
);
DoubleHolder dh = new DoubleHolder();
LongHolder lh = new LongHolder();
HashMix um1 = new HashMix(TO_UNIT_INTERVAL, TO_UNIT_INTERVAL,dh, lh);
for (long i = 0; i >= 0L; i += 1L << 58) {
double fraction = TO_UNIT_INTERVAL.applyAsDouble(i);
lh.setValue(i);
dh.setValue(fraction);
double actual = um1.applyAsDouble(i);
double expected = TO_UNIT_INTERVAL.applyAsDouble(i);
assertThat(actual).isEqualTo(expected, Offset.offset(0.0000001d));
}
}
@ -46,11 +51,37 @@ public class HashMixTest {
public void testCrossfadeMix() {
LongToDoubleFunction rampdown1 = l -> 1.0d - TO_UNIT_INTERVAL.applyAsDouble(l);
LongToDoubleFunction rampdown2 = l -> 2.0d - TO_UNIT_INTERVAL.applyAsDouble(l);
HashMix um1 = new HashMix(rampdown1,rampdown2);
for (long i = 1<<24; i <= Long.MAX_VALUE>>1; i<<=1) {
HashMix um1 = new HashMix(rampdown1, rampdown2);
for (long i = 0; i >= 0L; i += 1L << 58) {
double value = um1.applyAsDouble(i);
assertThat(um1.applyAsDouble(i)).isEqualTo(1.0d, Offset.offset(0.0000001d));
}
}
private class DoubleHolder implements LongToDoubleFunction {
private double value;
@Override
public double applyAsDouble(long value) {
return this.value;
}
public void setValue(double value) {
this.value = value;
}
}
private class LongHolder implements LongUnaryOperator {
private long value;
@Override
public long applyAsLong(long operand) {
return this.value;
}
public void setValue(long value) {
this.value = value;
}
}
}

View File

@ -2,13 +2,13 @@ package io.nosqlbench.virtdata.library.basics.shared.from_long.to_double;
/*
* 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
@ -18,6 +18,7 @@ package io.nosqlbench.virtdata.library.basics.shared.from_long.to_double;
*/
import io.nosqlbench.virtdata.library.basics.shared.from_double.to_long.UnitHistribution;
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Test;
@ -26,17 +27,17 @@ import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class EmpiricalHistributionTest {
public class UnitHistributionTest {
@Test
public void testUniformSyntaxRequired() {
assertThatThrownBy(() -> new EmpiricalHistribution("1 2:2 3:3")).hasMessageContaining(
assertThatThrownBy(() -> new UnitHistribution("1 2:2 3:3")).hasMessageContaining(
"all elements must be");
}
@Test
public void testBasicHistribution() {
EmpiricalHistribution h = new EmpiricalHistribution("1:1 2:2 3:3");
UnitHistribution h = new UnitHistribution("1:1 2:2 3:3");
long[] counts = new long[10];
int total=1000000;
HashRange hr = new HashRange(0.0d, 1.0d);