Skip to content

Commit

Permalink
Build during expression by updating ForEach and Spans
Browse files Browse the repository at this point in the history
  • Loading branch information
adrienmaillard committed Oct 28, 2022
1 parent 10da48b commit 7ec6844
Show file tree
Hide file tree
Showing 14 changed files with 681 additions and 224 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ static JsonParser<Rate> rateF(final JsonParser<Expression<LinearProfile>> linear
untuple((kind, alias) -> new ActivityWindow(alias)),
$ -> tuple(Unit.UNIT, $.activityAlias));

static final JsonParser<ActivitySpan> activitySpanP =
productP
.field("kind", literalP("SpansExpressionActivitySpan"))
.field("alias", stringP)
.map(
untuple((kind, alias) -> new ActivitySpan(alias)),
$ -> tuple(Unit.UNIT, $.activityAlias));
static final JsonParser<StartOf> startOfP =
productP
.field("kind", literalP("WindowsExpressionStartOf"))
Expand Down Expand Up @@ -329,14 +336,25 @@ static JsonParser<WindowsFromSpans> windowsFromSpansF(final JsonParser<Expressio
$ -> tuple(Unit.UNIT, $.expression()));
}

static JsonParser<ForEachActivity> forEachActivityF(final JsonParser<Expression<List<Violation>>> violationListExpressionP) {
static JsonParser<ForEachActivitySpans> forEachActivitySpansF(final JsonParser<Expression<Spans>> spansExpressionP) {
return productP
.field("kind", literalP("ForEachActivitySpans"))
.field("activityType", stringP)
.field("alias", stringP)
.field("expression", spansExpressionP)
.map(
untuple((kind, actType, alias, expression) -> new ForEachActivitySpans(actType, alias, expression)),
$ -> tuple(Unit.UNIT, $.activityType, $.alias, $.expression));
}

static JsonParser<ForEachActivityViolations> forEachActivityWindowsF(final JsonParser<Expression<List<Violation>>> violationListExpressionP) {
return productP
.field("kind", literalP("ForEachActivity"))
.field("kind", literalP("ForEachActivityViolations"))
.field("activityType", stringP)
.field("alias", stringP)
.field("expression", violationListExpressionP)
.map(
untuple((kind, actType, alias, expression) -> new ForEachActivity(actType, alias, expression)),
untuple((kind, actType, alias, expression) -> new ForEachActivityViolations(actType, alias, expression)),
$ -> tuple(Unit.UNIT, $.activityType, $.alias, $.expression));
}

Expand All @@ -350,7 +368,6 @@ static JsonParser<ForEachActivity> forEachActivityF(final JsonParser<Expression<

private static JsonParser<Expression<Windows>> windowsExpressionF(JsonParser<Expression<Spans>> spansP) {
return recursiveP(selfP -> chooseP(
activityWindowP,
startOfP,
endOfP,
changesP,
Expand All @@ -371,7 +388,8 @@ private static JsonParser<Expression<Windows>> windowsExpressionF(JsonParser<Exp
shiftByF(selfP),
startsF(selfP),
endsF(selfP),
windowsFromSpansF(spansP)));
windowsFromSpansF(spansP),
activityWindowP));
}

static JsonParser<SpansFromWindows> spansFromWindowsF(JsonParser<Expression<Windows>> windowsExpressionP) {
Expand All @@ -389,26 +407,28 @@ private static JsonParser<Expression<Spans>> spansExpressionF(JsonParser<Express
endsF(selfP),
splitF(selfP),
splitF(windowsP),
spansFromWindowsF(windowsP)
));
spansFromWindowsF(windowsP),
forEachActivitySpansF(selfP),
activitySpanP
));
}

public static final JsonParser<Expression<Windows>> windowsExpressionP = recursiveP(selfP -> windowsExpressionF(spansExpressionF(selfP)));

public static final JsonParser<Expression<Spans>> spansExpressionP = recursiveP(selfP -> spansExpressionF(windowsExpressionF(selfP)));

static final JsonParser<ViolationsOf> violationsOfP =
static final JsonParser<ViolationsOfWindows> violationsOfP =
productP
.field("kind", literalP("ViolationsOf"))
.field("expression", windowsExpressionP)
.map(
untuple((kind, expression) -> new ViolationsOf(expression)),
untuple((kind, expression) -> new ViolationsOfWindows(expression)),
$ -> tuple(Unit.UNIT, $.expression));


public static final JsonParser<Expression<List<Violation>>> constraintP =
recursiveP(selfP -> chooseP(
forEachActivityF(selfP),
windowsExpressionP.map(ViolationsOf::new, $ -> $.expression),
forEachActivityWindowsF(selfP),
windowsExpressionP.map(ViolationsOfWindows::new, $ -> $.expression),
violationsOfP));
}
Original file line number Diff line number Diff line change
@@ -1,71 +1,107 @@
package gov.nasa.jpl.aerie.constraints.time;

import gov.nasa.jpl.aerie.constraints.time.Interval.Inclusivity;
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import gov.nasa.jpl.aerie.constraints.time.Interval.Inclusivity;

/**
* A collection of intervals that can overlap.
*/
public class Spans implements IntervalContainer<Spans>, Iterable<Interval> {
private final List<Interval> intervals;
public class Spans implements IntervalContainer<Spans>, Iterable<Segment<Optional<Spans.Metadata>>> {
private final List<Segment<Optional<Metadata>>> intervals;

public record Metadata(long id){}

public Spans() {
this.intervals = new ArrayList<>();
}

public Spans(final ArrayList<Interval> intervals) {
intervals.removeIf(Interval::isEmpty);
this.intervals = intervals;
public Spans(final List<Segment<Optional<Metadata>>> intervals) {
this.intervals = new ArrayList<>(intervals);
}

public Spans(final Spans spans){
this.intervals = new ArrayList<>(spans.intervals);
}

public Spans(final Iterable<Interval> iter) {
this.intervals = StreamSupport.stream(iter.spliterator(), false).filter($ -> !$.isEmpty()).toList();
this.intervals = new ArrayList<>();
StreamSupport.stream(iter.spliterator(), false).filter($ -> !$.isEmpty())
.forEach(itv -> this.intervals.add(Segment.of(itv, Optional.empty())));
}

public Spans(final Interval... intervals) {
this.intervals = Arrays.stream(intervals).filter($ -> !$.isEmpty()).toList();
this.intervals = new ArrayList<>();
Arrays.stream(intervals).filter($ -> !$.isEmpty()).forEach(itv -> this.intervals.add(Segment.of(itv, Optional.empty())));
}

@SafeVarargs
public Spans(final Segment<Optional<Metadata>>... intervals) {
this.intervals = new ArrayList<>();
Arrays.stream(intervals).filter($ -> !$.interval().isEmpty()).forEach(this.intervals::add);
}

public Windows intoWindows() {
return new Windows(false).set(this.intervals, true);
return new Windows(false).set(this.intervals.stream().map(Segment::interval).toList(), true);
}

public void add(final Interval window) {
if (!window.isEmpty()) {
this.intervals.add(window);
this.intervals.add(Segment.of(window, Optional.empty()));
}
}

public void addAll(final Iterable<Interval> iter) {
this.intervals.addAll(
StreamSupport
.stream(iter.spliterator(), false)
.filter($ -> !$.isEmpty())
.toList()
);
public void add(final Interval window, Optional<Metadata> metadata) {
if (!window.isEmpty()) {
this.intervals.add(Segment.of(window, metadata));
}
}
public void addAll(final Spans iter) {
this.intervals.addAll(iter.intervals);
}

public void addAll(final Iterable<Segment<Optional<Metadata>>> iter) {
StreamSupport
.stream(iter.spliterator(), false)
.filter($ -> !$.interval().isEmpty())
.forEach(this.intervals::add);
}

public Spans map(final Function<Interval, Interval> mapper) {
return new Spans(this.intervals.stream().map(mapper).filter($ -> !$.isEmpty()).toList());
final var ret = new Spans();
this.intervals.forEach(interval -> {
final var newInterval = mapper.apply(interval.interval());
if(!newInterval.isEmpty())
ret.add(newInterval, interval.value());
});
return ret;
}

public Spans flatMap(final Function<Interval, ? extends Stream<Interval>> mapper) {
return new Spans(this.intervals.stream().flatMap(mapper).filter($ -> !$.isEmpty()).toList());
final var ret = new Spans();
this.intervals.forEach(interval -> mapper.apply(interval.interval()).filter(x -> !x.isEmpty()).forEach(
newInterval -> ret.add(newInterval, interval.value())));
return ret;
}

public Spans filter(final Predicate<Interval> filter) {
return new Spans(this.intervals.stream().filter(filter).toList());
final var pred = new Predicate<Segment<Optional<Metadata>>>() {
@Override
public boolean test(final Segment<Optional<Metadata>> intervalOptionalPair) {
return filter.test(intervalOptionalPair.interval());
}
};
return new Spans(this.intervals.stream().filter(pred).toList());
}

/**
Expand Down Expand Up @@ -149,7 +185,7 @@ public String toString() {
}

@Override
public Iterator<Interval> iterator() {
public Iterator<Segment<Optional<Metadata>>> iterator() {
return this.intervals.iterator();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package gov.nasa.jpl.aerie.constraints.tree;

import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment;
import gov.nasa.jpl.aerie.constraints.model.SimulationResults;
import gov.nasa.jpl.aerie.constraints.time.Interval;
import gov.nasa.jpl.aerie.constraints.time.Segment;
import gov.nasa.jpl.aerie.constraints.time.Spans;

import java.util.Objects;
import java.util.Optional;
import java.util.Set;

public final class ActivitySpan implements Expression<Spans> {
public final String activityAlias;

public ActivitySpan(final String activityAlias) {
this.activityAlias = activityAlias;
}

@Override
public Spans evaluate(final SimulationResults results, final Interval bounds, final EvaluationEnvironment environment) {
final var activity = environment.activityInstances().get(this.activityAlias);
return new Spans(Segment.of(activity.interval, Optional.of(new Spans.Metadata(activity.id))));
}

@Override
public void extractResources(final Set<String> names) { }

@Override
public String prettyPrint(final String prefix) {
return String.format(
"\n%s(during %s)",
prefix,
this.activityAlias
);
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof ActivitySpan)) return false;
final var o = (ActivitySpan)obj;

return Objects.equals(this.activityAlias, o.activityAlias);
}

@Override
public int hashCode() {
return Objects.hash(this.activityAlias);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package gov.nasa.jpl.aerie.constraints.tree;

import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment;
import gov.nasa.jpl.aerie.constraints.model.SimulationResults;
import gov.nasa.jpl.aerie.constraints.time.Interval;
import gov.nasa.jpl.aerie.constraints.time.Spans;

import java.util.HashMap;
import java.util.Objects;
import java.util.Set;

public final class ForEachActivitySpans implements Expression<Spans> {
public final String activityType;
public final String alias;
public final Expression<Spans> expression;

public ForEachActivitySpans(
final String activityType,
final String alias,
final Expression<Spans> expression
) {
this.activityType = activityType;
this.alias = alias;
this.expression = expression;
}

@Override
public Spans evaluate(final SimulationResults results, final Interval bounds, final EvaluationEnvironment environment) {
final var spans = new Spans();
for (final var activity : results.activities) {
if (activity.type.equals(this.activityType)) {
final var newEnvironment = new EvaluationEnvironment(
new HashMap<>(environment.activityInstances()),
environment.realExternalProfiles(),
environment.discreteExternalProfiles()
);
newEnvironment.activityInstances().put(this.alias, activity);

final var expressionSpans = this.expression.evaluate(results, bounds, newEnvironment);
spans.addAll(expressionSpans);
}
}
return spans;
}

@Override
public void extractResources(final Set<String> names) {
this.expression.extractResources(names);
}

@Override
public String prettyPrint(final String prefix) {
return String.format(
"\n%s(for-each-activity %s %s %s)",
prefix,
this.activityType,
this.alias,
this.expression.prettyPrint(prefix + " ")
);
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof ForEachActivitySpans)) return false;
final var o = (ForEachActivitySpans)obj;

return Objects.equals(this.activityType, o.activityType) &&
Objects.equals(this.alias, o.alias) &&
Objects.equals(this.expression, o.expression);
}

@Override
public int hashCode() {
return Objects.hash(this.activityType, this.alias, this.expression);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
import java.util.Objects;
import java.util.Set;

public final class ForEachActivity implements Expression<List<Violation>> {
public final class ForEachActivityViolations implements Expression<List<Violation>> {
public final String activityType;
public final String alias;
public final Expression<List<Violation>> expression;

public ForEachActivity(
public ForEachActivityViolations(
final String activityType,
final String alias,
final Expression<List<Violation>> expression
Expand Down Expand Up @@ -69,8 +69,8 @@ public String prettyPrint(final String prefix) {

@Override
public boolean equals(Object obj) {
if (!(obj instanceof ForEachActivity)) return false;
final var o = (ForEachActivity)obj;
if (!(obj instanceof ForEachActivityViolations)) return false;
final var o = (ForEachActivityViolations)obj;

return Objects.equals(this.activityType, o.activityType) &&
Objects.equals(this.alias, o.alias) &&
Expand Down
Loading

0 comments on commit 7ec6844

Please sign in to comment.