io.github.ericmedvet.jnb.buildable.Functions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jnb.buildable Show documentation
Show all versions of jnb.buildable Show documentation
Buildable components of jnb, a small framework for building objects from a named parameter map.
The newest version!
/*-
* ========================LICENSE_START=================================
* jnb-buildable
* %%
* Copyright (C) 2023 - 2024 Eric Medvet
* %%
* 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.
* =========================LICENSE_END==================================
*/
package io.github.ericmedvet.jnb.buildable;
import io.github.ericmedvet.jnb.core.Cacheable;
import io.github.ericmedvet.jnb.core.Discoverable;
import io.github.ericmedvet.jnb.core.MathOp;
import io.github.ericmedvet.jnb.core.Param;
import io.github.ericmedvet.jnb.datastructure.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Discoverable(prefixTemplate = "function|f")
public class Functions {
private static final Logger L = Logger.getLogger(Functions.class.getName());
private Functions() {}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction avg(
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%.1f") String format) {
Function, Double> f =
vs -> vs.stream().mapToDouble(Number::doubleValue).average().orElseThrow();
return FormattedNamedFunction.from(f, format, "avg").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction clip(
@Param(value = "of", dNPM = "f.identity()") Function beforeF,
@Param("range") DoubleRange range,
@Param(value = "format", dS = "%.1f") String format) {
Function f = range::clip;
return FormattedNamedFunction.from(
f, format, ("clip[" + format + ";" + format + "]").formatted(range.min(), range.max()))
.compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction composition(
@Param(value = "of", dNPM = "f.identity()") Function beforeF,
@Param(value = "then", dNPM = "f.identity()") Function afterF) {
return FormattedNamedFunction.from(afterF, FormattedFunction.format(afterF), NamedFunction.name(afterF))
.compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static NamedFunction> distinct(
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%s") String format) {
Function, Set> f = HashSet::new;
return FormattedNamedFunction.from(f, format, "distinct").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static NamedFunction> each(
@Param("mapF") Function mapF,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF) {
Function, Collection> f = ts -> ts.stream().map(mapF).toList();
return NamedFunction.from(f, "each[%s]".formatted(NamedFunction.name(mapF)))
.compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static NamedFunction> filter(
@Param(value = "condition", dNPM = "predicate.always()") Predicate condition,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%s") String format) {
Function, Collection> f =
ts -> ts.stream().filter(condition).toList();
return FormattedNamedFunction.from(f, format, "filter[%s]".formatted(condition))
.compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static NamedFunction fromBase64(
@Param(value = "of", dNPM = "f.identity()") Function beforeF,
@Param(value = "format", dS = "%s") String format) {
Function f = s -> {
try (ByteArrayInputStream bais =
new ByteArrayInputStream(Base64.getDecoder().decode(s));
ObjectInputStream ois = new ObjectInputStream(bais)) {
return ois.readObject();
} catch (Throwable t) {
L.warning("Cannot deserialize due to %s".formatted(t));
return null;
}
};
return FormattedNamedFunction.from(f, format, "from.base64").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction gridCompactness(
@Param(value = "predicate", dNPM = "f.nonNull()") Function predicate,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%2d") String format) {
Function, Double> f = g -> GridUtils.compactness(g, predicate::apply);
return FormattedNamedFunction.from(f, format, "grid.compactness").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction gridCount(
@Param(value = "predicate", dNPM = "f.nonNull()") Function predicate,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%2d") String format) {
Function, Integer> f = g -> GridUtils.count(g, predicate::apply);
return FormattedNamedFunction.from(f, format, "grid.count").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction gridCoverage(
@Param(value = "predicate", dNPM = "f.nonNull()") Function predicate,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%2d") String format) {
Function, Double> f = g -> (double) GridUtils.count(g, predicate::apply) / (double) (g.w() * g.h());
return FormattedNamedFunction.from(f, format, "grid.coverage").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction gridElongation(
@Param(value = "predicate", dNPM = "f.nonNull()") Function predicate,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%2d") String format) {
Function, Double> f = g -> GridUtils.elongation(g, predicate::apply);
return FormattedNamedFunction.from(f, format, "grid.elongation").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction gridFitH(
@Param(value = "predicate", dNPM = "f.nonNull()") Function predicate,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%2d") String format) {
Function, Integer> f = g -> GridUtils.fit(g, predicate::apply).h();
return FormattedNamedFunction.from(f, format, "grid.fit.h").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction gridFitW(
@Param(value = "predicate", dNPM = "f.nonNull()") Function predicate,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%2d") String format) {
Function, Integer> f = g -> GridUtils.fit(g, predicate::apply).w();
return FormattedNamedFunction.from(f, format, "grid.fit.w").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction gridH(
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%2d") String format) {
Function, Integer> f = Grid::h;
return FormattedNamedFunction.from(f, format, "grid.h").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction gridW(
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%2d") String format) {
Function, Integer> f = Grid::w;
return FormattedNamedFunction.from(f, format, "grid.w").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static Function identity() {
Function f = x -> x;
return NamedFunction.from(f, NamedFunction.IDENTITY_NAME);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction mathConst(
@Param("v") double v, @Param(value = "format", dS = "%.1f") String format) {
return FormattedNamedFunction.from(x -> v, format, format.formatted(v));
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction mathOp(
@Param(value = "of", dNPM = "f.identity()") Function beforeF,
@Param("args") List> args,
@Param("op") MathOp op,
@Param(value = "format", dS = "%.1f") String format) {
Function f = y -> op.applyAsDouble(
args.stream().mapToDouble(aF -> aF.apply(y).doubleValue()).toArray());
return FormattedNamedFunction.from(
f,
format,
"%s[%s]"
.formatted(
op.toString().toLowerCase(),
args.stream().map(NamedFunction::name).collect(Collectors.joining(";"))))
.compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static > FormattedNamedFunction max(
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%s") String format) {
Function, C> f =
cs -> cs.stream().max(Comparable::compareTo).orElseThrow();
return FormattedNamedFunction.from(f, format, "max").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static > FormattedNamedFunction median(
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%s") String format) {
Function, C> f =
cs -> cs.stream().sorted().toList().get(Math.min(cs.size() - 1, Math.max(0, cs.size() / 2)));
return FormattedNamedFunction.from(f, format, "median").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static > FormattedNamedFunction min(
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%s") String format) {
Function, C> f =
cs -> cs.stream().min(Comparable::compareTo).orElseThrow();
return FormattedNamedFunction.from(f, format, "min").compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static NamedFunction nTh(
@Param("n") int n,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%s") String format) {
Function, T> f = ts -> n >= 0 ? ts.get(n) : ts.get(ts.size() + n);
return FormattedNamedFunction.from(f, format, "[%d]".formatted(n)).compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction> nkTh(
@Param("n") int n,
@Param("k") int k,
@Param(value = "of", dNPM = "f.identity()") Function> beforeF,
@Param(value = "format", dS = "%s") String format) {
Function, List> f = ts -> IntStream.range(0, ts.size())
.filter(i -> (i % n) == k)
.mapToObj(ts::get)
.toList();
return FormattedNamedFunction.from(f, format, "[%di+%d]".formatted(n, k))
.compose(beforeF);
}
@SuppressWarnings("unused")
@Cacheable
public static FormattedNamedFunction nonNull(
@Param(value = "of", dNPM = "f.identity()") Function beforeF,
@Param(value = "format", dS = "%s") String format) {
Function