main.io.github.moonlightsuite.moonlight.offline.algorithms.BooleanOp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of moonlight-engine Show documentation
Show all versions of moonlight-engine Show documentation
MoonLight is a light-weight Java-tool for monitoring temporal, spatial and spatio-temporal properties of distributed complex systems, such as Cyber-Physical Systems and Collective Adaptive Systems.
The newest version!
package io.github.moonlightsuite.moonlight.offline.algorithms;
import io.github.moonlightsuite.moonlight.offline.signal.Signal;
import io.github.moonlightsuite.moonlight.offline.signal.SignalCursor;
import java.util.Arrays;
import java.util.List;
import java.util.function.*;
import java.util.stream.Stream;
import static io.github.moonlightsuite.moonlight.offline.signal.SignalCursor.isNotCompleted;
public class BooleanOp {
private static final String
ERROR = "signal data structure failed irreparably";
private final boolean forward;
private Signal output;
private double time;
public BooleanOp() {
forward = true;
}
public BooleanOp(boolean isForward) {
forward = isForward;
}
private static T error() {
throw new UnsupportedOperationException(ERROR);
}
public Signal applyUnary(Signal s, Function op) {
return applyOp(cursors ->
op.apply(cursors.get(0).getCurrentValue()), s);
}
public Signal applyUnaryWithBound(Signal s, BiFunction op, R init) {
return applyOpWith1StepMemory(
(cursors, prev) -> op.apply(cursors.get(0).getCurrentValue(), prev),
init, s);
}
public Signal applyBinary(Signal s1,
BiFunction op,
Signal s2) {
return applyOp(cursors -> op.apply(cursors.get(0).getCurrentValue(),
cursors.get(1).getCurrentValue()),
s1, s2);
}
@SafeVarargs
private Signal applyOp(
Function>, R> op,
Signal... signals) {
output = new Signal<>();
setStartingTime(signals);
List> cs = prepareCursors(signals);
apply(cs, () -> op.apply(cs));
setEndingTime(signals);
return output;
}
@SafeVarargs
private Signal applyOpWith1StepMemory(
BiFunction>, R, R> op,
R init,
Signal... signals) {
output = new Signal<>();
setStartingTime(signals);
List> cs = prepareCursors(signals);
applyWithOneStepMemory(cs, prev -> op.apply(cs, prev), init);
setEndingTime(signals);
return output;
}
public Signal filterUnary(Signal s, Predicate p) {
return filterOp(cursors -> cursors.get(0).getCurrentValue(), p, s);
}
@SafeVarargs
private Signal filterOp(
Function>, R> op,
Predicate p,
Signal... signals) {
output = new Signal<>();
setStartingTime(signals);
List> cs = prepareCursors(signals);
applyFilter(cs, p, () -> op.apply(cs));
setEndingTime(signals);
return output;
}
private void applyFilter(List> cursors,
Predicate p,
Supplier value) {
while (isNotCompleted(cursors)) {
addResult(p.test(value.get()) ? value.get() : null);
moveCursorsForward(cursors);
}
}
@SafeVarargs
private void setStartingTime(Signal... signals) {
if (forward)
time = maxStart(Arrays.stream(signals));
else
time = minEnd(Arrays.stream(signals));
}
private double maxStart(Stream> stream) {
return stream.map(Signal::getStart)
.reduce(Math::max)
.orElseGet(BooleanOp::error);
}
private double minEnd(Stream> stream) {
return stream.map(Signal::getEnd)
.reduce(Math::min)
.orElseGet(BooleanOp::error);
}
@SafeVarargs
private void setEndingTime(Signal... signals) {
if (!output.isEmpty()) {
double end = minEnd(Arrays.stream(signals));
output.endAt(end);
}
}
private void apply(List> cursors,
Supplier value) {
while (isNotCompleted(cursors)) {
addResult(value.get());
moveCursorsForward(cursors);
}
}
private void applyWithOneStepMemory(List> cursors,
UnaryOperator value, R init) {
R prev = init;
while (isNotCompleted(cursors)) {
prev = value.apply(prev);
addResult(prev);
moveCursorsForward(cursors);
}
}
@SafeVarargs
private List> prepareCursors(
Signal... signals) {
return Arrays.stream(signals).map(s -> {
var c = s.getIterator(forward);
c.move(time);
return c;
}).toList();
}
private void addResult(R value) {
if (forward) {
output.add(time, value);
} else {
output.addBefore(time, value);
}
}
private void moveCursorsForward(List> cursors) {
time = cursors.stream()
.map(this::moveTime)
.reduce(rightEndingTime())
.orElseGet(BooleanOp::error);
cursors.forEach(c -> c.move(time));
}
private BinaryOperator rightEndingTime() {
if (forward)
return Math::min;
return Math::max;
}
private double moveTime(SignalCursor cursor) {
if (forward)
return cursor.nextTime();
return cursor.previousTime();
}
}