dev.marksman.kraftwerk.frequency.FrequencyMapN Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kraftwerk Show documentation
Show all versions of kraftwerk Show documentation
Purely functional random data generation
The newest version!
package dev.marksman.kraftwerk.frequency;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.builtin.fn2.Map;
import dev.marksman.kraftwerk.Generator;
import dev.marksman.kraftwerk.Weighted;
import java.util.TreeMap;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons;
import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
import static dev.marksman.kraftwerk.Generators.generateLongIndex;
final class FrequencyMapN implements FrequencyMap {
private final Iterable>> entries;
private Generator cachedGenerator;
@SuppressWarnings("unchecked")
private FrequencyMapN(Iterable extends Weighted extends Generator extends A>>> entries) {
this.entries = (Iterable>>) entries;
}
static FrequencyMapN frequencyMapN(Weighted extends Generator extends A>> first,
Iterable>> rest) {
return new FrequencyMapN<>(cons(first, rest));
}
static Generator addLabel(Generator gen) {
return gen.labeled("frequency map");
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public Generator toGenerator() {
synchronized (this) {
if (cachedGenerator == null) cachedGenerator = buildGenerator();
}
return cachedGenerator;
}
private Generator buildGenerator() {
long total = 0L;
TreeMap> tree = new TreeMap<>();
for (Weighted> entry : entries) {
total += entry.getWeight();
tree.put(total, entry.getValue());
}
return addLabel(generateLongIndex(total)
.flatMap(n -> tree.ceilingEntry(1 + n).getValue()));
}
@SuppressWarnings("unchecked")
@Override
public FrequencyMap add(Weighted extends Generator extends A>> weightedGenerator) {
if (weightedGenerator.getWeight() < 1) {
return this;
} else {
return new FrequencyMapN<>(cons((Weighted>) weightedGenerator, entries));
}
}
@Override
public FrequencyMap combine(FrequencyMap other) {
return foldLeft(FrequencyMap::add, other, entries);
}
@Override
public FrequencyMap fmap(Fn1 super A, ? extends B> fn) {
Iterable>> mapped = Map.map(entry -> entry.fmap(gen -> gen.fmap(fn)), entries);
return new FrequencyMapN<>(mapped);
}
@Override
public FrequencyMap multiply(int positiveFactor) {
if (positiveFactor == 1) {
return this;
} else {
return new FrequencyMapN<>(Map.map(entry -> entry.multiplyBy(positiveFactor), entries));
}
}
}