diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/model/ActivityInstance.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/model/ActivityInstance.java index 940bbae929..96e9144dc3 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/model/ActivityInstance.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/model/ActivityInstance.java @@ -1,42 +1,41 @@ package gov.nasa.jpl.aerie.constraints.model; import gov.nasa.jpl.aerie.constraints.time.Interval; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import java.util.Map; import java.util.Objects; +import java.util.Optional; -public final class ActivityInstance { - public final long id; - public final String type; - public final Map parameters; - public final Interval interval; - +public record ActivityInstance( + ActivityInstanceId instanceId, + String type, + Map parameters, + Interval interval, + Optional directiveId +) { public ActivityInstance( - final long id, - final String type, - final Map parameters, - final Interval interval + long id, + String type, + Map parameters, + Interval interval ) { - this.type = type; - this.id = id; - this.parameters = parameters; - this.interval = interval; + this(id, type, parameters, interval, Optional.empty()); } - @Override - public boolean equals(Object obj) { - if (!(obj instanceof ActivityInstance)) return false; - final var o = (ActivityInstance)obj; - - return Objects.equals(this.id, o.id) && - Objects.equals(this.type, o.type) && - Objects.equals(this.parameters, o.parameters) && - Objects.equals(this.interval, o.interval); + public ActivityInstance( + long id, + String type, + Map parameters, + Interval interval, + Optional directiveId + ) { + this(new ActivityInstanceId(id), type, parameters, interval, directiveId); } - @Override - public int hashCode() { - return Objects.hash(this.id, this.type, this.parameters, this.interval); + public long id() { + return this.instanceId().id(); } } diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ActivitySpan.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ActivitySpan.java index d2dd4f2805..868673989e 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ActivitySpan.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ActivitySpan.java @@ -20,7 +20,7 @@ public ActivitySpan(final String 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)))); + return new Spans(Segment.of(activity.interval(), Optional.of(new Spans.Metadata(activity)))); } @Override diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ActivityWindow.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ActivityWindow.java index 1ad673d159..8f0acdab89 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ActivityWindow.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ActivityWindow.java @@ -21,7 +21,7 @@ public Windows evaluate(final SimulationResults results, final Interval bounds, final var activity = environment.activityInstances().get(this.activityAlias); return new Windows( Segment.of(bounds, false), - Segment.of(activity.interval, true) + Segment.of(activity.interval(), true) ); } diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/DiscreteParameter.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/DiscreteParameter.java index 4c336c4219..d89e29b41b 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/DiscreteParameter.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/DiscreteParameter.java @@ -22,7 +22,7 @@ public DiscreteParameter(final String activityAlias, final String parameterName) public DiscreteProfile evaluate(final SimulationResults results, final Interval bounds, final EvaluationEnvironment environment) { final var activity = environment.activityInstances().get(this.activityAlias); return new DiscreteProfile( - Segment.of(bounds, activity.parameters.get(this.parameterName)) + Segment.of(bounds, activity.parameters().get(this.parameterName)) ); } diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/EndOf.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/EndOf.java index 1fd684bcd2..e582523f4c 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/EndOf.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/EndOf.java @@ -21,7 +21,7 @@ public Windows evaluate(final SimulationResults results, final Interval bounds, final var activity = environment.activityInstances().get(this.activityAlias); return new Windows( Segment.of(bounds, false), - Segment.of(Interval.at(activity.interval.end), true) + Segment.of(Interval.at(activity.interval().end), true) ); } diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ForEachActivitySpans.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ForEachActivitySpans.java index 48a5d8e720..6a9bcdbb33 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ForEachActivitySpans.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ForEachActivitySpans.java @@ -74,7 +74,7 @@ public String prettyPrint(final String prefix) { public record MatchType(String type) implements TriFunction { @Override public Boolean apply(ActivityInstance act, SimulationResults results, EvaluationEnvironment env) { - return Objects.equals(act.type, type); + return Objects.equals(act.type(), type); } } } diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ForEachActivityViolations.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ForEachActivityViolations.java index 79cdb5e48d..5c134e78df 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ForEachActivityViolations.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/ForEachActivityViolations.java @@ -16,7 +16,7 @@ public record ForEachActivityViolations( public ConstraintResult evaluate(final SimulationResults results, final Interval bounds, final EvaluationEnvironment environment) { var violations = new ConstraintResult(); for (final var activity : results.activities) { - if (activity.type.equals(this.activityType)) { + if (activity.type().equals(this.activityType)) { final var newEnvironment = new EvaluationEnvironment( new HashMap<>(environment.activityInstances()), environment.spansInstances(), @@ -28,7 +28,7 @@ public ConstraintResult evaluate(final SimulationResults results, final Interval final var newViolations = this.expression.evaluate(results, bounds, newEnvironment); for (final var violation: newViolations.violations) { - violation.addActivityId(activity.id); + violation.addActivityId(activity.id()); } violations = ConstraintResult.merge(violations, newViolations); } diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/RealParameter.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/RealParameter.java index 51ff346744..9ef970401a 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/RealParameter.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/RealParameter.java @@ -24,12 +24,12 @@ public RealParameter(final String activityAlias, final String parameterName) { @Override public LinearProfile evaluate(final SimulationResults results, final Interval bounds, final EvaluationEnvironment environment) { final var activity = environment.activityInstances().get(this.activityAlias); - final var parameter = activity.parameters.get(this.parameterName); + final var parameter = activity.parameters().get(this.parameterName); final var value = parameter.asReal().orElseThrow( () -> new InputMismatchException( String.format("Activity parameter \"%s\" with value %s cannot be interpreted as real", this.parameterName, - activity.parameters.get(parameterName).toString()))); + activity.parameters().get(parameterName).toString()))); return new LinearProfile( Segment.of(Interval.FOREVER, new LinearEquation(Duration.ZERO, value, 0.0)) diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/RollingThreshold.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/RollingThreshold.java index 2c01d07d68..85bf2522e2 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/RollingThreshold.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/RollingThreshold.java @@ -84,7 +84,7 @@ public ConstraintResult evaluate(SimulationResults results, final Interval bound for (final var span : reportedSpans) { if (!Interval.intersect(span.interval(), expandedInterval).isEmpty()) { violationIntervals.add(span.interval()); - span.value().ifPresent(m -> violationActivityIds.add(m.activityInstance().id)); + span.value().ifPresent(m -> violationActivityIds.add(m.activityInstance().id())); } } if (this.algorithm == RollingThresholdAlgorithm.ExcessHull || this.algorithm == RollingThresholdAlgorithm.DeficitHull) { diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/StartOf.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/StartOf.java index 7f8a4972a3..28a5def93e 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/StartOf.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/tree/StartOf.java @@ -21,7 +21,7 @@ public Windows evaluate(final SimulationResults results, final Interval bounds, final var activity = environment.activityInstances().get(this.activityAlias); return new Windows( Segment.of(bounds, false), - Segment.of(Interval.at(activity.interval.start), true) + Segment.of(Interval.at(activity.interval().start), true) ); } diff --git a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulatedActivityTest.java b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/ActivityInstanceTest.java similarity index 99% rename from examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulatedActivityTest.java rename to examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/ActivityInstanceTest.java index 236e10fb4e..ec44be8cf9 100644 --- a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulatedActivityTest.java +++ b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/ActivityInstanceTest.java @@ -22,7 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -public final class SimulatedActivityTest { +public final class ActivityInstanceTest { @Test public void testUnspecifiedArgInSimulatedActivity() { final var schedule = SimulationUtility.buildSchedule( diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulatedActivity.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstance.java similarity index 81% rename from merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulatedActivity.java rename to merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstance.java index cb96469865..48d1a0dc49 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulatedActivity.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstance.java @@ -8,13 +8,13 @@ import java.util.Map; import java.util.Optional; -public record SimulatedActivity( +public record ActivityInstance( String type, Map arguments, Instant start, Duration duration, - SimulatedActivityId parentId, - List childIds, + ActivityInstanceId parentId, + List childIds, Optional directiveId, SerializedValue computedAttributes ) { } diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstanceId.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstanceId.java new file mode 100644 index 0000000000..4d57e7a666 --- /dev/null +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstanceId.java @@ -0,0 +1,3 @@ +package gov.nasa.jpl.aerie.merlin.driver; + +public record ActivityInstanceId(long id) {} diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulatedActivityId.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulatedActivityId.java deleted file mode 100644 index e4d31f9788..0000000000 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulatedActivityId.java +++ /dev/null @@ -1,3 +0,0 @@ -package gov.nasa.jpl.aerie.merlin.driver; - -public record SimulatedActivityId(long id) {} diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationResults.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationResults.java index b842fd48cc..8f3e5f481d 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationResults.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationResults.java @@ -20,16 +20,16 @@ public final class SimulationResults { public final Duration duration; public final Map> realProfiles; public final Map> discreteProfiles; - public final Map simulatedActivities; - public final Map unfinishedActivities; + public final Map simulatedActivities; + public final Map unfinishedActivities; public final List> topics; public final Map>> events; public SimulationResults( final Map> realProfiles, final Map> discreteProfiles, - final Map simulatedActivities, - final Map unfinishedActivities, + final Map simulatedActivities, + final Map unfinishedActivities, final Instant startTime, final Duration duration, final List> topics, diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/UnfinishedActivity.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/UnfinishedActivity.java index a03b41a840..7e87f20582 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/UnfinishedActivity.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/UnfinishedActivity.java @@ -11,7 +11,7 @@ public record UnfinishedActivity( String type, Map arguments, Instant start, - SimulatedActivityId parentId, - List childIds, + ActivityInstanceId parentId, + List childIds, Optional directiveId ) { } diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/SimulationEngine.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/SimulationEngine.java index 8344f129b0..fed9782634 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/SimulationEngine.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/SimulationEngine.java @@ -3,8 +3,8 @@ import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.MissionModel.SerializableTopic; import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivityId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.UnfinishedActivity; @@ -712,8 +712,8 @@ public DirectiveDetail getDirectiveDetailsFromSpan( public record SimulationActivityExtract( Instant startTime, Duration duration, - Map simulatedActivities, - Map unfinishedActivities + Map simulatedActivities, + Map unfinishedActivities ) {} private SpanInfo computeSpanInfo( @@ -756,25 +756,25 @@ private HashMap spanToActivityDirectiveId( return activityDirectiveIds; } - private HashMap spanToSimulatedActivities( + private HashMap spanToSimulatedActivities( final SpanInfo spanInfo ) { final var activityDirectiveIds = spanToActivityDirectiveId(spanInfo); - final var spanToSimulatedActivityId = new HashMap(activityDirectiveIds.size()); - final var usedSimulatedActivityIds = new HashSet<>(); + final var spanToActivityInstanceId = new HashMap(activityDirectiveIds.size()); + final var usedActivityInstanceIds = new HashSet<>(); for (final var entry : activityDirectiveIds.entrySet()) { - spanToSimulatedActivityId.put(entry.getKey(), new SimulatedActivityId(entry.getValue().id())); - usedSimulatedActivityIds.add(entry.getValue().id()); + spanToActivityInstanceId.put(entry.getKey(), new ActivityInstanceId(entry.getValue().id())); + usedActivityInstanceIds.add(entry.getValue().id()); } long counter = 1L; for (final var span : this.spans.keySet()) { if (!spanInfo.isActivity(span)) continue; - if (spanToSimulatedActivityId.containsKey(span)) continue; + if (spanToActivityInstanceId.containsKey(span)) continue; - while (usedSimulatedActivityIds.contains(counter)) counter++; - spanToSimulatedActivityId.put(span, new SimulatedActivityId(counter++)); + while (usedActivityInstanceIds.contains(counter)) counter++; + spanToActivityInstanceId.put(span, new ActivityInstanceId(counter++)); } - return spanToSimulatedActivityId; + return spanToActivityInstanceId; } /** @@ -803,30 +803,30 @@ public SimulationActivityExtract computeActivitySimulationResults( }); // Give every task corresponding to a child activity an ID that doesn't conflict with any root activity. - final var spanToSimulatedActivityId = spanToSimulatedActivities(spanInfo); + final var spanToActivityInstanceId = spanToSimulatedActivities(spanInfo); - final var simulatedActivities = new HashMap(); - final var unfinishedActivities = new HashMap(); + final var simulatedActivities = new HashMap(); + final var unfinishedActivities = new HashMap(); this.spans.forEach((span, state) -> { if (!spanInfo.isActivity(span)) return; - final var activityId = spanToSimulatedActivityId.get(span); + final var activityId = spanToActivityInstanceId.get(span); final var directiveId = activityDirectiveIds.get(span); if (state.endOffset().isPresent()) { final var inputAttributes = spanInfo.input().get(span); final var outputAttributes = spanInfo.output().get(span); - simulatedActivities.put(activityId, new SimulatedActivity( + simulatedActivities.put(activityId, new ActivityInstance( inputAttributes.getTypeName(), inputAttributes.getArguments(), startTime.plus(state.startOffset().in(Duration.MICROSECONDS), ChronoUnit.MICROS), state.endOffset().get().minus(state.startOffset()), - spanToSimulatedActivityId.get(activityParents.get(span)), + spanToActivityInstanceId.get(activityParents.get(span)), activityChildren .getOrDefault(span, Collections.emptyList()) .stream() - .map(spanToSimulatedActivityId::get) + .map(spanToActivityInstanceId::get) .toList(), (activityParents.containsKey(span)) ? Optional.empty() : Optional.ofNullable(directiveId), outputAttributes @@ -837,11 +837,11 @@ public SimulationActivityExtract computeActivitySimulationResults( inputAttributes.getTypeName(), inputAttributes.getArguments(), startTime.plus(state.startOffset().in(Duration.MICROSECONDS), ChronoUnit.MICROS), - spanToSimulatedActivityId.get(activityParents.get(span)), + spanToActivityInstanceId.get(activityParents.get(span)), activityChildren .getOrDefault(span, Collections.emptyList()) .stream() - .map(spanToSimulatedActivityId::get) + .map(spanToActivityInstanceId::get) .toList(), (activityParents.containsKey(span)) ? Optional.empty() : Optional.of(directiveId) )); @@ -853,7 +853,7 @@ public SimulationActivityExtract computeActivitySimulationResults( private TreeMap>> createSerializedTimeline( final TemporalEventSource combinedTimeline, final Iterable> serializableTopics, - final HashMap spanToActivities, + final HashMap spanToActivities, final HashMap, Integer> serializableTopicToId) { final var serializedTimeline = new TreeMap>>(); var time = Duration.ZERO; diff --git a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/AnchorSimulationTest.java b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/AnchorSimulationTest.java index 9f300abc16..976f9d4457 100644 --- a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/AnchorSimulationTest.java +++ b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/AnchorSimulationTest.java @@ -496,7 +496,7 @@ private void constructFullComplete5AryTree( int currentLevel, long parentNode, Map activitiesToSimulate, - Map simulatedActivities) + Map simulatedActivities) { if (currentLevel > maxLevel) return; for (int i = 1; i <= 5; i++) { @@ -505,8 +505,8 @@ private void constructFullComplete5AryTree( new ActivityDirectiveId(curElement), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(parentNode), false)); simulatedActivities.put( - new SimulatedActivityId(curElement), - new SimulatedActivity( + new ActivityInstanceId(curElement), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(currentLevel, ChronoUnit.MINUTES), @@ -523,7 +523,7 @@ private void constructFullComplete5AryTree( } } - private static void assertEqualsAsideFromChildren(SimulatedActivity expected, SimulatedActivity actual) { + private static void assertEqualsAsideFromChildren(ActivityInstance expected, ActivityInstance actual) { assertEquals(expected.type(), actual.type()); assertEquals(expected.arguments(), actual.arguments()); assertEquals(expected.start(), actual.start()); @@ -538,7 +538,7 @@ private static void assertEqualsAsideFromChildren(SimulatedActivity expected, Si public void activitiesAnchoredToPlan() { final var minusOneMinute = Duration.of(-60, Duration.SECONDS); final var resolveToPlanStartAnchors = new HashMap(415); - final Map simulatedActivities = new HashMap<>(415); + final Map simulatedActivities = new HashMap<>(415); // Anchored to Plan Start (only positive is allowed) for (long l = 0; l < 5; l++) { @@ -546,7 +546,7 @@ public void activitiesAnchoredToPlan() { resolveToPlanStartAnchors.put( activityDirectiveId, new ActivityDirective(Duration.of(l, Duration.SECONDS), serializedDelayDirective, null, true)); - simulatedActivities.put(new SimulatedActivityId(l), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(l), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(l, ChronoUnit.SECONDS), @@ -568,7 +568,7 @@ public void activitiesAnchoredToPlan() { serializedDelayDirective, null, false)); - simulatedActivities.put(new SimulatedActivityId(l), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(l), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(10, ChronoUnit.DAYS).minus(l, ChronoUnit.MINUTES), @@ -584,7 +584,7 @@ public void activitiesAnchoredToPlan() { resolveToPlanStartAnchors.put( new ActivityDirectiveId(15), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(0), true)); - simulatedActivities.put(new SimulatedActivityId(15), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(15), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -601,7 +601,7 @@ public void activitiesAnchoredToPlan() { resolveToPlanStartAnchors.put( activityDirectiveId, new ActivityDirective(oneMinute, serializedDelayDirective, new ActivityDirectiveId(l - 1), true)); - simulatedActivities.put(new SimulatedActivityId(l), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(l), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -615,7 +615,7 @@ public void activitiesAnchoredToPlan() { resolveToPlanStartAnchors.put( activityDirectiveId, new ActivityDirective(minusOneMinute, serializedDelayDirective, new ActivityDirectiveId(l - 1), true)); - simulatedActivities.put(new SimulatedActivityId(l), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(l), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -656,7 +656,7 @@ public void activitiesAnchoredToPlan() { public void activitiesAnchoredToOtherActivities() { final var allEndTimeAnchors = new HashMap(400); final var endTimeAnchorEveryFifth = new HashMap(400); - final Map simulatedActivities = new HashMap<>(800); + final Map simulatedActivities = new HashMap<>(800); final var activitiesToSimulate = new HashMap(800); allEndTimeAnchors.put( @@ -666,8 +666,8 @@ public void activitiesAnchoredToOtherActivities() { new ActivityDirectiveId(400), new ActivityDirective(oneMinute, serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(0), - new SimulatedActivity( + new ActivityInstanceId(0), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -677,8 +677,8 @@ public void activitiesAnchoredToOtherActivities() { Optional.of(new ActivityDirectiveId(0)), computedAttributes)); simulatedActivities.put( - new SimulatedActivityId(400), - new SimulatedActivity( + new ActivityInstanceId(400), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -700,8 +700,8 @@ public void activitiesAnchoredToOtherActivities() { new ActivityDirectiveId(l - 1), false)); simulatedActivities.put( - new SimulatedActivityId(l), - new SimulatedActivity( + new ActivityInstanceId(l), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus((2 * l) + 1, ChronoUnit.MINUTES), @@ -730,8 +730,8 @@ public void activitiesAnchoredToOtherActivities() { true)); } simulatedActivities.put( - new SimulatedActivityId(k), - new SimulatedActivity( + new ActivityInstanceId(k), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(l + c, ChronoUnit.MINUTES), @@ -779,7 +779,7 @@ public void decomposingActivitiesAndAnchors() { final var activitiesToSimulate = new HashMap(23); // NOTE: This list is intentionally keyed on ActivityDirectiveId, not on SimulatedActivityId. // Additionally, because we do not know the order the child activities will generate in, DecompositionDirectives will have a List.of() rather than the correct value - final var topLevelSimulatedActivities = new HashMap(23); + final var topLevelSimulatedActivities = new HashMap(23); final var threeMinutes = Duration.of(3, Duration.MINUTES); // ND <-s- D <-s- D @@ -800,7 +800,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(1), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -811,7 +811,7 @@ public void decomposingActivitiesAndAnchors() { computedAttributes)); topLevelSimulatedActivities.put( new ActivityDirectiveId(2), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -822,7 +822,7 @@ public void decomposingActivitiesAndAnchors() { computedAttributes)); topLevelSimulatedActivities.put( new ActivityDirectiveId(3), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -841,7 +841,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(4), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), @@ -860,7 +860,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(5), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -879,7 +879,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(6), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), @@ -904,7 +904,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(7), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -915,7 +915,7 @@ public void decomposingActivitiesAndAnchors() { computedAttributes)); topLevelSimulatedActivities.put( new ActivityDirectiveId(8), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -934,7 +934,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(9), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), @@ -953,7 +953,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(10), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -972,7 +972,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(11), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), @@ -991,7 +991,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(12), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -1010,7 +1010,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(13), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), @@ -1029,7 +1029,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(14), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -1048,7 +1048,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(15), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), @@ -1067,7 +1067,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(16), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), @@ -1086,7 +1086,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(17), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(6, ChronoUnit.MINUTES), @@ -1105,7 +1105,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(18), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), @@ -1124,7 +1124,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(19), - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(6, ChronoUnit.MINUTES), @@ -1143,7 +1143,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(20), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -1162,7 +1162,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(21), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -1181,7 +1181,7 @@ public void decomposingActivitiesAndAnchors() { true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(22), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), @@ -1200,7 +1200,7 @@ public void decomposingActivitiesAndAnchors() { false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(23), - new SimulatedActivity( + new ActivityInstance( serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), @@ -1228,8 +1228,8 @@ public void decomposingActivitiesAndAnchors() { assertEquals(modelTopicList.get(i), actualSimResults.topics.get(i)); } - final var childSimulatedActivities = new HashMap(28); - final var otherSimulatedActivities = new HashMap(23); + final var childSimulatedActivities = new HashMap(28); + final var otherSimulatedActivities = new HashMap(23); assertEquals(51, actualSimResults.simulatedActivities.size()); // 23 + 2*(14 Decomposing activities) for (final var entry : actualSimResults.simulatedActivities.entrySet()) { @@ -1260,7 +1260,7 @@ public void decomposingActivitiesAndAnchors() { if (firstChild.start().isBefore(secondChild.start())) { assertEqualsAsideFromChildren( - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), entry.getValue().start(), @@ -1271,7 +1271,7 @@ public void decomposingActivitiesAndAnchors() { computedAttributes), firstChild); assertEqualsAsideFromChildren( - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), entry.getValue().start().plus(2, ChronoUnit.MINUTES), @@ -1283,7 +1283,7 @@ public void decomposingActivitiesAndAnchors() { secondChild); } else { assertEqualsAsideFromChildren( - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), entry.getValue().start().plus(2, ChronoUnit.MINUTES), @@ -1294,7 +1294,7 @@ public void decomposingActivitiesAndAnchors() { computedAttributes), firstChild); assertEqualsAsideFromChildren( - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), entry.getValue().start(), @@ -1319,14 +1319,14 @@ public void naryTreeAnchorChain() { // Number of activity directives = 5^0 + 5^1 + 5^2 + 5^3 + 5^4 + 5^5 = 3906 final var activitiesToSimulate = new HashMap(3906); - final var simulatedActivities = new HashMap(3906); + final var simulatedActivities = new HashMap(3906); activitiesToSimulate.put( new ActivityDirectiveId(0), new ActivityDirective(Duration.ZERO, serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(0), - new SimulatedActivity( + new ActivityInstanceId(0), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, diff --git a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/TemporalSubsetSimulationTests.java b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/TemporalSubsetSimulationTests.java index fb31916f7f..3df904ceee 100644 --- a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/TemporalSubsetSimulationTests.java +++ b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/TemporalSubsetSimulationTests.java @@ -69,8 +69,8 @@ private static void assertEqualsSimulationResults(SimulationResults expected, Si @Test @DisplayName("Ten-day plan, no anchors: Simulate first half of plan") public void simulateFirstHalf(){ - final var simulatedActivities = new HashMap(120); - final var unfinishedActivities = new HashMap(1); + final var simulatedActivities = new HashMap(120); + final var unfinishedActivities = new HashMap(1); final var activitiesInPlan = new HashMap(240); for(int i = 0; i < 120; ++i){ @@ -78,8 +78,8 @@ public void simulateFirstHalf(){ new ActivityDirectiveId(i), new ActivityDirective(Duration.of(i, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(i), - new SimulatedActivity( + new ActivityInstanceId(i), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(i, ChronoUnit.HOURS), @@ -98,7 +98,7 @@ public void simulateFirstHalf(){ // Activity 120 won't be finished since it starts at the simulation end time unfinishedActivities.put( - new SimulatedActivityId(120), + new ActivityInstanceId(120), new UnfinishedActivity( serializedDelayDirective.getTypeName(), Map.of(), @@ -133,7 +133,7 @@ public void simulateFirstHalf(){ @Test @DisplayName("Ten-day plan, no anchors: Simulate second half of plan") public void simulateSecondHalf(){ - final var simulatedActivities = new HashMap(120); + final var simulatedActivities = new HashMap(120); final var activitiesInPlan = new HashMap(240); for(int i = 0; i < 120; ++i){ @@ -144,8 +144,8 @@ public void simulateSecondHalf(){ for(int i = 120; i < 240; ++i){ simulatedActivities.put( - new SimulatedActivityId(i), - new SimulatedActivity( + new ActivityInstanceId(i), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(i, ChronoUnit.HOURS), @@ -185,8 +185,8 @@ public void simulateSecondHalf(){ @Test @DisplayName("Ten-day plan, no anchors: Simulate Day 3 to Day 8") void simulateMiddle() { - final var simulatedActivities = new HashMap(120); - final var unfinishedActivities = new HashMap(1); + final var simulatedActivities = new HashMap(120); + final var unfinishedActivities = new HashMap(1); final var activitiesInPlan = new HashMap(240); for(int i = 0; i < 72; ++i){ @@ -200,8 +200,8 @@ void simulateMiddle() { new ActivityDirectiveId(i), new ActivityDirective(Duration.of(i, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(i), - new SimulatedActivity( + new ActivityInstanceId(i), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(i, ChronoUnit.HOURS), @@ -220,7 +220,7 @@ void simulateMiddle() { // Activity 192 won't be finished since it starts at the simulation end time unfinishedActivities.put( - new SimulatedActivityId(192), + new ActivityInstanceId(192), new UnfinishedActivity( serializedDelayDirective.getTypeName(), Map.of(), @@ -255,8 +255,8 @@ void simulateMiddle() { @Test @DisplayName("Ten-day plan, no anchors: Simulate from Day -2 to Day 3") void simulateBeforePlanStart() { - final var simulatedActivities = new HashMap(120); - final var unfinishedActivities = new HashMap(1); + final var simulatedActivities = new HashMap(120); + final var unfinishedActivities = new HashMap(1); final var activitiesInPlan = new HashMap(240); for(int i = -48; i < 72; ++i){ @@ -264,8 +264,8 @@ void simulateBeforePlanStart() { new ActivityDirectiveId(i), new ActivityDirective(Duration.of(i, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(i), - new SimulatedActivity( + new ActivityInstanceId(i), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(i, ChronoUnit.HOURS), @@ -284,7 +284,7 @@ void simulateBeforePlanStart() { // Activity 72 won't be finished since it starts at the simulation end time unfinishedActivities.put( - new SimulatedActivityId(72), + new ActivityInstanceId(72), new UnfinishedActivity( serializedDelayDirective.getTypeName(), Map.of(), @@ -319,8 +319,8 @@ void simulateBeforePlanStart() { @Test @DisplayName("Ten-day plan, no anchors: Simulate from Day 8 to Day 13") void simulateAfterPlanEnd() { - final var simulatedActivities = new HashMap(120); - final var unfinishedActivities = new HashMap(1); + final var simulatedActivities = new HashMap(120); + final var unfinishedActivities = new HashMap(1); final var activitiesInPlan = new HashMap(240); for(int i = 72; i < 192; ++i){ @@ -334,8 +334,8 @@ void simulateAfterPlanEnd() { new ActivityDirectiveId(i), new ActivityDirective(Duration.of(i, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(i), - new SimulatedActivity( + new ActivityInstanceId(i), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(i, ChronoUnit.HOURS), @@ -372,8 +372,8 @@ void simulateAfterPlanEnd() { @Test @DisplayName("One-day plan, anchors: Simulate around anchors") void simulateAroundAnchors() { - final var simulatedActivities = new HashMap(16); - final var unfinishedActivities = new HashMap(0); + final var simulatedActivities = new HashMap(16); + final var unfinishedActivities = new HashMap(0); final var activitiesInPlan = new HashMap(37); // 4 sets of activities, each size 4, Hours 3, 4, 5, 6, 7 @@ -382,8 +382,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(0), new ActivityDirective(Duration.of(3, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(0), - new SimulatedActivity( + new ActivityInstanceId(0), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(3, ChronoUnit.HOURS), @@ -398,8 +398,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(1), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(0), true)); simulatedActivities.put( - new SimulatedActivityId(1), - new SimulatedActivity( + new ActivityInstanceId(1), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(4, ChronoUnit.HOURS), @@ -412,8 +412,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(2), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(1), true)); simulatedActivities.put( - new SimulatedActivityId(2), - new SimulatedActivity( + new ActivityInstanceId(2), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(5, ChronoUnit.HOURS), @@ -426,8 +426,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(3), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(2), true)); simulatedActivities.put( - new SimulatedActivityId(3), - new SimulatedActivity( + new ActivityInstanceId(3), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(6, ChronoUnit.HOURS), @@ -440,8 +440,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(4), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(3), true)); simulatedActivities.put( - new SimulatedActivityId(4), - new SimulatedActivity( + new ActivityInstanceId(4), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(7, ChronoUnit.HOURS), @@ -456,8 +456,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(5), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(0), false)); simulatedActivities.put( - new SimulatedActivityId(5), - new SimulatedActivity( + new ActivityInstanceId(5), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(4, ChronoUnit.HOURS).plus(1, ChronoUnit.MINUTES), @@ -470,8 +470,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(6), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(5), false)); simulatedActivities.put( - new SimulatedActivityId(6), - new SimulatedActivity( + new ActivityInstanceId(6), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(5, ChronoUnit.HOURS).plus(2, ChronoUnit.MINUTES), @@ -484,8 +484,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(7), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(6), false)); simulatedActivities.put( - new SimulatedActivityId(7), - new SimulatedActivity( + new ActivityInstanceId(7), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(6, ChronoUnit.HOURS).plus(3, ChronoUnit.MINUTES), @@ -498,8 +498,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(8), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(7), false)); simulatedActivities.put( - new SimulatedActivityId(8), - new SimulatedActivity( + new ActivityInstanceId(8), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(7, ChronoUnit.HOURS).plus(4, ChronoUnit.MINUTES), @@ -514,8 +514,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(9), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(0), true)); simulatedActivities.put( - new SimulatedActivityId(9), - new SimulatedActivity( + new ActivityInstanceId(9), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(4, ChronoUnit.HOURS), @@ -528,8 +528,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(10), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(9), false)); simulatedActivities.put( - new SimulatedActivityId(10), - new SimulatedActivity( + new ActivityInstanceId(10), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(5, ChronoUnit.HOURS).plus(1, ChronoUnit.MINUTES), @@ -542,8 +542,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(11), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(10), true)); simulatedActivities.put( - new SimulatedActivityId(11), - new SimulatedActivity( + new ActivityInstanceId(11), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(6, ChronoUnit.HOURS).plus(1, ChronoUnit.MINUTES), @@ -556,8 +556,8 @@ void simulateAroundAnchors() { new ActivityDirectiveId(12), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(11), false)); simulatedActivities.put( - new SimulatedActivityId(12), - new SimulatedActivity( + new ActivityInstanceId(12), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(7, ChronoUnit.HOURS).plus(2, ChronoUnit.MINUTES), @@ -575,8 +575,8 @@ void simulateAroundAnchors() { // Set 4: No Anchors for(int i = 3; i < 8; i++){ simulatedActivities.put( - new SimulatedActivityId(i+13), - new SimulatedActivity( + new ActivityInstanceId(i + 13), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(i, ChronoUnit.HOURS), @@ -613,8 +613,8 @@ void simulateAroundAnchors() { @Test @DisplayName("One-day plan, anchors: Start simulation between two anchored activities") void simulateStartBetweenAnchors() { - final var simulatedActivities = new HashMap(8); - final var unfinishedActivities = new HashMap(0); + final var simulatedActivities = new HashMap(8); + final var unfinishedActivities = new HashMap(0); final var activitiesInPlan = new HashMap(37); // Three chains, two interrupted (one end-time, one start-time), one not @@ -640,8 +640,8 @@ void simulateStartBetweenAnchors() { new ActivityDirectiveId(5), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(4), true)); simulatedActivities.put( - new SimulatedActivityId(5), - new SimulatedActivity( + new ActivityInstanceId(5), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(3, ChronoUnit.HOURS), @@ -654,8 +654,8 @@ void simulateStartBetweenAnchors() { new ActivityDirectiveId(6), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(5), true)); simulatedActivities.put( - new SimulatedActivityId(6), - new SimulatedActivity( + new ActivityInstanceId(6), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(4, ChronoUnit.HOURS), @@ -668,8 +668,8 @@ void simulateStartBetweenAnchors() { new ActivityDirectiveId(7), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(6), true)); simulatedActivities.put( - new SimulatedActivityId(7), - new SimulatedActivity( + new ActivityInstanceId(7), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(5, ChronoUnit.HOURS), @@ -684,8 +684,8 @@ void simulateStartBetweenAnchors() { new ActivityDirectiveId(8), new ActivityDirective(Duration.of(3, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(8), - new SimulatedActivity( + new ActivityInstanceId(8), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(3, ChronoUnit.HOURS), @@ -698,8 +698,8 @@ void simulateStartBetweenAnchors() { new ActivityDirectiveId(9), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(8), true)); simulatedActivities.put( - new SimulatedActivityId(9), - new SimulatedActivity( + new ActivityInstanceId(9), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(4, ChronoUnit.HOURS), @@ -712,8 +712,8 @@ void simulateStartBetweenAnchors() { new ActivityDirectiveId(10), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(9), true)); simulatedActivities.put( - new SimulatedActivityId(10), - new SimulatedActivity( + new ActivityInstanceId(10), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(5, ChronoUnit.HOURS), @@ -726,8 +726,8 @@ void simulateStartBetweenAnchors() { new ActivityDirectiveId(11), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(10), true)); simulatedActivities.put( - new SimulatedActivityId(11), - new SimulatedActivity( + new ActivityInstanceId(11), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(6, ChronoUnit.HOURS), @@ -774,8 +774,8 @@ void simulateStartBetweenAnchors() { @Test @DisplayName("One-day plan, anchors: End simulation between two anchored activities") void simulateEndBetweenAnchors() { - final var simulatedActivities = new HashMap(8); - final var unfinishedActivities = new HashMap(0); + final var simulatedActivities = new HashMap(8); + final var unfinishedActivities = new HashMap(0); final var activitiesInPlan = new HashMap(37); // Three chains, two interrupted (one end-time, one start-time), one not @@ -784,8 +784,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(0), new ActivityDirective(Duration.of(5, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(0), - new SimulatedActivity( + new ActivityInstanceId(0), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(5, ChronoUnit.HOURS), @@ -798,8 +798,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(1), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(0), false)); simulatedActivities.put( - new SimulatedActivityId(1), - new SimulatedActivity( + new ActivityInstanceId(1), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(6, ChronoUnit.HOURS).plus(1, ChronoUnit.MINUTES), @@ -812,8 +812,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(2), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(1), false)); simulatedActivities.put( - new SimulatedActivityId(2), - new SimulatedActivity( + new ActivityInstanceId(2), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(7, ChronoUnit.HOURS).plus(2, ChronoUnit.MINUTES), @@ -831,8 +831,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(4), new ActivityDirective(Duration.of(5, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(4), - new SimulatedActivity( + new ActivityInstanceId(4), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(5, ChronoUnit.HOURS), @@ -845,8 +845,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(5), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(4), true)); simulatedActivities.put( - new SimulatedActivityId(5), - new SimulatedActivity( + new ActivityInstanceId(5), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(6, ChronoUnit.HOURS), @@ -859,8 +859,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(6), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(5), true)); simulatedActivities.put( - new SimulatedActivityId(6), - new SimulatedActivity( + new ActivityInstanceId(6), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(7, ChronoUnit.HOURS), @@ -878,8 +878,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(8), new ActivityDirective(Duration.of(3, Duration.HOURS), serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(8), - new SimulatedActivity( + new ActivityInstanceId(8), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(3, ChronoUnit.HOURS), @@ -892,8 +892,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(9), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(8), true)); simulatedActivities.put( - new SimulatedActivityId(9), - new SimulatedActivity( + new ActivityInstanceId(9), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(4, ChronoUnit.HOURS), @@ -906,8 +906,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(10), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(9), true)); simulatedActivities.put( - new SimulatedActivityId(10), - new SimulatedActivity( + new ActivityInstanceId(10), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(5, ChronoUnit.HOURS), @@ -920,8 +920,8 @@ void simulateEndBetweenAnchors() { new ActivityDirectiveId(11), new ActivityDirective(Duration.of(1, Duration.HOURS), serializedDelayDirective, new ActivityDirectiveId(10), true)); simulatedActivities.put( - new SimulatedActivityId(11), - new SimulatedActivity( + new ActivityInstanceId(11), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), planStart.plus(6, ChronoUnit.HOURS), @@ -969,8 +969,8 @@ void simulateEndBetweenAnchors() { @Test @DisplayName("One-day plan, no anchors: Simulate no duration. Start at hour 5") void simulateNoDuration() { - final var simulatedActivities = new HashMap(0); - final var unfinishedActivities = new HashMap(1); + final var simulatedActivities = new HashMap(0); + final var unfinishedActivities = new HashMap(1); final var activitiesInPlan = new HashMap(24); for(int i = 0; i < 24; ++i){ @@ -979,7 +979,7 @@ void simulateNoDuration() { new ActivityDirective(Duration.of(i, Duration.HOURS), serializedDelayDirective, null, true)); } unfinishedActivities.put( - new SimulatedActivityId(12), + new ActivityInstanceId(12), new UnfinishedActivity( serializedDelayDirective.getTypeName(), Map.of(), diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/ResponseSerializers.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/ResponseSerializers.java index b2117e5107..42148295cd 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/ResponseSerializers.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/ResponseSerializers.java @@ -6,7 +6,7 @@ import gov.nasa.jpl.aerie.constraints.time.Interval; import gov.nasa.jpl.aerie.json.JsonParseResult.FailureReason; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.UnfinishedActivity; import gov.nasa.jpl.aerie.merlin.driver.json.ValueSchemaJsonParser; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.Parameter; @@ -238,20 +238,20 @@ public static JsonValue serializeInterval(final Interval interval) { .build(); } - private static JsonValue serializeSimulatedActivity(final SimulatedActivity simulatedActivity) { + private static JsonValue serializeSimulatedActivity(final ActivityInstance activityInstance) { return Json .createObjectBuilder() - .add("type", simulatedActivity.type()) - .add("arguments", serializeArgumentMap(simulatedActivity.arguments())) - .add("startTimestamp", serializeTimestamp(simulatedActivity.start())) - .add("duration", serializeDuration(simulatedActivity.duration())) - .add("parent", serializeNullable(id -> Json.createValue(id.id()), simulatedActivity.parentId())) - .add("children", serializeIterable((id -> Json.createValue(id.id())), simulatedActivity.childIds())) - .add("computedAttributes", serializeArgument(simulatedActivity.computedAttributes())) + .add("type", activityInstance.type()) + .add("arguments", serializeArgumentMap(activityInstance.arguments())) + .add("startTimestamp", serializeTimestamp(activityInstance.start())) + .add("duration", serializeDuration(activityInstance.duration())) + .add("parent", serializeNullable(id -> Json.createValue(id.id()), activityInstance.parentId())) + .add("children", serializeIterable((id -> Json.createValue(id.id())), activityInstance.childIds())) + .add("computedAttributes", serializeArgument(activityInstance.computedAttributes())) .build(); } - private static JsonValue serializeSimulatedActivities(final Map simulatedActivities) { + private static JsonValue serializeSimulatedActivities(final Map simulatedActivities) { return serializeMap( ResponseSerializers::serializeSimulatedActivity, simulatedActivities diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/SimulationResultsHandle.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/SimulationResultsHandle.java index fe4183cedd..8a94cec3dd 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/SimulationResultsHandle.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/SimulationResultsHandle.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.models; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivityId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -20,5 +20,5 @@ public interface SimulationResultsHandle { ProfileSet getProfiles(final List profileNames); - Map getSimulatedActivities(); + Map getSimulatedActivities(); } diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/InMemoryResultsCellRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/InMemoryResultsCellRepository.java index 11f842de30..5e60a356ef 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/InMemoryResultsCellRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/InMemoryResultsCellRepository.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.remotes; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivityId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationFailure; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.resources.ResourceProfile; @@ -198,7 +198,7 @@ public ProfileSet getProfiles(final List profileNames) { } @Override - public Map getSimulatedActivities() { + public Map getSimulatedActivities() { return this.simulationResults.simulatedActivities; } diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresResultsCellRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresResultsCellRepository.java index 60d23e6dc7..e6d1c54b6c 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresResultsCellRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresResultsCellRepository.java @@ -1,8 +1,8 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivityId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationException; import gov.nasa.jpl.aerie.merlin.driver.SimulationFailure; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; @@ -313,7 +313,7 @@ private static List> getSimulationTopics(Co } } - private static Pair, Map> getActivities( + private static Pair, Map> getActivities( final Connection connection, final long datasetId, final Timestamp startTime @@ -323,22 +323,22 @@ private static Pair, Map(); - final var unfinishedActivities = new HashMap(); + final var simulatedActivities = new HashMap(); + final var unfinishedActivities = new HashMap(); for (final var entry : activityRecords.entrySet()) { final var pgId = entry.getKey(); final var record = entry.getValue(); - final var activityInstanceId = new SimulatedActivityId(pgId); + final var activityInstanceId = new ActivityInstanceId(pgId); // Only records with duration and computed attributes represent simulated activities if (record.duration().isPresent() && record.attributes().computedAttributes().isPresent()) { - simulatedActivities.put(activityInstanceId, new SimulatedActivity( + simulatedActivities.put(activityInstanceId, new ActivityInstance( record.type(), record.attributes().arguments(), record.start(), record.duration().get(), - record.parentId().map(SimulatedActivityId::new).orElse(null), - record.childIds().stream().map(SimulatedActivityId::new).collect(Collectors.toList()), + record.parentId().map(ActivityInstanceId::new).orElse(null), + record.childIds().stream().map(ActivityInstanceId::new).collect(Collectors.toList()), record.attributes().directiveId().map(ActivityDirectiveId::new), record.attributes().computedAttributes().get() )); @@ -347,8 +347,8 @@ final var record = entry.getValue(); record.type(), record.attributes().arguments(), record.start(), - record.parentId().map(SimulatedActivityId::new).orElse(null), - record.childIds().stream().map(SimulatedActivityId::new).collect(Collectors.toList()), + record.parentId().map(ActivityInstanceId::new).orElse(null), + record.childIds().stream().map(ActivityInstanceId::new).collect(Collectors.toList()), record.attributes().directiveId().map(ActivityDirectiveId::new) )); } @@ -403,8 +403,8 @@ private static void insertSimulationEvents( private static void postActivities( final Connection connection, final long datasetId, - final Map simulatedActivities, - final Map unfinishedActivities, + final Map simulatedActivities, + final Map unfinishedActivities, final Timestamp simulationStart ) throws SQLException { try ( @@ -463,13 +463,13 @@ private static LinkedHashMap topoSort(Map nodes, Function profileNames) { } @Override - public Map getSimulatedActivities() { + public Map getSimulatedActivities() { try (final var connection = this.dataSource.getConnection()) { final var activities = getActivities( connection, diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/DirectiveIdGenerator.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/DirectiveIdGenerator.java new file mode 100644 index 0000000000..4b69e3f82a --- /dev/null +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/DirectiveIdGenerator.java @@ -0,0 +1,17 @@ +package gov.nasa.jpl.aerie.scheduler; + +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; + +public class DirectiveIdGenerator { + private long counter; + + public DirectiveIdGenerator(long startFrom) { + this.counter = startFrom; + } + + public ActivityDirectiveId next() { + final var result = counter; + counter += 1; + return new ActivityDirectiveId(result); + } +} diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityInstanceConflict.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityInstanceConflict.java index 305bf211c2..68b8f32416 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityInstanceConflict.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityInstanceConflict.java @@ -4,7 +4,7 @@ import gov.nasa.jpl.aerie.constraints.time.Interval; import gov.nasa.jpl.aerie.constraints.time.Windows; import gov.nasa.jpl.aerie.scheduler.goals.ActivityExistentialGoal; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; /** * describes an issue in a plan caused by a specific activity instance missing @@ -24,7 +24,7 @@ public class MissingActivityInstanceConflict extends MissingActivityConflict { */ public MissingActivityInstanceConflict( ActivityExistentialGoal goal, - SchedulingActivityDirective instance, + SchedulingActivity instance, EvaluationEnvironment evaluationEnvironment) { super(goal, evaluationEnvironment); @@ -77,13 +77,13 @@ public ActivityExistentialGoal getGoal() { * * @return the specifically requested instance that is desired */ - public SchedulingActivityDirective getInstance() { + public SchedulingActivity getInstance() { return instance; } /** * the specific activity instance that is desired in the plan */ - protected SchedulingActivityDirective instance; + protected SchedulingActivity instance; } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityTemplateConflict.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityTemplateConflict.java index eb2dea12b3..2c254f4579 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityTemplateConflict.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityTemplateConflict.java @@ -2,10 +2,10 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.time.Windows; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.goals.ActivityTemplateGoal; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; import java.util.Optional; @@ -24,7 +24,7 @@ public class MissingActivityTemplateConflict extends MissingActivityConflict { * @param template desired activity template * @param evaluationEnvironment the evaluation environment at the time of creation so variables can be retrieved later at instantiation * @param cardinality the desired number of times the activity template should be inserted - * @param anchorIdTo represents the id of the activty to which we need to create an anchor + * @param anchorIdTo represents the id of the activity to which we need to create an anchor * @param totalDuration the desired total duration */ public MissingActivityTemplateConflict( @@ -33,7 +33,7 @@ public MissingActivityTemplateConflict( ActivityExpression template, EvaluationEnvironment evaluationEnvironment, int cardinality, - Optional anchorIdTo, + Optional anchorIdTo, Optional anchorToStart, Optional totalDuration) { @@ -53,10 +53,10 @@ public MissingActivityTemplateConflict( //the number of times the activity needs to be inserted int cardinality; - Optional anchorIdTo; + Optional anchorIdTo; Optional anchorToStart; - public Optional getAnchorId(){ + public Optional getAnchorId(){ return anchorIdTo; } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingAssociationConflict.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingAssociationConflict.java index 009eed902c..e1c7a6ef3c 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingAssociationConflict.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingAssociationConflict.java @@ -2,18 +2,18 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.time.Windows; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.goals.Goal; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; import java.util.Collection; import java.util.Optional; public class MissingAssociationConflict extends Conflict { - private final Collection instances; + private final Collection instances; private final Optional anchorToStart; - private final Optional anchorIdTo; + private final Optional anchorIdTo; /** * ctor creates a new conflict * @@ -24,8 +24,8 @@ public class MissingAssociationConflict extends Conflict { */ public MissingAssociationConflict( final Goal goal, - final Collection instancesToChooseFrom, - final Optional anchorIdTo, + final Collection instancesToChooseFrom, + final Optional anchorIdTo, final Optional anchorToStart) { @@ -35,11 +35,11 @@ public MissingAssociationConflict( this.anchorToStart = anchorToStart; } - public Collection getActivityInstancesToChooseFrom(){ + public Collection getActivityInstancesToChooseFrom(){ return instances; } - public Optional getAnchorIdTo() { + public Optional getAnchorIdTo() { return anchorIdTo; } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/constraints/activities/ActivityExpression.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/constraints/activities/ActivityExpression.java index 64e5eebbbf..90e73b0f2a 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/constraints/activities/ActivityExpression.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/constraints/activities/ActivityExpression.java @@ -18,12 +18,11 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.NotNull; import gov.nasa.jpl.aerie.scheduler.Nullable; import gov.nasa.jpl.aerie.scheduler.solver.stn.TaskNetworkAdapter; -import kotlin.DeepRecursiveFunction; import org.apache.commons.lang3.tuple.Pair; import java.math.BigDecimal; @@ -203,7 +202,7 @@ public Builder withTimingPrecision(Duration acceptableAbsoluteTimingError){ * prototype for the new search criteria. must not be null. * @return the same builder object updated with new criteria */ - public @NotNull Builder basedOn(@NotNull SchedulingActivityDirective existingAct) { + public @NotNull Builder basedOn(@NotNull SchedulingActivity existingAct) { type = existingAct.getType(); if (existingAct.startOffset() != null) { @@ -298,7 +297,7 @@ Builder basedOn(@NotNull ActivityExpression template) { * the template criteria */ public boolean matches( - final @NotNull SchedulingActivityDirective act, + final @NotNull SchedulingActivity act, final SimulationResults simulationResults, final EvaluationEnvironment evaluationEnvironment, final boolean matchArgumentsExactly) { @@ -311,20 +310,20 @@ public boolean matches( final SimulationResults simulationResults, final EvaluationEnvironment evaluationEnvironment, final boolean matchArgumentsExactly) { - boolean match = (type == null || type.getName().equals(act.type)); + boolean match = (type == null || type.getName().equals(act.type())); if (match && startRange != null) { - final var startT = act.interval.start; + final var startT = act.interval().start; match = (startT != null) && startRange.contains(startT); } if (match && endRange != null) { - final var endT = act.interval.end; + final var endT = act.interval().end; match = (endT != null) && endRange.contains(endT); } if (match && durationRange != null) { - final var dur = act.interval.duration(); + final var dur = act.interval().duration(); final Optional durRequirementLower = this.durationRange.getLeft() .evaluate(simulationResults, evaluationEnvironment) .valueAt(ZERO) @@ -346,9 +345,9 @@ public boolean matches( //activity must have all instantiated arguments of template to be compatible if (match && arguments != null) { - Map actInstanceArguments = act.parameters; - final var instantiatedArguments = SchedulingActivityDirective - .instantiateArguments(arguments, act.interval.start, simulationResults, evaluationEnvironment, type); + Map actInstanceArguments = act.parameters(); + final var instantiatedArguments = SchedulingActivity + .instantiateArguments(arguments, act.interval().start, simulationResults, evaluationEnvironment, type); if(matchArgumentsExactly){ for (var param : instantiatedArguments.entrySet()) { if (actInstanceArguments.containsKey(param.getKey())) { @@ -366,7 +365,7 @@ public boolean matches( } public boolean matches( - final @NotNull SchedulingActivityDirective act, + final @NotNull SchedulingActivity act, final SimulationResults simulationResults, final EvaluationEnvironment evaluationEnvironment, final boolean matchArgumentsExactly, @@ -407,7 +406,7 @@ public boolean matches( //activity must have all instantiated arguments of template to be compatible if (match && arguments != null) { Map actInstanceArguments = act.arguments(); - final var instantiatedArguments = SchedulingActivityDirective + final var instantiatedArguments = SchedulingActivity .instantiateArguments(arguments, act.startOffset(), simulationResults, evaluationEnvironment, type); if(matchArgumentsExactly){ for (var param : instantiatedArguments.entrySet()) { @@ -432,7 +431,7 @@ public Spans evaluate( final EvaluationEnvironment environment) { final var spans = new Spans(); - results.activities.stream().filter(x -> matches(x, results, environment, false)).forEach(x -> spans.add(x.interval)); + results.activities.stream().filter(x -> matches(x, results, environment, false)).forEach(x -> spans.add(x.interval())); return spans; } @@ -458,8 +457,8 @@ public Interval instantiateDurationInterval( final EvaluationEnvironment evaluationEnvironment ){ if(durationRange == null) return null; - Optional durRequirementLower = Optional.empty(); - Optional durRequirementUpper = Optional.empty(); + Optional durRequirementLower; + Optional durRequirementUpper; try { durRequirementLower = durationRange().getLeft() .evaluate(null, planningHorizon.getHor(), evaluationEnvironment) diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CardinalityGoal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CardinalityGoal.java index 9b0b7055e1..880bdb5297 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CardinalityGoal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CardinalityGoal.java @@ -14,9 +14,7 @@ import gov.nasa.jpl.aerie.scheduler.conflicts.UnsatisfiableGoalConflict; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.model.Plan; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; -import org.apache.commons.collections4.BidiMap; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +47,7 @@ public class CardinalityGoal extends ActivityTemplateGoal { /** * Activities inserted so far to satisfy this goal */ - private final Set insertedSoFar = new HashSet<>(); + private final Set insertedSoFar = new HashSet<>(); /** * Current number of steps without inserting an activity with non-zero duration */ @@ -129,7 +127,6 @@ protected CardinalityGoal fill(CardinalityGoal goal) { public Collection getConflicts( final Plan plan, final SimulationResults simulationResults, - final Optional> mapSchedulingIdsToActivityIds, final EvaluationEnvironment evaluationEnvironment, final SchedulerModel schedulerModel) { @@ -141,13 +138,13 @@ public Collection getConflicts( for(Interval subInterval : windows.iterateEqualTo(true)) { final var subIntervalWindows = new Windows(false).set(subInterval, true); - final var acts = new LinkedList(); + final var acts = new LinkedList(); for(final var window : subIntervalWindows.iterateEqualTo(true)){ final var actTB = new ActivityExpression.Builder().basedOn(this.matchActTemplate).startsIn(window).build(); acts.addAll(plan.find(actTB, simulationResults, evaluationEnvironment)); } - acts.sort(Comparator.comparing(SchedulingActivityDirective::startOffset)); + acts.sort(Comparator.comparing(SchedulingActivity::startOffset)); int nbActs = 0; Duration total = Duration.ZERO; var planEvaluation = plan.getEvaluation(); @@ -218,7 +215,7 @@ public Collection getConflicts( private boolean stuckInsertingZeroDurationActivities(final Plan plan, final boolean occurrencePartIsSatisfied){ if(this.durationRange != null && occurrencePartIsSatisfied){ final var inserted = plan.getEvaluation().forGoal(this).getInsertedActivities(); - final var newlyInsertedActivities = inserted.stream().filter(a -> !insertedSoFar.contains(a.getId())).toList(); + final var newlyInsertedActivities = inserted.stream().filter(a -> !insertedSoFar.contains(a.id())).toList(); final var durationNewlyInserted = newlyInsertedActivities.stream().reduce(Duration.ZERO, (partialSum, activityInstance2) -> partialSum.plus(activityInstance2.duration()), Duration::plus); if(durationNewlyInserted.isZero()) { this.stepsWithoutProgress++; @@ -229,7 +226,7 @@ private boolean stuckInsertingZeroDurationActivities(final Plan plan, final bool if(stepsWithoutProgress > maxNoProgressSteps){ return true; } - newlyInsertedActivities.forEach(a -> insertedSoFar.add(a.getId())); + newlyInsertedActivities.forEach(a -> insertedSoFar.add(a.id())); } return false; } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CoexistenceGoal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CoexistenceGoal.java index 4ba2f1ec2c..920a654627 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CoexistenceGoal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CoexistenceGoal.java @@ -18,9 +18,7 @@ import gov.nasa.jpl.aerie.scheduler.constraints.timeexpressions.TimeExpressionRelative; import gov.nasa.jpl.aerie.scheduler.model.PersistentTimeAnchor; import gov.nasa.jpl.aerie.scheduler.model.Plan; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; -import org.apache.commons.collections4.BidiMap; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import java.util.ArrayList; import java.util.HashMap; @@ -182,7 +180,6 @@ protected CoexistenceGoal fill(CoexistenceGoal goal) { public java.util.Collection getConflicts( final Plan plan, final SimulationResults simulationResults, - final Optional> mapSchedulingIdsToActivityIds, final EvaluationEnvironment evaluationEnvironment, final SchedulerModel schedulerModel) { //TODO: check if interval gets split and if so, notify user? @@ -233,7 +230,7 @@ public java.util.Collection getConflicts( simulationResults, createEvaluationEnvironmentFromAnchor(evaluationEnvironment, window)); - var missingActAssociations = new ArrayList(); + var missingActAssociations = new ArrayList(); var planEvaluation = plan.getEvaluation(); var associatedActivitiesToThisGoal = planEvaluation.forGoal(this).getAssociatedActivities(); var alreadyOneActivityAssociated = false; @@ -247,16 +244,15 @@ public java.util.Collection getConflicts( } } if (!alreadyOneActivityAssociated) { - SchedulingActivityDirectiveId anchorIdTo = null; - if (window.value().isPresent() && mapSchedulingIdsToActivityIds.isPresent()){ - final ActivityDirectiveId actId = new ActivityDirectiveId(window.value().get().activityInstance().id); - anchorIdTo = mapSchedulingIdsToActivityIds.get().inverseBidiMap().get(actId); + ActivityDirectiveId anchorIdTo = null; + if (window.value().isPresent()) { + anchorIdTo = window.value().get().activityInstance().directiveId().orElse(null); } - final var missingActAssociationsWithAnchor = new ArrayList(); - final var missingActAssociationsWithoutAnchor = new ArrayList(); + final var missingActAssociationsWithAnchor = new ArrayList(); + final var missingActAssociationsWithoutAnchor = new ArrayList(); /* If activities that can satisfy the goal have been found, then create two arraylist to distinguish between: - 1) those activities that also satisfy the anchoring (e.g. anchorId value equals the SchedulingActivityDirectiveId of the "for each" activity directive in the goal + 1) those activities that also satisfy the anchoring (e.g. anchorId value equals the ActivityDirectiveId of the "for each" activity directive in the goal 2) activities without the anchorId set */ for (var act : activitiesFound) { @@ -288,7 +284,7 @@ public java.util.Collection getConflicts( 1 1 1 MissingAssociationConflict(this, missingActAssociationsWithAnchor, Optional.empty(), false) */ // If anchors are disabled or there are some activity directives that satisfy the goal and already have the anchor or the anchorID is null, then we pass an empty anchor. Otherwise, we pass the anchorID of the directive that can satisfy the goal - final Optional anchorValue = + final Optional anchorValue = (this.persistentAnchor.equals(PersistentTimeAnchor.DISABLED) || !missingActAssociationsWithAnchor.isEmpty() || anchorIdTo == null) ? Optional.empty() : Optional.of(anchorIdTo); // Create MissingActivityTemplateConflict if no matching target activity found @@ -376,9 +372,8 @@ public void extractResources(final Set names) { } /** - * ctor creates an empty goal without details - * - * client code should use builders to instance goals + * Ctor creates an empty goal without details. + * Client code should use builders to instance goals. */ protected CoexistenceGoal() { } } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/Goal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/Goal.java index 8d10f333a0..5fc75c9e2a 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/Goal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/Goal.java @@ -8,12 +8,12 @@ import gov.nasa.jpl.aerie.constraints.tree.Expression; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.conflicts.Conflict; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; import org.apache.commons.collections4.BidiMap; import java.util.LinkedList; @@ -219,11 +219,11 @@ protected Goal fill(Goal goal) { goal.shouldRollbackIfUnsatisfied = this.shouldRollbackIfUnsatisfied; goal.resourceConstraints = null; - if (this.resourceConstraints.size() > 0) { + if (!this.resourceConstraints.isEmpty()) { if (this.resourceConstraints.size() > 1) { goal.resourceConstraints = new And(resourceConstraints); } else { - goal.resourceConstraints = resourceConstraints.get(0); + goal.resourceConstraints = resourceConstraints.getFirst(); } } @@ -297,7 +297,6 @@ public String getName() { public java.util.Collection getConflicts( Plan plan, final SimulationResults simulationResults, - final Optional> mapSchedulingIdsToActivityIds, final EvaluationEnvironment evaluationEnvironment, final SchedulerModel schedulerModel ) { diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/OptionGoal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/OptionGoal.java index 50f4d57f49..be5d7c9912 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/OptionGoal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/OptionGoal.java @@ -6,7 +6,6 @@ import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.scheduler.conflicts.Conflict; import gov.nasa.jpl.aerie.scheduler.model.Plan; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.solver.optimizers.Optimizer; import org.apache.commons.collections4.BidiMap; import org.apache.commons.lang3.NotImplementedException; @@ -38,7 +37,6 @@ public Optimizer getOptimizer(){ public java.util.Collection getConflicts( final Plan plan, final SimulationResults simulationResults, - final Optional> mapSchedulingIdsToActivityIds, final EvaluationEnvironment evaluationEnvironment, final SchedulerModel schedulerModel) { throw new NotImplementedException("Conflict detection is performed at solver level"); diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/ProceduralCreationGoal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/ProceduralCreationGoal.java index 981f40a972..b7cf69fc52 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/ProceduralCreationGoal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/ProceduralCreationGoal.java @@ -4,15 +4,12 @@ import gov.nasa.jpl.aerie.constraints.model.SimulationResults; import gov.nasa.jpl.aerie.constraints.time.Interval; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.conflicts.Conflict; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.conflicts.MissingActivityInstanceConflict; import gov.nasa.jpl.aerie.scheduler.conflicts.MissingAssociationConflict; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; -import org.apache.commons.collections4.BidiMap; import java.util.ArrayList; import java.util.Collection; @@ -60,12 +57,12 @@ public static class Builder extends ActivityExistentialGoal.Builder { * function. may be called out of order from different contexts. * @return this builder, ready for additional specification */ - public Builder generateWith(Function> generator) { + public Builder generateWith(Function> generator) { this.generateWith = generator; return this; } - protected Function> generateWith; + protected Function> generateWith; /** * {@inheritDoc} @@ -117,7 +114,6 @@ protected ProceduralCreationGoal fill(ProceduralCreationGoal goal) { public Collection getConflicts( final Plan plan, final SimulationResults simulationResults, - final Optional> mapSchedulingIdsToActivityIds, final EvaluationEnvironment evaluationEnvironment, final SchedulerModel schedulerModel) { final var conflicts = new java.util.LinkedList(); @@ -137,7 +133,7 @@ public Collection getConflicts( .build(); final var matchingActs = plan.find(satisfyingActSearch, simulationResults, new EvaluationEnvironment()); - var missingActAssociations = new ArrayList(); + var missingActAssociations = new ArrayList(); var planEvaluation = plan.getEvaluation(); var associatedActivitiesToThisGoal = planEvaluation.forGoal(this).getAssociatedActivities(); var alreadyOneActivityAssociated = false; @@ -202,7 +198,7 @@ protected ProceduralCreationGoal() { } * internal state that could produce variant results on re-invocation * with different hypothetical inputs */ - protected Function> generator; + protected Function> generator; /** * use the generator to determine the set of relevant activity requests @@ -217,7 +213,7 @@ protected ProceduralCreationGoal() { } * are deemed relevant to this goal (eg within the temporal context * of this goal) */ - private Collection getRelevantGeneratedActivities(Plan plan, SimulationResults simulationResults, EvaluationEnvironment evaluationEnvironment) { + private Collection getRelevantGeneratedActivities(Plan plan, SimulationResults simulationResults, EvaluationEnvironment evaluationEnvironment) { //run the generator in the plan context final var allActs = generator.apply(plan); diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/RecurrenceGoal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/RecurrenceGoal.java index 36995145e4..5a6839f43b 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/RecurrenceGoal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/RecurrenceGoal.java @@ -4,19 +4,16 @@ import gov.nasa.jpl.aerie.constraints.model.SimulationResults; import gov.nasa.jpl.aerie.constraints.time.Interval; import gov.nasa.jpl.aerie.constraints.time.Windows; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.DurationType; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.conflicts.Conflict; import gov.nasa.jpl.aerie.scheduler.conflicts.MissingActivityConflict; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.conflicts.MissingActivityTemplateConflict; import gov.nasa.jpl.aerie.scheduler.conflicts.MissingAssociationConflict; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; -import org.apache.commons.collections4.BidiMap; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -116,7 +113,6 @@ else if (every.max.isNegative()) { public java.util.Collection getConflicts( @NotNull final Plan plan, final SimulationResults simulationResults, - final Optional> mapSchedulingIdsToActivityIds, final EvaluationEnvironment evaluationEnvironment, final SchedulerModel schedulerModel) { final var conflicts = new java.util.LinkedList(); @@ -142,7 +138,7 @@ public java.util.Collection getConflicts( .startsIn(subInterval) .build(); final var acts = new java.util.LinkedList<>(plan.find(satisfyingActSearch, simulationResults, new EvaluationEnvironment())); - acts.sort(java.util.Comparator.comparing(SchedulingActivityDirective::startOffset)); + acts.sort(java.util.Comparator.comparing(SchedulingActivity::startOffset)); //walk through existing matching activities to find too-large gaps, //starting from the goal's own start time diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Plan.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Plan.java index c263617651..f4c2dec08f 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Plan.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Plan.java @@ -2,6 +2,7 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.model.SimulationResults; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.solver.Evaluation; @@ -32,7 +33,7 @@ public interface Plan { * * @param acts IN the set of activity instances to schedule into the plan */ - void add(Collection acts); + void add(Collection acts); /** * adds the given activity instance to the scheduled plan solution @@ -41,7 +42,7 @@ public interface Plan { * * @param act IN activity instance to schedule into the plan */ - void add(SchedulingActivityDirective act); + void add(SchedulingActivity act); /** * adds the given activity instances to the scheduled plan solution * @@ -49,7 +50,7 @@ public interface Plan { * * @param acts IN the set of activity instances to remove from the plan */ - void remove(Collection acts); + void remove(Collection acts); /** * removes the given activity instance to the scheduled plan solution @@ -58,47 +59,47 @@ public interface Plan { * * @param act IN activity instance to remove from the plan */ - void remove(SchedulingActivityDirective act); + void remove(SchedulingActivity act); /** * replace and old activity by a new one * @param oldAct Old Activity * @param newAct New Activity */ - void replaceActivity(SchedulingActivityDirective oldAct, SchedulingActivityDirective newAct); + void replaceActivity(SchedulingActivity oldAct, SchedulingActivity newAct); /** * fetches activities in the plan ordered by start time * * @return set of all activities in the plan ordered by start time */ - List getActivitiesByTime(); + List getActivitiesByTime(); /** * fetches activities in the plan by type * * @return map of all activities in the plan by type */ - Map> getActivitiesByType(); + Map> getActivitiesByType(); /** * fetches activities in the plan by id * * @return map of all activities in the plan by id */ - Map getActivitiesById(); + Map getActivitiesById(); /** * fetches activities in the plan * * @return set of all activities in the plan */ - Set getActivities(); + Set getActivities(); /** * @return the set of anchors from all activities in the plan */ - Set getAnchorIds(); + Set getAnchorIds(); /** * finds activity instances in the plan that meet the given criteria @@ -106,7 +107,7 @@ public interface Plan { * @param template IN the matching criteria to use on activity instances * @return collection of instances that match the given template */ - Collection find( + Collection find( ActivityExpression template, SimulationResults simulationResults, EvaluationEnvironment evaluationEnvironment); /** * adds a new evaluation to the plan @@ -125,5 +126,5 @@ Collection find( */ Evaluation getEvaluation(); - Duration calculateAbsoluteStartOffsetAnchoredActivity(SchedulingActivityDirective actAnchorTo); + Duration calculateAbsoluteStartOffsetAnchoredActivity(SchedulingActivity actAnchorTo); } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/PlanInMemory.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/PlanInMemory.java index a7a3c440a1..cc97ba5d0b 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/PlanInMemory.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/PlanInMemory.java @@ -2,6 +2,7 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.model.SimulationResults; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.solver.Evaluation; @@ -36,7 +37,7 @@ public class PlanInMemory implements Plan { /** * container of all activity instances in plan, indexed by start time */ - private final TreeMap> actsByTime; + private final TreeMap> actsByTime; /** * ctor creates a new empty solution plan @@ -63,7 +64,7 @@ public Plan duplicate() { * {@inheritDoc} */ @Override - public void add(Collection acts) { + public void add(Collection acts) { for (final var act : acts) { add(act); } @@ -81,7 +82,7 @@ public int size(){ * {@inheritDoc} */ @Override - public void add(final SchedulingActivityDirective act) { + public void add(final SchedulingActivity act) { if (act == null) { throw new IllegalArgumentException( "adding null activity to plan"); @@ -91,21 +92,19 @@ public void add(final SchedulingActivityDirective act) { throw new IllegalArgumentException( "adding activity with null start time to plan"); } - final var id = act.getId(); - assert id != null; actsByTime.computeIfAbsent(startT, k -> new LinkedList<>()) .add(act); } @Override - public void remove(Collection acts) { + public void remove(Collection acts) { for (var act : acts) { remove(act); } } @Override - public void remove(SchedulingActivityDirective act) { + public void remove(SchedulingActivity act) { var acts = actsByTime.get(act.startOffset()); if (acts != null) acts.remove(act); } @@ -114,9 +113,9 @@ public void remove(SchedulingActivityDirective act) { * {@inheritDoc} */ @Override - public List getActivitiesByTime() { + public List getActivitiesByTime() { //REVIEW: could probably do something tricky with streams to avoid new - final var orderedActs = new LinkedList(); + final var orderedActs = new LinkedList(); //NB: tree map ensures that values are in key order, but still need to flatten for (final var actsAtT : actsByTime.values()) { @@ -127,7 +126,7 @@ public List getActivitiesByTime() { return Collections.unmodifiableList(orderedActs); } - public void replaceActivity(SchedulingActivityDirective oldAct, SchedulingActivityDirective newAct){ + public void replaceActivity(SchedulingActivity oldAct, SchedulingActivity newAct){ this.remove(oldAct); this.add(newAct); if(evaluation != null) this.evaluation.updateGoalEvals(oldAct, newAct); @@ -137,8 +136,8 @@ public void replaceActivity(SchedulingActivityDirective oldAct, SchedulingActivi * {@inheritDoc} */ @Override - public Map> getActivitiesByType() { - final var map = new HashMap>(); + public Map> getActivitiesByType() { + final var map = new HashMap>(); for(final var entry: this.actsByTime.entrySet()){ for(final var activity : entry.getValue()){ map.computeIfAbsent(activity.type(), t -> new ArrayList<>()).add(activity); @@ -148,8 +147,8 @@ public Map> getActivitiesByType( } @Override - public Map getActivitiesById() { - final var map = new HashMap(); + public Map getActivitiesById() { + final var map = new HashMap(); for(final var entry: this.actsByTime.entrySet()){ for(final var activity : entry.getValue()){ map.put(activity.id(), activity); @@ -159,9 +158,9 @@ public Map getActivi } @Override - public Set getAnchorIds() { + public Set getAnchorIds() { return getActivities().stream() - .map(SchedulingActivityDirective::anchorId) + .map(SchedulingActivity::anchorId) .collect(Collectors.toSet()); } @@ -169,8 +168,8 @@ public Set getAnchorIds() { * {@inheritDoc} */ @Override - public Set getActivities() { - final var set = new HashSet(); + public Set getActivities() { + final var set = new HashSet(); for(final var entry: this.actsByTime.entrySet()){ set.addAll(entry.getValue()); } @@ -181,13 +180,13 @@ public Set getActivities() { * {@inheritDoc} */ @Override - public Collection find( + public Collection find( ActivityExpression template, SimulationResults simulationResults, EvaluationEnvironment evaluationEnvironment) { //REVIEW: could do something clever with returning streams to prevent wasted work //REVIEW: something more clever for time-based queries using time index - LinkedList matched = new LinkedList<>(); + LinkedList matched = new LinkedList<>(); for (final var actsAtTime : actsByTime.values()) { for (final var act : actsAtTime) { if (template.matches(act, simulationResults, evaluationEnvironment, true, this)) { @@ -215,11 +214,11 @@ public Evaluation getEvaluation() { } @Override - public Duration calculateAbsoluteStartOffsetAnchoredActivity(SchedulingActivityDirective act){ + public Duration calculateAbsoluteStartOffsetAnchoredActivity(SchedulingActivity act){ if(act == null) return null; if(act.anchorId() != null){ - SchedulingActivityDirective parent = this.getActivitiesById().get(act.anchorId()); + SchedulingActivity parent = this.getActivitiesById().get(act.anchorId()); if(!act.anchoredToStart() && parent.duration() == null) throw new IllegalArgumentException("Cannot calculate the absolute duration for an activity that is not anchored to the start while the parent doesn't have duration"); return calculateAbsoluteStartOffsetAnchoredActivity(parent).plus(act.anchoredToStart() ? act.startOffset() : act.startOffset().plus(parent.duration())); diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Problem.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Problem.java index c0a6774aa7..c046c6a295 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Problem.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Problem.java @@ -146,14 +146,14 @@ public Plan getInitialPlan() { */ public void setInitialPlan( final Plan plan, - final Optional initialSimulationResults, - final BidiMap mapSchedulingIdsToActivityIds) { + final Optional initialSimulationResults + ) { initialPlan = plan; this.initialSimulationResults = initialSimulationResults.map(simulationResults -> new SimulationData( plan, simulationResults, - SimulationResultsConverter.convertToConstraintModelResults(simulationResults), - Optional.ofNullable(mapSchedulingIdsToActivityIds))); + SimulationResultsConverter.convertToConstraintModelResults(simulationResults) + )); } /** @@ -162,7 +162,7 @@ public void setInitialPlan( * @param plan the initial seed plan that schedulers may start from */ public void setInitialPlan(final Plan plan) { - setInitialPlan(plan, Optional.empty(), null); + setInitialPlan(plan, Optional.empty()); } public Optional getInitialSimulationResults(){ return initialSimulationResults; } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulePlanGrounder.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulePlanGrounder.java index 7cf9e621cb..8da3da77ca 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulePlanGrounder.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulePlanGrounder.java @@ -11,24 +11,30 @@ import java.util.HashMap; import java.util.List; import java.util.Optional; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; public class SchedulePlanGrounder { public static Optional> groundSchedule( - final List schedulingActivityDirectiveList, + final List schedulingActivityList, final Duration planDuration ){ - final var grounded = new HashMap(); + final var groundedDirectives = new HashMap(); - final var idMap = schedulingActivityDirectiveList + final var idMap = schedulingActivityList .stream() - .map(a -> Pair.of(new ActivityDirectiveId(a.getId().id()), a)) + .map(a -> Pair.of(a.id(), a)) + .filter($ -> $.getKey() != null) .collect(Collectors.toMap(Pair::getLeft, Pair::getRight)); - final var converted = schedulingActivityDirectiveList + final var maxDirectiveId = idMap.keySet() + .stream().map(ActivityDirectiveId::id) + .max(Long::compare); + + final var converted = schedulingActivityList .stream() .map(a -> Pair.of( - new ActivityDirectiveId(a.id().id()), + a.id(), new ActivityDirective( a.startOffset(), a.type().getName(), @@ -36,6 +42,7 @@ public static Optional> groundSchedule( (a.anchorId() == null) ? null : new ActivityDirectiveId(a.anchorId().id()), a.anchoredToStart() ))) + .filter($ -> $.getKey() != null) .collect(Collectors.toMap(Pair::getLeft, Pair::getRight)); final var converter = new StartOffsetReducer(planDuration, converted); var computed = converter.compute(); @@ -45,11 +52,11 @@ public static Optional> groundSchedule( Duration offset = Duration.ZERO; final var idActivity = directive.getKey(); if(idActivity != null){ - if(grounded.get(idActivity) == null){ + if(groundedDirectives.get(idActivity) == null){ return Optional.empty(); } else { - final var alreadyGroundedAct = grounded.get(idActivity); - offset = alreadyGroundedAct.interval.end; + final var alreadyGroundedAct = groundedDirectives.get(idActivity); + offset = alreadyGroundedAct.interval().end; } } for(final Pair dependentDirective : directive.getValue()) { @@ -60,13 +67,32 @@ public static Optional> groundSchedule( if(dependentOriginalActivity.duration() == null){ return Optional.empty(); } - grounded.put(dependentId, new ActivityInstance( + groundedDirectives.put(dependentId, new ActivityInstance( dependentId.id(), dependentOriginalActivity.type().getName(), dependentOriginalActivity.arguments(), - Interval.between(startTime, startTime.plus(dependentOriginalActivity.duration())))); + Interval.between(startTime, startTime.plus(dependentOriginalActivity.duration())), + Optional.of(new ActivityDirectiveId(dependentId.id())) + )); } } - return Optional.of(grounded.values().stream().toList()); + final var result = new java.util.ArrayList<>(groundedDirectives.values().stream().toList()); + + final var instanceIdCounter = new AtomicLong(maxDirectiveId.orElse(0L) + 1L); + result.addAll( + schedulingActivityList + .stream() + .filter($ -> $.id() == null) + .map($ -> new ActivityInstance( + instanceIdCounter.getAndIncrement(), + $.type().getName(), + $.arguments(), + Interval.between($.startOffset(), $.startOffset().plus($.duration())), + Optional.empty() + )) + .toList() + ); + + return Optional.of(result); } } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivity.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivity.java new file mode 100644 index 0000000000..b2e55bc2f9 --- /dev/null +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivity.java @@ -0,0 +1,283 @@ +package gov.nasa.jpl.aerie.scheduler.model; + + +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.tree.ProfileExpression; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * Contains all known information about an activity, representing BOTH directive-only information + * and instance-only information. + * If an activity only has a directive and hasn't been simulated, instance-specific data like duration + * will be null. If an activity is generated during simulation and thus doesn't have a directive, directive + * ID will be null. Only generated activities can have a non-null parent. + * + * @param id unique id + * @param type the descriptor for the behavior invoked by this activity instance + * @param startOffset the time at which this activity instance is scheduled to start + * @param duration the length of time this activity instances lasts for after its start + * @param arguments arguments are stored in a String/SerializedValue hashmap. + * @param topParent the parent activity if any + * @param isNew whether this activity was created in this scheduling run, or already existed in the plan + */ +public record SchedulingActivity( + ActivityDirectiveId id, + ActivityType type, + Duration startOffset, + Duration duration, + Map arguments, + ActivityDirectiveId topParent, + ActivityDirectiveId anchorId, + boolean anchoredToStart, + boolean isNew +) { + + public static SchedulingActivity of( + ActivityDirectiveId id, + ActivityType type, + Duration startOffset, + Duration duration, + ActivityDirectiveId anchorId, + boolean anchoredToStart, + boolean isNew + ) { + return new SchedulingActivity( + id, + type, + startOffset, + duration, + Map.of(), + null, + anchorId, + anchoredToStart, + isNew + ); + } + + public static SchedulingActivity of( + ActivityDirectiveId id, + ActivityType type, + Duration startOffset, + Duration duration, + Map parameters, + ActivityDirectiveId topParent, + ActivityDirectiveId anchorId, + boolean anchoredToStart, + boolean isNew + ) { + return new SchedulingActivity( + id, + type, + startOffset, + duration, + parameters, + topParent, + anchorId, + anchoredToStart, + isNew + ); + } + + public SchedulingActivity withNewDuration(Duration duration){ + return SchedulingActivity.of( + this.id, + this.type, + this.startOffset, + duration, + new HashMap<>(this.arguments), + this.topParent, + this.anchorId, + this.anchoredToStart, + this.isNew() + ); + } + + public SchedulingActivity withNewAnchor(ActivityDirectiveId anchorId, boolean anchoredToStart, Duration startOffset) { + return SchedulingActivity.of( + this.id, + this.type, + startOffset, + this.duration, + new HashMap<>(this.arguments), + this.topParent, + anchorId, + anchoredToStart, + this.isNew + ); + } + + public SchedulingActivity withNewDirectiveId(ActivityDirectiveId id) { + return SchedulingActivity.of( + id, + this.type, + startOffset, + this.duration, + new HashMap<>(this.arguments), + this.topParent, + this.anchorId, + this.anchoredToStart, + this.isNew + ); + } + + public SchedulingActivity withNewTopParent(ActivityDirectiveId topParent) { + return SchedulingActivity.of( + this.id, + this.type, + startOffset, + this.duration, + new HashMap<>(this.arguments), + topParent, + this.anchorId, + this.anchoredToStart, + this.isNew + ); + } + + public static SchedulingActivity fromExistingActivityDirective(ActivityDirectiveId id, ActivityDirective activity, ActivityType type, Duration duration){ + return SchedulingActivity.of( + id, + type, + activity.startOffset(), + duration, + activity.serializedActivity().getArguments(), + null, + activity.anchorId(), + activity.anchoredToStart(), + false + ); + } + + /** + * Returns the id of parent activity if this activity is generated. + */ + public Optional getParentActivity(){ + return Optional.ofNullable(topParent); + } + + public Duration getEndTime(){ + return startOffset.plus(duration); + } + + /** + * fetches the activity with the earliest end time in a list of activity instances + * + * @return the activity + */ + public static SchedulingActivity getActWithEarliestEndTime(List acts) { + if (!acts.isEmpty()) { + acts.sort(Comparator.comparing(SchedulingActivity::getEndTime)); + + return acts.getFirst(); + } + return null; + } + + /** + * fetches the activity with the latest end time in a list of activity instances + * + * @return the activity + */ + public static SchedulingActivity getActWithLatestEndTime(List acts) { + if (!acts.isEmpty()) { + acts.sort(Comparator.comparing(SchedulingActivity::getEndTime)); + + return acts.getLast(); + } + return null; + } + + /** + * fetches the activity with the earliest starting time in a list of activity instances + * + * @return the activity + */ + public static SchedulingActivity getActWithEarliestStartTime(List acts) { + if (!acts.isEmpty()) { + acts.sort(Comparator.comparing(SchedulingActivity::startOffset)); + + return acts.getFirst(); + } + return null; + } + + /** + * fetches the activity with the latest starting time in a list of activity instances + * + * @return the activity + */ + public static SchedulingActivity getActWithLatestStartTime(List acts) { + if (!acts.isEmpty()) { + acts.sort(Comparator.comparing(SchedulingActivity::startOffset)); + + return acts.getLast(); + } + return null; + } + + /** + * fetches the activity type specification that this instance is based on + * + * @return the activity type specification that this instance is based on + */ + public ActivityType getType() { + return type; + } + + public String toString() { + return "[" + this.type.getName() + ","+ this.id + "," + startOffset + "," + ((duration != null) ? getEndTime() : "no duration") + ", "+ topParent + ", " + anchorId+", "+anchoredToStart+"]"; + } + + /** + * Checks equality but not in name + * @param that the other activity instance to compare to + * @return true if they are equal in properties, false otherwise + */ + public boolean equalsInProperties(final SchedulingActivity that){ + return type.equals(that.type) + && duration.isEqualTo(that.duration) + && startOffset.isEqualTo(that.startOffset) + && arguments.equals(that.arguments) + && Objects.equals(topParent, that.topParent) + && Objects.equals(anchorId, that.anchorId) + && (anchoredToStart == that.anchoredToStart); + } + + public static Map instantiateArguments(final Map> arguments, + final Duration startTime, + final SimulationResults simulationResults, + final EvaluationEnvironment environment, + final ActivityType activityType){ + final var results = new HashMap(); + arguments.forEach((key, value) -> + results.put(key, + value.evaluate(simulationResults, Interval.between(startTime, startTime), environment) + .valueAt(startTime) + .orElseThrow(() -> new Error("Profile for argument " + key + " has no value at time " + startTime))) + ); + return results; + } + + /** + * adds an argument to the activity instance + * + * @param argument specification. must be identical as the one defined in the model + * @param param value of the argument + */ + public void addArgument(String argument, SerializedValue param) { + assert(type.isParamLegal(argument)); + arguments.put(argument, param); + } +} diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivityDirective.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivityDirective.java deleted file mode 100644 index 87550b9011..0000000000 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivityDirective.java +++ /dev/null @@ -1,321 +0,0 @@ -package gov.nasa.jpl.aerie.scheduler.model; - - -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.tree.ProfileExpression; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; - -/** - * @param id unique id - * @param type the descriptor for the behavior invoked by this activity instance - * @param startOffset the time at which this activity instance is scheduled to start - * @param duration the length of time this activity instances lasts for after its start - * @param arguments arguments are stored in a String/SerializedValue hashmap. - * @param topParent the parent activity if any - */ -public record SchedulingActivityDirective( - SchedulingActivityDirectiveId id, - ActivityType type, - Duration startOffset, - Duration duration, - Map arguments, - SchedulingActivityDirectiveId topParent, - SchedulingActivityDirectiveId anchorId, - boolean anchoredToStart - ){ - - private static final AtomicLong uniqueId = new AtomicLong(); - - - /** - * creates a new unscheduled activity instance of specified type - * - * @param type IN the datatype signature of and behavior descriptor invoked - * by this activity instance - */ - //TODO: reconsider unscheduled activity instances - public static SchedulingActivityDirective of(ActivityType type, SchedulingActivityDirectiveId anchorId, boolean anchoredToStart) { - return new SchedulingActivityDirective(new SchedulingActivityDirectiveId(uniqueId.getAndIncrement()), type, - Duration.ZERO, - Duration.ZERO, - Map.of(), null, - anchorId, anchoredToStart); - } - - /** - * creates a new activity instance of specified type - * - * @param type IN the datatype signature of and behavior descriptor invoked - * by this activity instance - * @param startOffset IN the time at which the activity is scheduled - */ - public static SchedulingActivityDirective of(ActivityType type, Duration startOffset, SchedulingActivityDirectiveId anchorId, boolean anchoredToStart) { - return new SchedulingActivityDirective(new SchedulingActivityDirectiveId(uniqueId.getAndIncrement()), type, - startOffset, - Duration.ZERO, - Map.of(), null, - anchorId, anchoredToStart); - } - - /** - * creates a new activity instance of specified type - * - * @param type IN the datatype signature of and behavior descriptor invoked - * by this activity instance - * @param startOffset IN the time at which the activity is scheduled - * @param duration IN the duration that the activity lasts for - */ - public static SchedulingActivityDirective of(ActivityType type, Duration startOffset, Duration duration, SchedulingActivityDirectiveId anchorId, boolean anchoredToStart) { - return new SchedulingActivityDirective(new SchedulingActivityDirectiveId(uniqueId.getAndIncrement()), type, - startOffset, - duration, - Map.of(), null, anchorId, anchoredToStart); - - } - public static SchedulingActivityDirective of(SchedulingActivityDirectiveId id, ActivityType type, Duration startOffset, Duration duration, SchedulingActivityDirectiveId anchorId, boolean anchoredToStart) { - return new SchedulingActivityDirective( - id, - type, - startOffset, - duration, - Map.of(), - null, - anchorId, - anchoredToStart); - } - - public static SchedulingActivityDirective of(ActivityType type, Duration startOffset, Duration duration, Map parameters, SchedulingActivityDirectiveId anchorId, boolean anchoredToStart) { - return new SchedulingActivityDirective(new SchedulingActivityDirectiveId(uniqueId.getAndIncrement()), type, - startOffset, - duration, - parameters, null, anchorId, anchoredToStart); - } - - public static SchedulingActivityDirective of(ActivityType type, Duration startOffset, Duration duration, Map parameters, SchedulingActivityDirectiveId topParent, SchedulingActivityDirectiveId anchorId, boolean anchoredToStart) { - return new SchedulingActivityDirective(new SchedulingActivityDirectiveId(uniqueId.getAndIncrement()), type, - startOffset, - duration, - parameters, topParent, anchorId, anchoredToStart); - } - - public static SchedulingActivityDirective of( - SchedulingActivityDirectiveId id, - ActivityType type, - Duration startOffset, - Duration duration, - Map parameters, - SchedulingActivityDirectiveId topParent, - SchedulingActivityDirectiveId anchorId, - boolean anchoredToStart) { - return new SchedulingActivityDirective( - id, - type, - startOffset, - duration, - parameters, - topParent, - anchorId, - anchoredToStart); - } - - public static SchedulingActivityDirective copyOf(SchedulingActivityDirective activityInstance, Duration duration){ - return SchedulingActivityDirective.of( - activityInstance.id, - activityInstance.type, - activityInstance.startOffset, - duration, - new HashMap<>(activityInstance.arguments), - activityInstance.topParent, - activityInstance.anchorId, - activityInstance.anchoredToStart); - } - - public static SchedulingActivityDirective copyOf(SchedulingActivityDirective activityInstance, SchedulingActivityDirectiveId anchorId, boolean anchoredToStart, Duration startOffset){ - return SchedulingActivityDirective.of( - activityInstance.id, - activityInstance.type, - startOffset, - activityInstance.duration, - new HashMap<>(activityInstance.arguments), - activityInstance.topParent, - anchorId, - anchoredToStart); - } - - /** - * Scheduler Activity Directives generated from the Plan have their ID set to the negative of the ActivityDirectiveId - */ - public static SchedulingActivityDirective fromActivityDirective(ActivityDirectiveId id, ActivityDirective activity, ActivityType type, Duration duration){ - return SchedulingActivityDirective.of( - new SchedulingActivityDirectiveId(-id.id()), - type, - activity.startOffset(), - duration, - activity.serializedActivity().getArguments(), - null, - (activity.anchorId() != null ? new SchedulingActivityDirectiveId(-activity.anchorId().id()) : null), - activity.anchoredToStart()); - } - - /** - * create an activity instance based on the provided one (but a different id) - * - * @param o IN the activity instance to copy from - */ - public static SchedulingActivityDirective of(SchedulingActivityDirective o) { - return new SchedulingActivityDirective( - new SchedulingActivityDirectiveId(uniqueId.getAndIncrement()), - o.type, - o.startOffset, o.duration, - Map.copyOf(o.arguments), - o.topParent, - o.anchorId, - o.anchoredToStart - ); - } - - /** - * Returns the id of parent activity if this activity is generated. - */ - public Optional getParentActivity(){ - return Optional.ofNullable(topParent); - } - - public Duration getEndTime(){ - return startOffset.plus(duration); - } - - /** - * fetches the activity with the earliest end time in a list of activity instances - * - * @return the activity - */ - public static SchedulingActivityDirective getActWithEarliestEndTime(List acts) { - if (acts.size() > 0) { - acts.sort(Comparator.comparing(SchedulingActivityDirective::getEndTime)); - - return acts.get(0); - } - return null; - } - - /** - * fetches the activity with the latest end time in a list of activity instances - * - * @return the activity - */ - public static SchedulingActivityDirective getActWithLatestEndTime(List acts) { - if (acts.size() > 0) { - acts.sort(Comparator.comparing(SchedulingActivityDirective::getEndTime)); - - return acts.get(acts.size() - 1); - } - return null; - } - - /** - * fetches the activity with the earliest starting time in a list of activity instances - * - * @return the activity - */ - public static SchedulingActivityDirective getActWithEarliestStartTime(List acts) { - if (acts.size() > 0) { - acts.sort(Comparator.comparing(SchedulingActivityDirective::startOffset)); - - return acts.get(0); - } - return null; - } - - /** - * fetches the activity with the latest starting time in a list of activity instances - * - * @return the activity - */ - public static SchedulingActivityDirective getActWithLatestStartTime(List acts) { - if (acts.size() > 0) { - acts.sort(Comparator.comparing(SchedulingActivityDirective::startOffset)); - - return acts.get(acts.size() - 1); - } - return null; - } - - - - /** - * fetches the human-legible identifier of the activity instance - * - * @return a human-legible identifier for this activity instance - */ - public SchedulingActivityDirectiveId getId() { - return this.id; - } - - /** - * fetches the activity type specification that this instance is based on - * - * @return the activity type specification that this instance is based on - */ - public ActivityType getType() { - return type; - } - - public String toString() { - return "[" + this.type.getName() + ","+ this.id + "," + startOffset + "," + ((duration != null) ? getEndTime() : "no duration") + ", "+ topParent + ", " + anchorId+", "+anchoredToStart+"]"; - } - - /** - * Checks equality but not in name - * @param that the other activity instance to compare to - * @return true if they are equal in properties, false otherwise - */ - public boolean equalsInProperties(final SchedulingActivityDirective that){ - return type.equals(that.type) - && duration.isEqualTo(that.duration) - && startOffset.isEqualTo(that.startOffset) - && arguments.equals(that.arguments) - && Objects.equals(topParent, that.topParent) - && Objects.equals(anchorId, that.anchorId) - && (anchoredToStart == that.anchoredToStart); - } - - public static Map instantiateArguments(final Map> arguments, - final Duration startTime, - final SimulationResults simulationResults, - final EvaluationEnvironment environment, - final ActivityType activityType){ - final var results = new HashMap(); - arguments.forEach((key, value) -> - results.put(key, - value.evaluate(simulationResults, Interval.between(startTime, startTime), environment) - .valueAt(startTime) - .orElseThrow(() -> new Error("Profile for argument " + key + " has no value at time " + startTime))) - ); - return results; - } - - /** - * adds an argument to the activity instance - * - * @param argument specification. must be identical as the one defined in the model - * @param param value of the argument - */ - public void addArgument(String argument, SerializedValue param) { - assert(type.isParamLegal(argument)); - arguments.put(argument, param); - } -} diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivityDirectiveId.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivityDirectiveId.java deleted file mode 100644 index 5c957285b4..0000000000 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivityDirectiveId.java +++ /dev/null @@ -1,3 +0,0 @@ -package gov.nasa.jpl.aerie.scheduler.model; - -public record SchedulingActivityDirectiveId(long id) {} diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacade.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacade.java index d779ceed27..a597106377 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacade.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacade.java @@ -15,7 +15,7 @@ import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -109,25 +109,11 @@ public void addActivityTypes(final Collection activityTypes) { activityTypes.forEach(at -> this.activityTypes.put(at.getName(), at)); } - private void replaceValue(final Map map, final V value, final V replacement) { - for (final Map.Entry entry : map.entrySet()) { - if (entry.getValue().equals(value)) { - entry.setValue(replacement); - break; - } - } - } - private void replaceIds( final PlanSimCorrespondence planSimCorrespondence, - final Map updates) - { - for (final var replacements : updates.entrySet()) { - replaceValue( - planSimCorrespondence.planActDirectiveIdToSimulationActivityDirectiveId(), - replacements.getKey(), - replacements.getValue()); - if (planSimCorrespondence.directiveIdActivityDirectiveMap().containsKey(replacements.getKey())) { + final Map updates){ + for(final var replacements : updates.entrySet()){ + if(planSimCorrespondence.directiveIdActivityDirectiveMap().containsKey(replacements.getKey())){ final var value = planSimCorrespondence.directiveIdActivityDirectiveMap().remove(replacements.getKey()); planSimCorrespondence.directiveIdActivityDirectiveMap().put(replacements.getValue(), value); } @@ -174,7 +160,7 @@ public SimulationResultsComputerInputs simulateNoResultsAllActivities(final Plan @Override public SimulationResultsComputerInputs simulateNoResultsUntilEndAct( final Plan plan, - final SchedulingActivityDirective activity) + final SchedulingActivity activity) throws SimulationException, SchedulingInterruptedException { return simulateNoResults(plan, null, activity).simulationResultsComputerInputs(); } @@ -194,7 +180,7 @@ public AugmentedSimulationResultsComputerInputs simulateNoResults(final Plan pla private AugmentedSimulationResultsComputerInputs simulateNoResults( final Plan plan, final Duration until, - final SchedulingActivityDirective activity) + final SchedulingActivity activity) throws SimulationException, SchedulingInterruptedException { final var planSimCorrespondence = scheduleFromPlan(plan, this.schedulerModel); @@ -225,7 +211,7 @@ private AugmentedSimulationResultsComputerInputs simulateNoResults( else if (activity != null && until == null) { simulationDuration = planningHorizon.getEndAerie(); stoppingCondition = CheckpointSimulationDriver.stopOnceActivityHasFinished( - planSimCorrespondence.planActDirectiveIdToSimulationActivityDirectiveId().get(activity.id())); + activity.id()); LOGGER.info("Simulation mode: until activity ends " + activity); } //(3) @@ -278,8 +264,8 @@ else if (activity == null && until == null) { activityResults, activityTypes, plan, - planSimCorrespondence, - planningHorizon); + planningHorizon + ); SimulationFacadeUtils.pullActivityDurationsIfNecessary( plan, @@ -336,8 +322,8 @@ public SimulationData simulateWithResults( this.latestSimulationData = new SimulationData( plan, driverResults, - SimulationResultsConverter.convertToConstraintModelResults(driverResults), - Optional.ofNullable(resultsInput.planSimCorrespondence().planActDirectiveIdToSimulationActivityDirectiveId())); + SimulationResultsConverter.convertToConstraintModelResults(driverResults) + ); return this.latestSimulationData; } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationData.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationData.java index 5f1517f6ab..2d360ba401 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationData.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationData.java @@ -1,16 +1,10 @@ package gov.nasa.jpl.aerie.scheduler.simulation; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.scheduler.model.Plan; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; -import org.apache.commons.collections4.BidiMap; - -import java.util.Optional; public record SimulationData( Plan plan, SimulationResults driverResults, - gov.nasa.jpl.aerie.constraints.model.SimulationResults constraintsResults, - Optional> mapSchedulingIdsToActivityIds + gov.nasa.jpl.aerie.constraints.model.SimulationResults constraintsResults ){} diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacade.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacade.java index cbae355dac..14c82a3671 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacade.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacade.java @@ -7,9 +7,7 @@ import gov.nasa.jpl.aerie.scheduler.SchedulingInterruptedException; import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.model.Plan; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; -import org.apache.commons.collections4.BidiMap; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import java.util.Collection; import java.util.HashSet; @@ -32,7 +30,7 @@ SimulationResultsComputerInputs simulateNoResultsAllActivities(Plan plan) SimulationResultsComputerInputs simulateNoResultsUntilEndAct( Plan plan, - SchedulingActivityDirective activity) throws SimulationException, SchedulingInterruptedException; + SchedulingActivity activity) throws SimulationException, SchedulingInterruptedException; AugmentedSimulationResultsComputerInputs simulateNoResults( Plan plan, @@ -61,7 +59,6 @@ record AugmentedSimulationResultsComputerInputs( ) {} record PlanSimCorrespondence( - BidiMap planActDirectiveIdToSimulationActivityDirectiveId, Map directiveIdActivityDirectiveMap){ @Override public boolean equals(Object other){ diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacadeUtils.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacadeUtils.java index bb72056c17..69d510fd6a 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacadeUtils.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacadeUtils.java @@ -3,8 +3,8 @@ import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivityId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResultsComputerInputs; import gov.nasa.jpl.aerie.merlin.driver.engine.SimulationEngine; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; @@ -13,9 +13,7 @@ import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; -import org.apache.commons.collections4.bidimap.DualHashBidiMap; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,28 +24,21 @@ public class SimulationFacadeUtils { private static final Logger LOGGER = LoggerFactory.getLogger(SimulationFacadeUtils.class); - private static int itSimActivityId = 0; public static SimulationFacade.PlanSimCorrespondence scheduleFromPlan(final Plan plan, final SchedulerModel schedulerModel){ final var activities = plan.getActivities(); - final var planActDirectiveIdToSimulationActivityDirectiveId = new DualHashBidiMap(); - if(activities.isEmpty()) return new SimulationFacade.PlanSimCorrespondence(new DualHashBidiMap<>(), Map.of()); + if(activities.isEmpty()) return new SimulationFacade.PlanSimCorrespondence(Map.of()); //filter out child activities final var activitiesWithoutParent = activities.stream().filter(a -> a.topParent() == null).toList(); final Map directivesToSimulate = new HashMap<>(); - for(final var activity : activitiesWithoutParent){ - final var activityIdSim = new ActivityDirectiveId(itSimActivityId++); - planActDirectiveIdToSimulationActivityDirectiveId.put(activity.getId(), activityIdSim); - } - for(final var activity : activitiesWithoutParent) { - final var activityDirective = schedulingActToActivityDir(activity, planActDirectiveIdToSimulationActivityDirectiveId, schedulerModel); + final var activityDirective = schedulingActToActivityDir(activity, schedulerModel); directivesToSimulate.put( - planActDirectiveIdToSimulationActivityDirectiveId.get(activity.getId()), + activity.id(), activityDirective); } - return new SimulationFacade.PlanSimCorrespondence(planActDirectiveIdToSimulationActivityDirectiveId, directivesToSimulate); + return new SimulationFacade.PlanSimCorrespondence(directivesToSimulate); } /** @@ -59,17 +50,15 @@ public static void pullActivityDurationsIfNecessary( final SimulationFacade.PlanSimCorrespondence correspondence, final SimulationEngine.SimulationActivityExtract activityExtract ) { - final var toReplace = new HashMap(); + final var toReplace = new HashMap(); for (final var activity : plan.getActivities()) { if (activity.duration() == null) { final var activityDirective = findSimulatedActivityById( activityExtract.simulatedActivities().values(), - correspondence.planActDirectiveIdToSimulationActivityDirectiveId().get(activity.getId())); + activity.id() + ); if (activityDirective.isPresent()) { - final var replacementAct = SchedulingActivityDirective.copyOf( - activity, - activityDirective.get().duration() - ); + final var replacementAct = activity.withNewDuration(activityDirective.get().duration()); toReplace.put(activity, replacementAct); } //if not, maybe the activity is not finished @@ -78,8 +67,8 @@ public static void pullActivityDurationsIfNecessary( toReplace.forEach(plan::replaceActivity); } - private static Optional findSimulatedActivityById( - Collection simulatedActivities, + private static Optional findSimulatedActivityById( + Collection simulatedActivities, final ActivityDirectiveId activityDirectiveId ){ return simulatedActivities.stream() @@ -91,7 +80,6 @@ public static void updatePlanWithChildActivities( final SimulationEngine.SimulationActivityExtract activityExtract, final Map activityTypes, final Plan plan, - final SimulationFacade.PlanSimCorrespondence planSimCorrespondence, final PlanningHorizon planningHorizon) { //remove all activities with parents @@ -102,14 +90,17 @@ public static void updatePlanWithChildActivities( if (activity.parentId() == null) return; final var rootParent = getIdOfRootParent(activityExtract, activityInstanceId); if(rootParent.isPresent()) { - final var activityInstance = SchedulingActivityDirective.of( + final var activityInstance = SchedulingActivity.of( + null, activityTypes.get(activity.type()), planningHorizon.toDur(activity.start()), activity.duration(), activity.arguments(), - planSimCorrespondence.planActDirectiveIdToSimulationActivityDirectiveId().getKey(rootParent.get()), + rootParent.get(), null, - true); + true, + false + ); plan.add(activityInstance); } }); @@ -118,7 +109,7 @@ public static void updatePlanWithChildActivities( private static Optional getIdOfRootParent( final SimulationEngine.SimulationActivityExtract results, - final SimulatedActivityId instanceId){ + final ActivityInstanceId instanceId){ if(!results.simulatedActivities().containsKey(instanceId)){ if(!results.unfinishedActivities().containsKey(instanceId)){ LOGGER.debug("The simulation of the parent of activity with id "+ instanceId.id() + " has been finished"); @@ -145,8 +136,7 @@ public static Optional getActivityDuration( } public static ActivityDirective schedulingActToActivityDir( - final SchedulingActivityDirective activity, - final Map planActDirectiveIdToSimulationActivityDirectiveId, + final SchedulingActivity activity, final SchedulerModel schedulerModel) { if(activity.getParentActivity().isPresent()) { throw new Error("This method should not be called with a generated activity but with its top-level parent."); @@ -157,12 +147,10 @@ public static ActivityDirective schedulingActToActivityDir( if (durationType instanceof DurationType.Controllable dt) { arguments.put(dt.parameterName(), schedulerModel.serializeDuration(activity.duration())); } else if ( - durationType instanceof DurationType.Uncontrollable + !(durationType instanceof DurationType.Uncontrollable || durationType instanceof DurationType.Fixed - || durationType instanceof DurationType.Parametric + || durationType instanceof DurationType.Parametric) ) { - // If an activity has already been simulated, it will have a duration, even if its DurationType is Uncontrollable. - } else { throw new Error("Unhandled variant of DurationType: " + durationType); } } @@ -170,7 +158,7 @@ public static ActivityDirective schedulingActToActivityDir( return new ActivityDirective( activity.startOffset(), serializedActivity, - planActDirectiveIdToSimulationActivityDirectiveId.get(activity.anchorId()), + activity.anchorId(), activity.anchoredToStart()); } } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationResultsConverter.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationResultsConverter.java index 868f912f16..b858e31a8b 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationResultsConverter.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationResultsConverter.java @@ -4,7 +4,7 @@ import gov.nasa.jpl.aerie.constraints.model.DiscreteProfile; import gov.nasa.jpl.aerie.constraints.model.LinearProfile; import gov.nasa.jpl.aerie.constraints.time.Interval; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -43,13 +43,13 @@ public static gov.nasa.jpl.aerie.constraints.model.SimulationResults convertToCo * @return an activity instance suitable for a constraint model SimulationResult */ public static gov.nasa.jpl.aerie.constraints.model.ActivityInstance convertToConstraintModelActivityInstance( - long id, SimulatedActivity driverActivity, final Instant startTime) + long id, ActivityInstance driverActivity, final Instant startTime) { final var startT = Duration.of(startTime.until(driverActivity.start(), ChronoUnit.MICROS), MICROSECONDS); final var endT = startT.plus(driverActivity.duration()); final var activityInterval = Interval.between(startT, endT); return new gov.nasa.jpl.aerie.constraints.model.ActivityInstance( id, driverActivity.type(), driverActivity.arguments(), - activityInterval); + activityInterval, driverActivity.directiveId()); } } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/Evaluation.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/Evaluation.java index 2370c467a7..2aa2bb1e69 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/Evaluation.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/Evaluation.java @@ -3,7 +3,7 @@ import gov.nasa.jpl.aerie.scheduler.goals.ActivityExistentialGoal; import gov.nasa.jpl.aerie.scheduler.goals.ChildCustody; import gov.nasa.jpl.aerie.scheduler.goals.Goal; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import java.util.Collections; import java.util.Map; @@ -33,7 +33,7 @@ public static class GoalEvaluation { /** * a map associating each activity that contributed to the goal to a boolean stating whether the goal created it or not */ - protected final java.util.Map acts = new java.util.HashMap<>(); + protected final java.util.Map acts = new java.util.HashMap<>(); /** * the numeric evaluation score for the goal @@ -81,14 +81,14 @@ public Optional getNbConflictsDetected() { * evaluation * @param createdByThisGoal IN a boolean stating whether the instance has been created by this goal or not */ - public void associate(SchedulingActivityDirective act, boolean createdByThisGoal) { acts.put(act, createdByThisGoal);} + public void associate(SchedulingActivity act, boolean createdByThisGoal) { acts.put(act, createdByThisGoal);} /** * Replaces an activity in the goal evaluation by another activity * @param toBeReplaced the activity to be replaced * @param replacement the replacement activity */ - public void replace(final SchedulingActivityDirective toBeReplaced, final SchedulingActivityDirective replacement){ + public void replace(final SchedulingActivity toBeReplaced, final SchedulingActivity replacement){ final var found = acts.get(toBeReplaced); if(found != null){ acts.remove(toBeReplaced); @@ -115,11 +115,11 @@ public GoalEvaluation duplicate(){ * evaluation * @param createdByThisGoal IN a boolean stating whether the instance has been created by this goal or not */ - public void associate(java.util.Collection acts, boolean createdByThisGoal) { + public void associate(java.util.Collection acts, boolean createdByThisGoal) { acts.forEach(a ->this.acts.put(a, createdByThisGoal)); } - public void removeAssociation(java.util.Collection acts){ + public void removeAssociation(java.util.Collection acts){ this.acts.entrySet().removeIf(act -> acts.contains(act.getKey())); } @@ -128,7 +128,7 @@ public void removeAssociation(java.util.Collection * * @return the set of all activities that contributed to the evaluation */ - public java.util.Collection getAssociatedActivities() { + public java.util.Collection getAssociatedActivities() { return java.util.Collections.unmodifiableSet(acts.keySet()); } /** @@ -136,7 +136,7 @@ public java.util.Collection getAssociatedActivities * * @return the set of all activities that this goal inserted in the plan */ - public java.util.Collection getInsertedActivities() { + public java.util.Collection getInsertedActivities() { return java.util.Collections.unmodifiableSet(acts.entrySet().stream().filter((a)-> a.getValue().equals(true)).map( Map.Entry::getKey).collect( Collectors.toSet())); @@ -198,7 +198,7 @@ public int hashCode() { return Objects.hash(goalEvals); } - public boolean canAssociateMoreToCreatorOf(final SchedulingActivityDirective instance){ + public boolean canAssociateMoreToCreatorOf(final SchedulingActivity instance){ final var creator$ = getGoalCreator(instance); // for now: all existing activities in the plan are allowed to be associated with any goal if (creator$.isEmpty()) return true; @@ -211,7 +211,7 @@ public boolean canAssociateMoreToCreatorOf(final SchedulingActivityDirective ins /** * If an activity instance was already in the plan prior to this run of the scheduler, this method will return Optional.empty() */ - Optional getGoalCreator(final SchedulingActivityDirective instance){ + Optional getGoalCreator(final SchedulingActivity instance){ for(final var goalEval : goalEvals.entrySet()){ if(goalEval.getValue().getInsertedActivities().contains(instance)){ return Optional.of(goalEval.getKey()); @@ -225,7 +225,7 @@ Optional getGoalCreator(final SchedulingActivityDirective instance){ * @param oldAct Old Activity * @param newAct New Activity */ - public void updateGoalEvals(final SchedulingActivityDirective oldAct, final SchedulingActivityDirective newAct) { + public void updateGoalEvals(final SchedulingActivity oldAct, final SchedulingActivity newAct) { for (GoalEvaluation goalEval : goalEvals.values()) { if (goalEval.acts.containsKey(oldAct)) { Boolean value = goalEval.acts.get(oldAct); diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/PrioritySolver.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/PrioritySolver.java index 058b227499..9f56bd39db 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/PrioritySolver.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/PrioritySolver.java @@ -6,9 +6,11 @@ import gov.nasa.jpl.aerie.constraints.time.Segment; import gov.nasa.jpl.aerie.constraints.time.Windows; import gov.nasa.jpl.aerie.constraints.tree.Expression; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.DurationType; import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException; +import gov.nasa.jpl.aerie.scheduler.DirectiveIdGenerator; import gov.nasa.jpl.aerie.scheduler.EquationSolvingAlgorithms; import gov.nasa.jpl.aerie.scheduler.NotNull; import gov.nasa.jpl.aerie.scheduler.SchedulingInterruptedException; @@ -27,11 +29,10 @@ import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.Problem; import gov.nasa.jpl.aerie.scheduler.model.SchedulePlanGrounder; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.simulation.SimulationData; import gov.nasa.jpl.aerie.scheduler.simulation.SimulationFacade; import gov.nasa.jpl.aerie.scheduler.solver.stn.TaskNetworkAdapter; -import org.apache.commons.collections4.bidimap.DualHashBidiMap; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -88,7 +89,9 @@ public class PrioritySolver implements Solver { private final SimulationFacade simulationFacade; - public record ActivityMetadata(SchedulingActivityDirective activityDirective){} + private final DirectiveIdGenerator idGenerator; + + public record ActivityMetadata(SchedulingActivity activityDirective){} public static class HistoryWithActivity implements EquationSolvingAlgorithms.History { List, Optional>> events; @@ -143,6 +146,18 @@ public PrioritySolver(final Problem problem, final boolean analysisOnly) { this.problem = problem; this.simulationFacade = problem.getSimulationFacade(); this.analysisOnly = analysisOnly; + + this.idGenerator = new DirectiveIdGenerator( + problem + .getInitialPlan() + .getActivitiesById() + .keySet() + .stream() + .map(ActivityDirectiveId::id) + .max(Long::compareTo) + .orElse(-1L) + + 1 + ); } public PrioritySolver(final Problem problem) { @@ -185,7 +200,7 @@ public Optional getNextSolution() throws SchedulingInterruptedException { } } - public record InsertActivityResult(boolean success, List activitiesInserted){} + public record InsertActivityResult(boolean success, List activitiesInserted){} /** * Tries to insert a collection of activity instances in plan. Simulates each of the activity and checks whether the expected @@ -193,7 +208,7 @@ public record InsertActivityResult(boolean success, List acts) throws SchedulingInterruptedException{ + private InsertActivityResult checkAndInsertActs(Collection acts) throws SchedulingInterruptedException{ // TODO: When anchors are allowed to be added by Scheduling goals, inserting the new activities one at a time should be reconsidered boolean allGood = true; logger.info("Inserting new activities in the plan to check plan validity"); @@ -215,7 +230,7 @@ private InsertActivityResult checkAndInsertActs(Collection plan.getActivitiesById().get(act.getId())).toList()); + return new InsertActivityResult(allGood, acts.stream().map(act -> plan.getActivitiesById().get(act.id())).toList()); } @@ -320,14 +335,14 @@ private void satisfyOptionGoal(OptionGoal goal) throws SchedulingInterruptedExce if (goal.hasOptimizer()) { //try to satisfy all and see what is best Goal currentSatisfiedGoal = null; - Collection actsToInsert = null; - Collection actsToAssociateWith = null; + Collection actsToInsert = null; + Collection actsToAssociateWith = null; for (var subgoal : goal.getSubgoals()) { satisfyGoal(subgoal); if(plan.getEvaluation().forGoal(subgoal).getScore() == 0 || !subgoal.shouldRollbackIfUnsatisfied()) { var associatedActivities = plan.getEvaluation().forGoal(subgoal).getAssociatedActivities(); var insertedActivities = plan.getEvaluation().forGoal(subgoal).getInsertedActivities(); - var aggregatedActivities = new ArrayList(); + var aggregatedActivities = new ArrayList(); aggregatedActivities.addAll(associatedActivities); aggregatedActivities.addAll(insertedActivities); if (!aggregatedActivities.isEmpty() && @@ -522,7 +537,7 @@ else if(!analysisOnly && (missing instanceof MissingActivityTemplateConflict mi durationLeft = durationLeft.minus(insertionResult .activitiesInserted() .stream() - .map(SchedulingActivityDirective::duration) + .map(SchedulingActivity::duration) .reduce(Duration.ZERO, Duration::plus)); } } else{ @@ -550,12 +565,11 @@ else if(!analysisOnly && (missing instanceof MissingActivityTemplateConflict mi // If existing activity is a match but is missing the anchor, then the appropriate anchorId has been included in MissingAssociationConflict. // In that case, a new activity must be created as a copy of act but including the anchorId. This activity is then added to all appropriate data structures and the association is created if (missingAssociationConflict.getAnchorIdTo().isPresent()){ - SchedulingActivityDirective predecessor = plan.getActivitiesById().get(missingAssociationConflict.getAnchorIdTo().get()); + SchedulingActivity predecessor = plan.getActivitiesById().get(missingAssociationConflict.getAnchorIdTo().get()); Duration startOffset = act.startOffset().minus(plan.calculateAbsoluteStartOffsetAnchoredActivity(predecessor)); // In case the goal requires generation of anchors, then check that the anchor is to the Start. Otherwise (anchor to End), make sure that there is a positive offset if(missingAssociationConflict.getAnchorToStart().isEmpty() || missingAssociationConflict.getAnchorToStart().get() || startOffset.longerThan(Duration.ZERO)){ - var replacementAct = SchedulingActivityDirective.copyOf( - act, + var replacementAct = act.withNewAnchor( missingAssociationConflict.getAnchorIdTo().get(), missingAssociationConflict.getAnchorToStart().get(), startOffset @@ -595,7 +609,8 @@ else if(!analysisOnly && (missing instanceof MissingActivityTemplateConflict mi logger.warn("Rolling back changes for "+goal.getName()); rollback(goal); } - logger.info("Finishing goal satisfaction for goal " + goal.getName() +":"+ (missingConflicts.size() == 0 ? "SUCCESS" : "FAILURE. Number of conflicts that could not be addressed: " + missingConflicts.size())); + logger.info("Finishing goal satisfaction for goal " + goal.getName() +":"+ (missingConflicts.isEmpty() + ? "SUCCESS" : "FAILURE. Number of conflicts that could not be addressed: " + missingConflicts.size())); plan.getEvaluation().forGoal(goal).setScore(-missingConflicts.size()); } @@ -621,7 +636,6 @@ private Collection getConflicts(Goal goal) throws SchedulingInterrupte final var rawConflicts = goal.getConflicts( plan, simulationResults.constraintsResults(), - simulationResults.mapSchedulingIdsToActivityIds(), evaluationEnvironment, this.problem.getSchedulerModel()); assert rawConflicts != null; @@ -664,10 +678,10 @@ private Collection getConflicts(Goal goal) throws SchedulingInterrupte * added to the plan to best satisfy the conflict without disrupting * the rest of the plan, or null if there are no such suggestions */ - private Collection getBestNewActivities(MissingActivityConflict missing) + private Collection getBestNewActivities(MissingActivityConflict missing) throws SchedulingInterruptedException { assert missing != null; - var newActs = new LinkedList(); + var newActs = new LinkedList(); //REVIEW: maybe push into polymorphic method of conflict/goal? (picking best act //may depend on the source goal) @@ -713,13 +727,13 @@ private Collection getBestNewActivities(MissingActi //create new act if there is any valid time (otherwise conflict is //unsatisfiable in current plan) - if (!startWindows.stream().noneMatch(Segment::value)) { + if (startWindows.stream().anyMatch(Segment::value)) { //TODO: move this into a polymorphic method? definitely don't want to be //demuxing on all the conflict types here if (missing instanceof final MissingActivityInstanceConflict missingInstance) { //FINISH: clean this up code dupl re windows etc final var act = missingInstance.getInstance(); - newActs.add(SchedulingActivityDirective.of(act)); + newActs.add(act); } else if (missing instanceof final MissingActivityTemplateConflict missingTemplate) { //select the "best" time among the possibilities, and latest among ties @@ -736,7 +750,7 @@ private Collection getBestNewActivities(MissingActi missing.getEvaluationEnvironment()); if(act.isPresent()){ if (missingTemplate.getAnchorId().isPresent()) { - final SchedulingActivityDirective predecessor = plan.getActivitiesById().get(missingTemplate.getAnchorId().get()); + final SchedulingActivity predecessor = plan.getActivitiesById().get(missingTemplate.getAnchorId().get()); int includePredDuration = 0; if (missingTemplate.getAnchorToStart().isPresent()) { includePredDuration = missingTemplate.getAnchorToStart().get() ? 0 : 1; @@ -745,7 +759,7 @@ private Collection getBestNewActivities(MissingActi final Duration startOffset = act.get().startOffset().minus(plan.calculateAbsoluteStartOffsetAnchoredActivity(predecessor).plus(dur)); // In case the goal requires generation of anchors and anchor is startsAt End, then check that predecessor completes before act starts. If that's not the case, don't add act as the anchor cannot be verified if(((MissingActivityTemplateConflict) missing).getAnchorToStart().isEmpty() || ((MissingActivityTemplateConflict) missing).getAnchorToStart().get() || startOffset.noShorterThan(Duration.ZERO)){ - final var actWithAnchor = Optional.of(SchedulingActivityDirective.copyOf(act.get(), missingTemplate.getAnchorId().get(), missingTemplate.getAnchorToStart().get(), startOffset)); + final var actWithAnchor = Optional.of(act.get().withNewAnchor(missingTemplate.getAnchorId().get(), missingTemplate.getAnchorToStart().get(), startOffset)); newActs.add(actWithAnchor.get()); } else{ @@ -827,8 +841,8 @@ private SimulationData getLatestSimResultsUpTo(final Duration time, final Set createOneActivity( + public @NotNull Optional createOneActivity( final MissingActivityTemplateConflict missingConflict, final String name, final Windows windows, @@ -907,7 +921,7 @@ private Windows narrowGlobalConstraints( return Optional.empty(); } - private Optional instantiateActivity( + private Optional instantiateActivity( final ActivityExpression activityExpression, final String name, final Interval interval, @@ -940,11 +954,12 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History< throws EquationSolvingAlgorithms.DiscontinuityException, SchedulingInterruptedException { final var latestConstraintsSimulationResults = getLatestSimResultsUpTo(start, resourceNames); - final var actToSim = SchedulingActivityDirective.of( + final var actToSim = new SchedulingActivity( + idGenerator.next(), activityExpression.type(), start, null, - SchedulingActivityDirective.instantiateArguments( + SchedulingActivity.instantiateArguments( activityExpression.arguments(), start, latestConstraintsSimulationResults.constraintsResults(), @@ -952,15 +967,17 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History< activityExpression.type()), null, null, - true); + true, + true + ); Duration computedDuration = null; try { final var duplicatePlan = plan.duplicate(); duplicatePlan.add(actToSim); simulationFacade.simulateNoResultsUntilEndAct(duplicatePlan, actToSim); - computedDuration = duplicatePlan.getActivitiesById().get(actToSim.getId()).duration(); + computedDuration = duplicatePlan.getActivitiesById().get(actToSim.id()).duration(); if(computedDuration != null) { - history.add(new EquationSolvingAlgorithms.FunctionCoordinate<>(start, start.plus(computedDuration)), new ActivityMetadata(SchedulingActivityDirective.copyOf(actToSim, computedDuration))); + history.add(new EquationSolvingAlgorithms.FunctionCoordinate<>(start, start.plus(computedDuration)), new ActivityMetadata(actToSim.withNewDuration(computedDuration))); } else{ logger.debug("No simulation error but activity duration could not be found in simulation, likely caused by unfinished activity or activity outside plan bounds."); history.add(new EquationSolvingAlgorithms.FunctionCoordinate<>(start, null), new ActivityMetadata(actToSim)); @@ -979,7 +996,7 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History< } else if (activityExpression.type().getDurationType() instanceof DurationType.Controllable dt) { //select earliest start time, STN guarantees satisfiability final var earliestStart = solved.start().start; - final var instantiatedArguments = SchedulingActivityDirective.instantiateArguments( + final var instantiatedArguments = SchedulingActivity.instantiateArguments( activityExpression.arguments(), earliestStart, getLatestSimResultsUpTo(earliestStart, resourceNames).constraintsResults(), @@ -1003,14 +1020,17 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History< setActivityDuration = solved.end().start.minus(solved.start().start); } // TODO: When scheduling is allowed to create activities with anchors, this constructor should pull from an expanded creation template - return Optional.of(SchedulingActivityDirective.of( + return Optional.of(SchedulingActivity.of( + idGenerator.next(), activityExpression.type(), earliestStart, setActivityDuration, instantiatedArguments, null, null, - true)); + true, + true + )); } else if (activityExpression.type().getDurationType() instanceof DurationType.Fixed dt) { if (!solved.duration().contains(dt.duration())) { logger.debug("Interval is too small"); @@ -1019,11 +1039,12 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History< final var earliestStart = solved.start().start; // TODO: When scheduling is allowed to create activities with anchors, this constructor should pull from an expanded creation template - return Optional.of(SchedulingActivityDirective.of( + return Optional.of(SchedulingActivity.of( + idGenerator.next(), activityExpression.type(), earliestStart, dt.duration(), - SchedulingActivityDirective.instantiateArguments( + SchedulingActivity.instantiateArguments( activityExpression.arguments(), earliestStart, getLatestSimResultsUpTo(earliestStart, resourceNames).constraintsResults(), @@ -1031,14 +1052,16 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History< activityExpression.type()), null, null, - true)); + true, + true + )); } else if (activityExpression.type().getDurationType() instanceof DurationType.Parametric dt) { final var history = new HistoryWithActivity(); final var f = new EquationSolvingAlgorithms.Function() { @Override public Duration valueAt(final Duration start, final EquationSolvingAlgorithms.History history) throws SchedulingInterruptedException { - final var instantiatedArgs = SchedulingActivityDirective.instantiateArguments( + final var instantiatedArgs = SchedulingActivity.instantiateArguments( activityExpression.arguments(), start, getLatestSimResultsUpTo(start, resourceNames).constraintsResults(), @@ -1048,12 +1071,16 @@ public Duration valueAt(final Duration start, final EquationSolvingAlgorithms.Hi try { final var duration = dt.durationFunction().apply(instantiatedArgs); - final var activity = SchedulingActivityDirective.of(activityExpression.type(),start, - duration, - instantiatedArgs, - null, - null, - true); + final var activity = SchedulingActivity.of( + idGenerator.next(), + activityExpression.type(),start, + duration, + instantiatedArgs, + null, + null, + true, + true + ); history.add(new EquationSolvingAlgorithms.FunctionCoordinate<>(start, start.plus(duration)), new ActivityMetadata(activity)); return duration.plus(start); } catch (InstantiationException e) { @@ -1069,7 +1096,7 @@ public Duration valueAt(final Duration start, final EquationSolvingAlgorithms.Hi } } - private Optional rootFindingHelper( + private Optional rootFindingHelper( final EquationSolvingAlgorithms.Function f, final HistoryWithActivity history, final TaskNetworkAdapter.TNActData solved @@ -1119,9 +1146,11 @@ public void printEvaluation() { logger.warn("Remaining conflicts for goals "); for (var goalEval : evaluation.getGoals()) { logger.warn(goalEval.getName() + " -> " + evaluation.forGoal(goalEval).score); - logger.warn("Activities created by this goal:"+ evaluation.forGoal(goalEval).getInsertedActivities().stream().map(SchedulingActivityDirective::toString).collect( + logger.warn("Activities created by this goal:"+ evaluation.forGoal(goalEval).getInsertedActivities().stream().map( + SchedulingActivity::toString).collect( Collectors.joining(" "))); - logger.warn("Activities associated to this goal:"+ evaluation.forGoal(goalEval).getAssociatedActivities().stream().map(SchedulingActivityDirective::toString).collect( + logger.warn("Activities associated to this goal:"+ evaluation.forGoal(goalEval).getAssociatedActivities().stream().map( + SchedulingActivity::toString).collect( Collectors.joining(" "))); } } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/Optimizer.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/Optimizer.java index 6a6c788e4b..3c827470d3 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/Optimizer.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/Optimizer.java @@ -1,15 +1,15 @@ package gov.nasa.jpl.aerie.scheduler.solver.optimizers; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import java.util.List; public abstract class Optimizer { - List currentGoalSolution = null; + List currentGoalSolution = null; //incremental call - public abstract boolean isBetterThanCurrent(List candidateGoalSolution); + public abstract boolean isBetterThanCurrent(List candidateGoalSolution); } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/OptimizerEarliestEndTime.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/OptimizerEarliestEndTime.java index e053f85356..ddd014544c 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/OptimizerEarliestEndTime.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/OptimizerEarliestEndTime.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.solver.optimizers; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import java.util.List; @@ -10,8 +10,8 @@ public class OptimizerEarliestEndTime extends Optimizer { Duration currentEarliestEndTime = null; @Override - public boolean isBetterThanCurrent(List candidateGoalSolution) { - SchedulingActivityDirective act = SchedulingActivityDirective.getActWithEarliestEndTime(candidateGoalSolution); + public boolean isBetterThanCurrent(List candidateGoalSolution) { + SchedulingActivity act = SchedulingActivity.getActWithEarliestEndTime(candidateGoalSolution); if(act == null || act.duration() != null) { throw new IllegalStateException("Cannot optimize on uninstantiated activities"); } diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/OptimizerLatestStartTime.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/OptimizerLatestStartTime.java index 40b3094d6d..86b567787e 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/OptimizerLatestStartTime.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/optimizers/OptimizerLatestStartTime.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.solver.optimizers; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import java.util.List; @@ -10,8 +10,8 @@ public class OptimizerLatestStartTime extends Optimizer { Duration currentLatestStartTime = null; @Override - public boolean isBetterThanCurrent(List candidateGoalSolution) { - SchedulingActivityDirective act = SchedulingActivityDirective.getActWithLatestStartTime(candidateGoalSolution); + public boolean isBetterThanCurrent(List candidateGoalSolution) { + SchedulingActivity act = SchedulingActivity.getActWithLatestStartTime(candidateGoalSolution); if(act == null || act.getEndTime() == null) { throw new IllegalStateException("Cannot optimize on uninstantiated activities"); } diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/LongDurationPlanTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/LongDurationPlanTest.java index 89d8305338..13cb2f985c 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/LongDurationPlanTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/LongDurationPlanTest.java @@ -4,7 +4,7 @@ import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.goals.ProceduralCreationGoal; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.Problem; @@ -40,10 +40,11 @@ private static Problem makeTestMissionAB() { private static PlanInMemory makePlanA012(Problem problem) { final var plan = new PlanInMemory(); final var actTypeA = problem.getActivityType("GrowBanana"); - plan.add(SchedulingActivityDirective.of(actTypeA, t0, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t1year, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t2year, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t3year, d1min, null, true)); + final var idGenerator = new DirectiveIdGenerator(0); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t0, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t1year, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t2year, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t3year, d1min, null, true, false)); return plan; } diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/PrioritySolverTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/PrioritySolverTest.java index 60fa027bf3..9a97333969 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/PrioritySolverTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/PrioritySolverTest.java @@ -14,7 +14,7 @@ import gov.nasa.jpl.aerie.scheduler.goals.CoexistenceGoal; import gov.nasa.jpl.aerie.scheduler.goals.ProceduralCreationGoal; import gov.nasa.jpl.aerie.scheduler.goals.RecurrenceGoal; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.Problem; @@ -35,6 +35,7 @@ import static org.junit.jupiter.api.Assertions.*; public class PrioritySolverTest { + private static final DirectiveIdGenerator idGenerator = new DirectiveIdGenerator(0); private static PrioritySolver makeEmptyProblemSolver() { MissionModel bananaMissionModel = SimulationUtility.getBananaMissionModel(); final var schedulerModel = SimulationUtility.getBananaSchedulerModel(); @@ -106,26 +107,26 @@ private static Problem makeTestMissionAB() { private static PlanInMemory makePlanA012(Problem problem) { final var plan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - plan.add(SchedulingActivityDirective.of(actTypeA, t0, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t1hr, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t2hr, d1min, null, true)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t0, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t1hr, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t2hr, d1min, null, true, false)); return plan; } private static PlanInMemory makePlanA12(Problem problem) { final var plan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - plan.add(SchedulingActivityDirective.of(actTypeA, t1hr, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t2hr, d1min, null, true)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t1hr, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t2hr, d1min, null, true, false)); return plan; } private static PlanInMemory makePlanAB012(Problem problem) { final var plan = makePlanA012(problem); final var actTypeB = problem.getActivityType("OtherControllableDurationActivity"); - plan.add(SchedulingActivityDirective.of(actTypeB, t0, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeB, t1hr, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeB, t2hr, d1min, null, true)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeB, t0, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeB, t1hr, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeB, t2hr, d1min, null, true, false)); return plan; } @@ -256,7 +257,7 @@ public void getNextSolution_coexistenceGoalOnActivityWorks_withInitialSimResults new SimulationEngineConfiguration(Map.of(),Instant.EPOCH, new MissionModelId(1)), () -> false); final var simResults = adHocFacade.simulateWithResults(makePlanA012(problem), h.getEndAerie()); - problem.setInitialPlan(makePlanA012(problem), Optional.of(simResults.driverResults()), simResults.mapSchedulingIdsToActivityIds().get()); + problem.setInitialPlan(makePlanA012(problem), Optional.of(simResults.driverResults())); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); final var actTypeB = problem.getActivityType("OtherControllableDurationActivity"); final var goal = new CoexistenceGoal.Builder() diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SchedulingGrounderTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SchedulingGrounderTest.java index eb9dc05041..d42f887caf 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SchedulingGrounderTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SchedulingGrounderTest.java @@ -2,16 +2,17 @@ import gov.nasa.jpl.aerie.constraints.model.ActivityInstance; import gov.nasa.jpl.aerie.constraints.time.Interval; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.SchedulePlanGrounder; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import org.junit.jupiter.api.Test; import java.util.List; import java.util.Map; +import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -27,20 +28,20 @@ public class SchedulingGrounderTest { @Test public void testChainAnchors(){ final var at = new ActivityType("at"); - final var id1 = new SchedulingActivityDirectiveId(1); - final var id2 = new SchedulingActivityDirectiveId(2); - final var id3 = new SchedulingActivityDirectiveId(3); - final var act1 = SchedulingActivityDirective.of(id1, at, t0, d1min, null, true); - final var act2 = SchedulingActivityDirective.of(id2, at, t1hr, d1min, act1.id(), false); - final var act3 = SchedulingActivityDirective.of(id3, at, t2hr, d1min, act2.id(), false); + final var id1 = new ActivityDirectiveId(1); + final var id2 = new ActivityDirectiveId(2); + final var id3 = new ActivityDirectiveId(3); + final var act1 = SchedulingActivity.of(id1, at, t0, d1min, null, true, false); + final var act2 = SchedulingActivity.of(id2, at, t1hr, d1min, act1.id(), false, false); + final var act3 = SchedulingActivity.of(id3, at, t2hr, d1min, act2.id(), false, false); final var acts = List.of(act1, act3, act2); final var result = SchedulePlanGrounder.groundSchedule(acts, h.getEndAerie()); //act 1 should start at 0 min into the plan //act 2 should start 61 min into the plan //act 3 should be [62 min, 63 min] - final var act1expt = new ActivityInstance(id1.id(), at.getName(), Map.of(), Interval.between(t0, t0.plus(d1min))); - final var act2expt = new ActivityInstance(id2.id(), at.getName(), Map.of(), Interval.between(t1hr.plus(t0).plus(d1min), t1hr.plus(t0).plus(d1min).plus(d1min))); - final var act3expt = new ActivityInstance(id3.id(), at.getName(), Map.of(), Interval.between(t0.plus(Duration.of(182, Duration.MINUTES)), t0.plus(Duration.of(183, Duration.MINUTES)))); + final var act1expt = new ActivityInstance(id1.id(), at.getName(), Map.of(), Interval.between(t0, t0.plus(d1min)), Optional.of(id1)); + final var act2expt = new ActivityInstance(id2.id(), at.getName(), Map.of(), Interval.between(t1hr.plus(t0).plus(d1min), t1hr.plus(t0).plus(d1min).plus(d1min)), Optional.of(id2)); + final var act3expt = new ActivityInstance(id3.id(), at.getName(), Map.of(), Interval.between(t0.plus(Duration.of(182, Duration.MINUTES)), t0.plus(Duration.of(183, Duration.MINUTES))), Optional.of(id3)); assertTrue(result.get().contains(act1expt)); assertTrue(result.get().contains(act2expt)); assertTrue(result.get().contains(act3expt)); @@ -49,8 +50,8 @@ public void testChainAnchors(){ @Test public void testEmptyDueToEmptyDuration(){ final var at = new ActivityType("at"); - final var id1 = new SchedulingActivityDirectiveId(1); - final var act1 = SchedulingActivityDirective.of(id1, at, t0, null, null, true); + final var id1 = new ActivityDirectiveId(1); + final var act1 = SchedulingActivity.of(id1, at, t0, null, null, true, false); final var result = SchedulePlanGrounder.groundSchedule(List.of(act1), h.getEndAerie()); assertTrue(result.isEmpty()); } @@ -58,10 +59,10 @@ public void testEmptyDueToEmptyDuration(){ @Test public void testAnchoredToPlanEnd(){ final var at = new ActivityType("at"); - final var id1 = new SchedulingActivityDirectiveId(1); - final var act1 = SchedulingActivityDirective.of(id1, at, Duration.negate(d1hr), d1min, null, false); + final var id1 = new ActivityDirectiveId(1); + final var act1 = SchedulingActivity.of(id1, at, Duration.negate(d1hr), d1min, null, false, false); final var result = SchedulePlanGrounder.groundSchedule(List.of(act1), h.getEndAerie()); - final var act1expt = new ActivityInstance(id1.id(), at.getName(), Map.of(), Interval.between(h.getEndAerie().minus(d1hr), h.getEndAerie().minus(d1hr).plus(d1min))); + final var act1expt = new ActivityInstance(id1.id(), at.getName(), Map.of(), Interval.between(h.getEndAerie().minus(d1hr), h.getEndAerie().minus(d1hr).plus(d1min)), Optional.of(id1)); assertEquals(act1expt, result.get().get(0)); } @@ -69,13 +70,13 @@ public void testAnchoredToPlanEnd(){ @Test public void noAnchor(){ final var at = new ActivityType("at"); - final var id1 = new SchedulingActivityDirectiveId(1); - final var id2 = new SchedulingActivityDirectiveId(2); - final var act1 = SchedulingActivityDirective.of(id1, at, t0, d1min, null, true); - final var act2 = SchedulingActivityDirective.of(id2, at, t1hr, d1min, null, true); + final var id1 = new ActivityDirectiveId(1); + final var id2 = new ActivityDirectiveId(2); + final var act1 = SchedulingActivity.of(id1, at, t0, d1min, null, true, false); + final var act2 = SchedulingActivity.of(id2, at, t1hr, d1min, null, true, false); final var result = SchedulePlanGrounder.groundSchedule(List.of(act1, act2), h.getEndAerie()); - final var act1expt = new ActivityInstance(id1.id(), at.getName(), Map.of(), Interval.between(t0, t0.plus(d1min))); - final var act2expt = new ActivityInstance(id2.id(), at.getName(), Map.of(), Interval.between(t1hr, t1hr.plus(d1min))); + final var act1expt = new ActivityInstance(id1.id(), at.getName(), Map.of(), Interval.between(t0, t0.plus(d1min)), Optional.of(id1)); + final var act2expt = new ActivityInstance(id2.id(), at.getName(), Map.of(), Interval.between(t1hr, t1hr.plus(d1min)), Optional.of(id2)); assertTrue(result.get().contains(act1expt)); assertTrue(result.get().contains(act2expt)); } @@ -83,13 +84,13 @@ public void noAnchor(){ @Test public void startTimeAnchor(){ final var at = new ActivityType("at"); - final var id1 = new SchedulingActivityDirectiveId(1); - final var id2 = new SchedulingActivityDirectiveId(2); - final var act1 = SchedulingActivityDirective.of(id1, at, t1hr, d1min, null, true); - final var act2 = SchedulingActivityDirective.of(id2, at, t1hr, d1min, act1.id(), true); + final var id1 = new ActivityDirectiveId(1); + final var id2 = new ActivityDirectiveId(2); + final var act1 = SchedulingActivity.of(id1, at, t1hr, d1min, null, true, false); + final var act2 = SchedulingActivity.of(id2, at, t1hr, d1min, act1.id(), true, false); final var result = SchedulePlanGrounder.groundSchedule(List.of(act1, act2), h.getEndAerie()); - final var act1expt = new ActivityInstance(id1.id(), at.getName(), Map.of(), Interval.between(t1hr, t1hr.plus(d1min))); - final var act2expt = new ActivityInstance(id2.id(), at.getName(), Map.of(), Interval.between(t2hr, t2hr.plus(d1min))); + final var act1expt = new ActivityInstance(id1.id(), at.getName(), Map.of(), Interval.between(t1hr, t1hr.plus(d1min)), Optional.of(id1)); + final var act2expt = new ActivityInstance(id2.id(), at.getName(), Map.of(), Interval.between(t2hr, t2hr.plus(d1min)), Optional.of(id2)); assertTrue(result.get().contains(act1expt)); assertTrue(result.get().contains(act2expt)); } diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SimulationFacadeTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SimulationFacadeTest.java index 9852e6f1df..cccea1c0b2 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SimulationFacadeTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SimulationFacadeTest.java @@ -15,7 +15,7 @@ import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.Problem; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.simulation.CheckpointSimulationFacade; import gov.nasa.jpl.aerie.scheduler.simulation.SimulationFacade; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; @@ -38,6 +38,8 @@ public class SimulationFacadeTest { + private final DirectiveIdGenerator idGenerator = new DirectiveIdGenerator(0); + MissionModel missionModel; Problem problem; SimulationFacade facade; @@ -114,10 +116,10 @@ private PlanInMemory makeTestPlanP0B1() { final var actTypeBite = problem.getActivityType("BiteBanana"); final var actTypePeel = problem.getActivityType("PeelBanana"); - var act1 = SchedulingActivityDirective.of(actTypePeel, t1, null, Map.of("peelDirection", SerializedValue.of("fromStem")), null, true); + var act1 = SchedulingActivity.of(idGenerator.next(), actTypePeel, t1, null, Map.of("peelDirection", SerializedValue.of("fromStem")), null, null, true, false); plan.add(act1); - var act2 = SchedulingActivityDirective.of(actTypeBite, t2, null, Map.of("biteSize", SerializedValue.of(0.1)), null, true); + var act2 = SchedulingActivity.of(idGenerator.next(), actTypeBite, t2, null, Map.of("biteSize", SerializedValue.of(0.1)), null, null, true, false); plan.add(act2); return plan; @@ -129,7 +131,7 @@ public void associationToExistingSatisfyingActivity() throws SchedulingInterrupt final var actTypePeel = problem.getActivityType("PeelBanana"); final var actTypeBite = problem.getActivityType("BiteBanana"); - var act1 = SchedulingActivityDirective.of(actTypePeel, t1, t2, Map.of("peelDirection", SerializedValue.of("fromStem")), null, true); + var act1 = SchedulingActivity.of(idGenerator.next(), actTypePeel, t1, t2, Map.of("peelDirection", SerializedValue.of("fromStem")), null, null, true, false); plan.add(act1); final var goal = new CoexistenceGoal.Builder() @@ -281,18 +283,18 @@ public void testProceduralGoalWithResourceConstraint() throws SchedulingInterrup final var actTypePeel = problem.getActivityType("PeelBanana"); - SchedulingActivityDirective act1 = SchedulingActivityDirective.of(actTypePeel, - t0, Duration.ZERO, null, true); + SchedulingActivity act1 = SchedulingActivity.of(idGenerator.next(), actTypePeel, + t0, Duration.ZERO, Map.of(), null, null, true, false); - SchedulingActivityDirective act2 = SchedulingActivityDirective.of(actTypePeel, - t2, Duration.ZERO, null, true); + SchedulingActivity act2 = SchedulingActivity.of(idGenerator.next(), actTypePeel, + t2, Duration.ZERO, Map.of(), null, null, true, false); //create an "external tool" that insists on a few fixed activities final var externalActs = java.util.List.of( act1, act2 ); - final Function> fixedGenerator + final Function> fixedGenerator = (p) -> externalActs; final var proceduralGoalWithConstraints = new ProceduralCreationGoal.Builder() @@ -323,11 +325,11 @@ public void testActivityTypeWithResourceConstraint() throws SchedulingInterrupte final var actTypePeel = problem.getActivityType("PeelBanana"); actTypePeel.setResourceConstraint(constraint); - SchedulingActivityDirective act1 = SchedulingActivityDirective.of(actTypePeel, - t0, Duration.ZERO, null, true); + SchedulingActivity act1 = SchedulingActivity.of(idGenerator.next(), actTypePeel, + t0, Duration.ZERO, Map.of(), null, null, true, false); - SchedulingActivityDirective act2 = SchedulingActivityDirective.of(actTypePeel, - t2, Duration.ZERO, null, true); + SchedulingActivity act2 = SchedulingActivity.of(idGenerator.next(), actTypePeel, + t2, Duration.ZERO, Map.of(), null, null, true, false); //create an "external tool" that insists on a few fixed activities final var externalActs = java.util.List.of( @@ -335,7 +337,7 @@ public void testActivityTypeWithResourceConstraint() throws SchedulingInterrupte act2 ); - final Function> fixedGenerator + final Function> fixedGenerator = (p) -> externalActs; final var proceduralgoalwithoutconstraints = new ProceduralCreationGoal.Builder() diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestApplyWhen.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestApplyWhen.java index 11657ff701..bcb89dbcd7 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestApplyWhen.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestApplyWhen.java @@ -33,7 +33,7 @@ import gov.nasa.jpl.aerie.scheduler.goals.CoexistenceGoal; import gov.nasa.jpl.aerie.scheduler.goals.RecurrenceGoal; import gov.nasa.jpl.aerie.scheduler.model.Problem; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.simulation.CheckpointSimulationFacade; @@ -50,10 +50,7 @@ import java.util.List; import java.util.Map; -import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.HOURS; -import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.MINUTE; import static gov.nasa.jpl.aerie.scheduler.SimulationUtility.buildProblemFromFoo; -import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.SECONDS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -61,6 +58,8 @@ public class TestApplyWhen { private static final Logger logger = LoggerFactory.getLogger(TestApplyWhen.class); + private final DirectiveIdGenerator idGenerator = new DirectiveIdGenerator(0); + ////////////////////////////////////////////RECURRENCE//////////////////////////////////////////// @Test public void testRecurrenceCutoff1() throws SchedulingInterruptedException { @@ -84,7 +83,7 @@ public void testRecurrenceCutoff1() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -116,7 +115,7 @@ public void testRecurrenceCutoff2() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -148,7 +147,7 @@ public void testRecurrenceShorterWindow() throws SchedulingInterruptedException final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -180,7 +179,7 @@ public void testRecurrenceLongerWindow() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -225,7 +224,7 @@ public void testRecurrenceBabyWindow() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -267,7 +266,7 @@ public void testRecurrenceWindows() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -309,7 +308,7 @@ public void testRecurrenceWindowsCutoffMidInterval() throws SchedulingInterrupte final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -353,7 +352,7 @@ public void testRecurrenceWindowsGlobalCheck() throws SchedulingInterruptedExcep final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -397,7 +396,7 @@ public void testRecurrenceWindowsCutoffMidActivity() throws SchedulingInterrupte final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -428,7 +427,7 @@ public void testRecurrenceCutoffUncontrollable() throws SchedulingInterruptedExc final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -468,13 +467,13 @@ public void testCardinality() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } assertEquals(2, plan.get().getActivitiesByTime().size()); assertEquals(plan.get().getActivitiesByTime().stream() - .map(SchedulingActivityDirective::duration) + .map(SchedulingActivity::duration) .reduce(Duration.ZERO, Duration::plus), Duration.of(4, Duration.SECOND)); //1 gets added, then throws 4 warnings meaning it tried to schedule 5 in total, not the expected 8... } @@ -514,7 +513,7 @@ public void testCardinalityWindows() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -561,7 +560,7 @@ public void testCardinalityWindowsCutoffMidActivity() throws SchedulingInterrupt final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution().orElseThrow(); - for(SchedulingActivityDirective a : plan.getActivitiesByTime()){ + for(SchedulingActivity a : plan.getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } @@ -601,13 +600,13 @@ public void testCardinalityUncontrollable() throws SchedulingInterruptedExceptio final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString()); } var size = plan.get().getActivitiesByTime().size(); var totalDuration = plan.get().getActivitiesByTime().stream() - .map(SchedulingActivityDirective::duration) + .map(SchedulingActivity::duration) .reduce(Duration.ZERO, Duration::plus); assertTrue(size >= 3 && size <= 10); assertTrue(totalDuration.dividedBy(Duration.SECOND) >= 16 && totalDuration.dividedBy(Duration.SECOND) <= 19); @@ -628,9 +627,9 @@ public void testCoexistenceWindowCutoff() throws SchedulingInterruptedException // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie(), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, start at start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(11, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 11s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(16, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 16s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie(), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, start at start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(11, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 11s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(16, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 16s after start // pass this plan as initialPlan to Problem object problem.setInitialPlan(partialPlan); @@ -657,7 +656,7 @@ public void testCoexistenceWindowCutoff() throws SchedulingInterruptedException final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } assertEquals(4, plan.get().getActivitiesByTime().size()); @@ -673,9 +672,9 @@ public void testCoexistenceJustFits() throws SchedulingInterruptedException { // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie(), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, start at start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(11, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 11s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(16, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 16s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie(), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, start at start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(11, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 11s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(16, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 16s after start // pass this plan as initialPlan to Problem object problem.setInitialPlan(partialPlan); @@ -702,7 +701,7 @@ public void testCoexistenceJustFits() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } assertEquals(5, plan.get().getActivitiesByTime().size()); @@ -727,9 +726,9 @@ public void testCoexistenceUncontrollableCutoff() throws SchedulingInterruptedEx // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie(), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, start at start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(11, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 11s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(16, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 16s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie(), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, start at start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(11, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 11s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(16, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 16s after start // pass this plan as initialPlan to Problem object problem.setInitialPlan(partialPlan); @@ -756,7 +755,7 @@ public void testCoexistenceUncontrollableCutoff() throws SchedulingInterruptedEx final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } assertEquals(2, plan.get().getActivitiesByType().get(actTypeB).size()); @@ -778,10 +777,10 @@ public void testCoexistenceWindows() throws SchedulingInterruptedException { // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(1, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, start at start. NOTE: must start at time=1, not time=0, else test fails. - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(8, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 11s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(14, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 16s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(19, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 16s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(1, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, start at start. NOTE: must start at time=1, not time=0, else test fails. + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(8, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 11s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(14, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 16s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(19, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 16s after start // pass this plan as initialPlan to Problem object @@ -816,7 +815,7 @@ public void testCoexistenceWindows() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } @@ -841,11 +840,11 @@ public void testCoexistenceWindowsCutoffMidActivity() throws SchedulingInterrupt // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(1, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, start at start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(7, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 11s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(14, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 16s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(19, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 16s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(25, Duration.SECONDS)), Duration.of(2, Duration.SECONDS), null, true)); //create an activity that's 2 seconds long, 25s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(1, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, start at start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(7, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 11s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(14, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 16s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(19, Duration.SECONDS)), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 16s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(25, Duration.SECONDS)), Duration.of(2, Duration.SECONDS), null, true, false)); //create an activity that's 2 seconds long, 25s after start // pass this plan as initialPlan to Problem object @@ -886,7 +885,7 @@ public void testCoexistenceWindowsCutoffMidActivity() throws SchedulingInterrupt var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } assertEquals(10, plan.get().getActivitiesById().size()); @@ -916,8 +915,8 @@ public void testCoexistenceWindowsBisect() throws SchedulingInterruptedException // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie(), Duration.of(4, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, start at start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(8, Duration.SECONDS)), Duration.of(3, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 11s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie(), Duration.of(4, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, start at start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(8, Duration.SECONDS)), Duration.of(3, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 11s after start // pass this plan as initialPlan to Problem object problem.setInitialPlan(partialPlan); @@ -953,7 +952,7 @@ public void testCoexistenceWindowsBisect() throws SchedulingInterruptedException final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } @@ -980,7 +979,7 @@ public void testCoexistenceWindowsBisect2() throws SchedulingInterruptedExceptio // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie(), Duration.of(13, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, start at start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie(), Duration.of(13, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, start at start // pass this plan as initialPlan to Problem object problem.setInitialPlan(partialPlan); @@ -1016,7 +1015,7 @@ public void testCoexistenceWindowsBisect2() throws SchedulingInterruptedExceptio final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } @@ -1038,9 +1037,9 @@ public void testCoexistenceUncontrollableJustFits() throws SchedulingInterrupted // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie(), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, start at start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(11, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 11s after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(16, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true)); //create an activity that's 5 seconds long, 16s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie(), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, start at start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(11, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 11s after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(16, Duration.SECONDS)), Duration.of(5, Duration.SECONDS), null, true, false)); //create an activity that's 5 seconds long, 16s after start // pass this plan as initialPlan to Problem object problem.setInitialPlan(partialPlan); @@ -1067,7 +1066,7 @@ public void testCoexistenceUncontrollableJustFits() throws SchedulingInterrupted final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } assertEquals(5, plan.get().getActivitiesByTime().size()); @@ -1115,7 +1114,7 @@ public void testCoexistenceExternalResource() throws SchedulingInterruptedExcept final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } final var emptySimulationResults = new SimulationResults(null, null, List.of(), Map.of(), Map.of()); @@ -1153,9 +1152,9 @@ public void testCoexistenceWithAnchors() throws SchedulingInterruptedException { final var partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("GrowBanana"); final var actTypeB = problem.getActivityType("PickBanana"); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie(), Duration.of(3, Duration.HOURS), null, true)); - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(5, Duration.HOURS)), Duration.of(3, Duration.HOURS), null, true)); //create an activity that's 5 hours long, start 5 hours after start - partialPlan.add(SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(10, Duration.HOURS)), Duration.of(3, Duration.HOURS), null, true)); //create an activity that's 5 seconds long, starts 10 hours after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie(), Duration.of(3, Duration.HOURS), null, true, false)); + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(5, Duration.HOURS)), Duration.of(3, Duration.HOURS), null, true, false)); //create an activity that's 5 hours long, start 5 hours after start + partialPlan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(10, Duration.HOURS)), Duration.of(3, Duration.HOURS), null, true, false)); //create an activity that's 5 seconds long, starts 10 hours after start // pass this plan as initialPlan to Problem object problem.setInitialPlan(partialPlan); @@ -1182,7 +1181,7 @@ public void testCoexistenceWithAnchors() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } assertEquals(6, plan.get().getActivitiesByTime().size()); @@ -1243,7 +1242,7 @@ public void changingForAllTimeIn() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString() + " -> "+ a.getType().toString()); } @@ -1317,7 +1316,7 @@ public void changingForAllTimeInCutoff() throws SchedulingInterruptedException { final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString() + " -> "+ a.getType().toString()); } @@ -1398,7 +1397,7 @@ public void changingForAllTimeInAlternativeCutoff() throws SchedulingInterrupted final var solver = new PrioritySolver(problem); var plan = solver.getNextSolution(); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString() + " -> "+ a.getType().toString()); } diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestCardinalityGoal.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestCardinalityGoal.java index 19bacdbfc9..6744cf7ab1 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestCardinalityGoal.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestCardinalityGoal.java @@ -8,7 +8,7 @@ import gov.nasa.jpl.aerie.scheduler.goals.CardinalityGoal; import gov.nasa.jpl.aerie.scheduler.goals.ChildCustody; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; import org.junit.jupiter.api.Test; @@ -44,7 +44,7 @@ public void testone() throws SchedulingInterruptedException { var plan = solver.getNextSolution(); assertEquals(6, plan.get().getActivitiesByTime().size()); assertEquals(plan.get().getActivitiesByTime().stream() - .map(SchedulingActivityDirective::duration) + .map(SchedulingActivity::duration) .reduce(Duration.ZERO, Duration::plus), Duration.of(12, Duration.SECOND)); } } diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestPersistentAnchor.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestPersistentAnchor.java index 3d065f6021..c4ac77b15f 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestPersistentAnchor.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestPersistentAnchor.java @@ -10,6 +10,7 @@ import gov.nasa.jpl.aerie.constraints.tree.Expression; import gov.nasa.jpl.aerie.constraints.tree.ForEachActivitySpans; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -38,11 +39,11 @@ public class TestPersistentAnchor { public record TestData( Optional plan, - ArrayList actsToBeAnchored, - ArrayList actsWithAnchor, - ArrayList actsWithoutAnchorAnchored, - ArrayList actsWithoutAnchorNotAnchored, - ArrayList actsNewAnchored + ArrayList actsToBeAnchored, + ArrayList actsWithAnchor, + ArrayList actsWithoutAnchorAnchored, + ArrayList actsWithoutAnchorNotAnchored, + ArrayList actsNewAnchored ) {} private static final Logger logger = LoggerFactory.getLogger(TestPersistentAnchor.class); @@ -58,8 +59,8 @@ public Boolean apply( final SimulationResults simResults, final EvaluationEnvironment environment) { - final var startTime = activityInstance.interval.start; - if (!activityInstance.type.equals(ae.type().getName())) return false; + final var startTime = activityInstance.interval().start; + if (!activityInstance.type().equals(ae.type().getName())) return false; for (final var arg : ae .arguments() .entrySet() @@ -73,7 +74,7 @@ public Boolean apply( .valueAt(startTime) .orElseThrow())) .entrySet()) { - if (!arg.getValue().equals(activityInstance.parameters.get(arg.getKey()))) return false; + if (!arg.getValue().equals(activityInstance.parameters().get(arg.getKey()))) return false; } return true; } @@ -94,7 +95,7 @@ public boolean allAnchorsIncluded(final TestData testData) { if(testData.plan.isEmpty()) return false; - Set planActivityAnchors = testData.plan.get().getAnchorIds(); + Set planActivityAnchors = testData.plan.get().getAnchorIds(); for(final var act : testData.actsToBeAnchored){ if(!planActivityAnchors.contains(act.anchorId())) return false; @@ -114,9 +115,9 @@ public boolean checkAnchoredActivities(final TestData testData, final boolean al if(testData.plan.isEmpty()) return false; - Set anchorIds = testData.actsToBeAnchored.stream() - .map(SchedulingActivityDirective::id) - .collect(Collectors.toSet()); + Set anchorIds = testData.actsToBeAnchored.stream() + .map(SchedulingActivity::id) + .collect(Collectors.toSet()); final var mapIdToActivity = testData.plan.get().getActivitiesById(); @@ -426,10 +427,10 @@ public void testCaseStartAtEndAnchorAt11() throws SchedulingInterruptedException public TestData createTestCaseStartsAt(final PersistentTimeAnchor persistentAnchor, final boolean missingActAssociationsWithAnchor, final boolean missingActAssociationsWithoutAnchor, final int activityDurationHours, final int goalStartPeriodHours, final int goalEndPeriodHours, final TimeAnchor timeAnchor, final TimeExpressionRelative timeExpression, final long relativeOffsetHours) throws SchedulingInterruptedException { - var actsToBeAnchored = new ArrayList(); - var templateActsAlreadyAnchor = new ArrayList(); - var templateActsWithoutAnchorAnchored = new ArrayList(); - var templateActsWithoutAnchorNotAnchored = new ArrayList(); + var actsToBeAnchored = new ArrayList(); + var templateActsAlreadyAnchor = new ArrayList(); + var templateActsWithoutAnchorAnchored = new ArrayList(); + var templateActsWithoutAnchorNotAnchored = new ArrayList(); final var bananaMissionModel = SimulationUtility.getBananaMissionModel(); final var planningHorizon = new PlanningHorizon(TestUtility.timeFromEpochHours(0), TestUtility.timeFromEpochHours(20)); @@ -448,28 +449,30 @@ public TestData createTestCaseStartsAt(final PersistentTimeAnchor persistentAnch SimulationUtility.getBananaSchedulerModel() ); + final var idGenerator = new DirectiveIdGenerator(0); + //have some activity already present // create a PlanInMemory, add ActivityInstances PlanInMemory partialPlan = new PlanInMemory(); final var actTypeA = problem.getActivityType("GrowBanana"); - SchedulingActivityDirective act1 = SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie(), Duration.of(activityDurationHours, Duration.HOURS), Map.of( + SchedulingActivity act1 = SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie(), Duration.of(activityDurationHours, Duration.HOURS), Map.of( "quantity", SerializedValue.of(1), "growingDuration", SerializedValue.of(Duration.HOUR.times(activityDurationHours).in(Duration.HOURS)) - ), null, null, true); + ), null, null, true, false); partialPlan.add(act1); actsToBeAnchored.add(act1); - SchedulingActivityDirective act2 = SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(5, Duration.HOURS)), Duration.of(activityDurationHours, Duration.HOURS), Map.of( + SchedulingActivity act2 = SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(5, Duration.HOURS)), Duration.of(activityDurationHours, Duration.HOURS), Map.of( "quantity", SerializedValue.of(1), "growingDuration", SerializedValue.of(Duration.HOUR.times(activityDurationHours).in(Duration.HOURS)) - ), null, null, true); + ), null, null, true, false); partialPlan.add(act2); actsToBeAnchored.add(act2); - SchedulingActivityDirective act3 = SchedulingActivityDirective.of(actTypeA, planningHorizon.getStartAerie().plus(Duration.of(10, Duration.HOURS)), Duration.of(activityDurationHours, Duration.HOURS), Map.of( + SchedulingActivity act3 = SchedulingActivity.of(idGenerator.next(), actTypeA, planningHorizon.getStartAerie().plus(Duration.of(10, Duration.HOURS)), Duration.of(activityDurationHours, Duration.HOURS), Map.of( "quantity", SerializedValue.of(1), "growingDuration", SerializedValue.of(Duration.HOUR.times(activityDurationHours).in(Duration.HOURS)) - ), null, null, true); + ), null, null, true, false); partialPlan.add(act3); actsToBeAnchored.add(act3); @@ -495,34 +498,34 @@ public TestData createTestCaseStartsAt(final PersistentTimeAnchor persistentAnch if(missingActAssociationsWithAnchor){ // Activities with anchors - SchedulingActivityDirective act4 = SchedulingActivityDirective.of(actTypeB, relativeOffset, Duration.of(activityDurationHours, Duration.HOURS), Map.of( - "quantity", SerializedValue.of(1)),null, act1.id(), anchoredToStart); + SchedulingActivity act4 = SchedulingActivity.of(idGenerator.next(), actTypeB, relativeOffset, Duration.of(activityDurationHours, Duration.HOURS), Map.of( + "quantity", SerializedValue.of(1)), null, act1.id(), anchoredToStart, false); partialPlan.add(act4); templateActsAlreadyAnchor.add(act4); - SchedulingActivityDirective act5 = SchedulingActivityDirective.of(actTypeB, relativeOffset, Duration.of(activityDurationHours, Duration.HOURS), Map.of( - "quantity", SerializedValue.of(1)),null, act2.id(), anchoredToStart); + SchedulingActivity act5 = SchedulingActivity.of(idGenerator.next(), actTypeB, relativeOffset, Duration.of(activityDurationHours, Duration.HOURS), Map.of( + "quantity", SerializedValue.of(1)), null, act2.id(), anchoredToStart, false); partialPlan.add(act5); templateActsAlreadyAnchor.add(act5); - SchedulingActivityDirective act6 = SchedulingActivityDirective.of(actTypeB, relativeOffset, Duration.of(activityDurationHours, Duration.HOURS), Map.of( - "quantity", SerializedValue.of(1)),null, act3.id(), anchoredToStart); + SchedulingActivity act6 = SchedulingActivity.of(idGenerator.next(), actTypeB, relativeOffset, Duration.of(activityDurationHours, Duration.HOURS), Map.of( + "quantity", SerializedValue.of(1)), null, act3.id(), anchoredToStart, false); partialPlan.add(act6); templateActsAlreadyAnchor.add(act6); } if(missingActAssociationsWithoutAnchor){ // Activities without anchors - SchedulingActivityDirective act7 = SchedulingActivityDirective.of(actTypeB, planningHorizon.getStartAerie().plus(offsetWithDuration), Duration.of(activityDurationHours, Duration.HOURS), Map.of( - "quantity", SerializedValue.of(1)),null, anchoredToStart); + SchedulingActivity act7 = SchedulingActivity.of(idGenerator.next(), actTypeB, planningHorizon.getStartAerie().plus(offsetWithDuration), Duration.of(activityDurationHours, Duration.HOURS), Map.of( + "quantity", SerializedValue.of(1)), null, null, anchoredToStart, false); partialPlan.add(act7); - SchedulingActivityDirective act8 = SchedulingActivityDirective.of(actTypeB, planningHorizon.getStartAerie().plus(Duration.of(5, Duration.HOURS)).plus(offsetWithDuration), Duration.of(activityDurationHours, Duration.HOURS), Map.of( - "quantity", SerializedValue.of(1)),null, anchoredToStart); + SchedulingActivity act8 = SchedulingActivity.of(idGenerator.next(), actTypeB, planningHorizon.getStartAerie().plus(Duration.of(5, Duration.HOURS)).plus(offsetWithDuration), Duration.of(activityDurationHours, Duration.HOURS), Map.of( + "quantity", SerializedValue.of(1)), null, null, anchoredToStart, false); partialPlan.add(act8); - SchedulingActivityDirective act9 = SchedulingActivityDirective.of(actTypeB, planningHorizon.getStartAerie().plus(Duration.of(10, Duration.HOURS)).plus(offsetWithDuration), Duration.of(activityDurationHours, Duration.HOURS), Map.of( - "quantity", SerializedValue.of(1)),null, anchoredToStart); + SchedulingActivity act9 = SchedulingActivity.of(idGenerator.next(), actTypeB, planningHorizon.getStartAerie().plus(Duration.of(10, Duration.HOURS)).plus(offsetWithDuration), Duration.of(activityDurationHours, Duration.HOURS), Map.of( + "quantity", SerializedValue.of(1)), null, null, anchoredToStart, false); partialPlan.add(act9); if (!persistentAnchor.equals(PersistentTimeAnchor.DISABLED) && !missingActAssociationsWithAnchor) { @@ -583,7 +586,7 @@ public TestData createTestCaseStartsAt(final PersistentTimeAnchor persistentAnch templateNewActsAnchored.removeAll(partialPlan.getActivities()); - for(SchedulingActivityDirective a : plan.get().getActivitiesByTime()){ + for(SchedulingActivity a : plan.get().getActivitiesByTime()){ logger.debug(a.startOffset().toString() + ", " + a.duration().toString()); } return new TestData(plan, actsToBeAnchored, templateActsAlreadyAnchor, templateActsWithoutAnchorAnchored, templateActsWithoutAnchorNotAnchored, templateNewActsAnchored); diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestUnsatisfiableCompositeGoals.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestUnsatisfiableCompositeGoals.java index 83dbb41db2..d2802cf614 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestUnsatisfiableCompositeGoals.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestUnsatisfiableCompositeGoals.java @@ -16,7 +16,7 @@ import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.Problem; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -32,6 +32,8 @@ public class TestUnsatisfiableCompositeGoals { + private final static DirectiveIdGenerator idGenerator = new DirectiveIdGenerator(0); + private final static PlanningHorizon h = new PlanningHorizon( TimeUtility.fromDOY("2025-001T00:00:00.000"), TimeUtility.fromDOY("2025-002T00:00:00.000") @@ -55,8 +57,8 @@ private static Problem makeTestMissionABWithCache() { private static PlanInMemory makePlanA12(Problem problem) { final var plan = new PlanInMemory(); final var actTypeA = problem.getActivityType("ControllableDurationActivity"); - plan.add(SchedulingActivityDirective.of(actTypeA, t1hr, d1min, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t2hr, d1min, null, true)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t1hr, d1min, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t2hr, d1min, null, true, false)); return plan; } diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestUtility.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestUtility.java index 537416e344..40d5f1e21d 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestUtility.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestUtility.java @@ -9,7 +9,7 @@ import gov.nasa.jpl.aerie.constraints.tree.WindowsFromSpans; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.SchedulingCondition; @@ -28,8 +28,8 @@ public static boolean emptyPlan(Plan plan) { return plan.getActivities().isEmpty(); } public static boolean activityStartingAtTime(Plan plan, Duration time, ActivityType activityType) { - List acts = plan.getActivitiesByTime(); - for (SchedulingActivityDirective act : acts) { + List acts = plan.getActivitiesByTime(); + for (SchedulingActivity act : acts) { if (act.getType().equals(activityType) && act.startOffset().compareTo(time) == 0) { return true; } @@ -38,8 +38,8 @@ public static boolean activityStartingAtTime(Plan plan, Duration time, ActivityT } public static boolean containsActivity(Plan plan, Duration startTime, Duration endTime, ActivityType activityType) { - List acts = plan.getActivitiesByTime(); - for (SchedulingActivityDirective act : acts) { + List acts = plan.getActivitiesByTime(); + for (SchedulingActivity act : acts) { if (act.getType().equals(activityType) && act.startOffset().compareTo(startTime) == 0 && act.getEndTime().compareTo(endTime) == 0) { @@ -65,8 +65,8 @@ public static boolean atLeastOneActivityOfTypeInTW(Plan plan, Windows tw, Activi */ public static boolean atLeastOneActivityOfTypeInRange(Plan plan, Interval interval, ActivityType activityType) { - List acts = plan.getActivitiesByTime(); - for (SchedulingActivityDirective act : acts) { + List acts = plan.getActivitiesByTime(); + for (SchedulingActivity act : acts) { if (act.getType().equals(activityType) && act.startOffset().compareTo(interval.start) >= 0 && act.getEndTime().compareTo(interval.end) <= 0) { @@ -117,8 +117,8 @@ public static List createAutoMutexGlobalSchedulingCondition /** * Returns true if plan does not contain specific activity instance act */ - public static boolean doesNotContainActivity(Plan plan, SchedulingActivityDirective act) { - for (SchedulingActivityDirective actI : plan.getActivitiesByTime()) { + public static boolean doesNotContainActivity(Plan plan, SchedulingActivity act) { + for (SchedulingActivity actI : plan.getActivitiesByTime()) { if (actI.equals(act)) { return false; } @@ -129,8 +129,8 @@ public static boolean doesNotContainActivity(Plan plan, SchedulingActivityDirect /** * Returns true if plan contains specific activity instance act */ - public static boolean containsExactlyActivity(Plan plan, SchedulingActivityDirective act) { - for (SchedulingActivityDirective actI : plan.getActivitiesByTime()) { + public static boolean containsExactlyActivity(Plan plan, SchedulingActivity act) { + for (SchedulingActivity actI : plan.getActivitiesByTime()) { if (actI.equalsInProperties(act)) { return true; } @@ -152,17 +152,17 @@ public static Instant timeFromEpochDays(int days) { } /** matches activities if they agree in everything except the (possibly auto-generated) names **/ - public static void assertSetEquality(List expected, List actual) { + public static void assertSetEquality(List expected, List actual) { assertEquals(expected.size(), actual.size()); final var backupExpected = new ArrayList<>(expected); - for (SchedulingActivityDirective directive : actual) { + for (SchedulingActivity directive : actual) { final int matchIndex = getIndexSADList(backupExpected, directive); assertNotEquals(-1, matchIndex); backupExpected.remove(matchIndex); // Remove to avoid similar elements matching twice } } - private static int getIndexSADList(List list, SchedulingActivityDirective directive) { + private static int getIndexSADList(List list, SchedulingActivity directive) { for (int i = 0; i < list.size(); ++i) { if (list.get(i).equalsInProperties(directive)) { return i; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/UncontrollableDurationTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/UncontrollableDurationTest.java index bf965c5161..9487ebefd2 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/UncontrollableDurationTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/UncontrollableDurationTest.java @@ -11,7 +11,7 @@ import gov.nasa.jpl.aerie.scheduler.constraints.timeexpressions.TimeExpressionRelativeSimple; import gov.nasa.jpl.aerie.scheduler.goals.CoexistenceGoal; import gov.nasa.jpl.aerie.scheduler.goals.RecurrenceGoal; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; @@ -27,6 +27,8 @@ public class UncontrollableDurationTest { + private final DirectiveIdGenerator idGenerator = new DirectiveIdGenerator(0); + PlanningHorizon planningHorizon; Problem problem; Plan plan; @@ -148,9 +150,9 @@ public void testTimeDependent() throws SchedulingInterruptedException { @Test public void testBug() throws SchedulingInterruptedException { - final var controllableDurationActivity = SchedulingActivityDirective.of(problem.getActivityType("ControllableDurationActivity"), + final var controllableDurationActivity = SchedulingActivity.of(idGenerator.next(), problem.getActivityType("ControllableDurationActivity"), Duration.of(1, Duration.MICROSECONDS), - Duration.of(3, Duration.MICROSECONDS), null, true); + Duration.of(3, Duration.MICROSECONDS), null, true, false); final var zeroDurationUncontrollableActivity = new ActivityExpression.Builder() .ofType(problem.getActivityType("ZeroDurationUncontrollableActivity")) diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/AnchorSchedulerTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/AnchorSchedulerTest.java index 3f557e3dbd..e9196c5a76 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/AnchorSchedulerTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/AnchorSchedulerTest.java @@ -9,8 +9,8 @@ import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.OneStepTask; import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivityId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.SimulationResultsComputerInputs; @@ -105,7 +105,7 @@ private static void assertEqualsSimulationResults(SimulationResults expected, Si } } - private void constructFullComplete5AryTree(int maxLevel, int currentLevel, long parentNode, Map activitiesToSimulate, Map simulatedActivities){ + private void constructFullComplete5AryTree(int maxLevel, int currentLevel, long parentNode, Map activitiesToSimulate, Map simulatedActivities){ if(currentLevel > maxLevel) return; for(int i = 1; i <= 5; i++) { long curElement = parentNode*5+i; @@ -113,8 +113,8 @@ private void constructFullComplete5AryTree(int maxLevel, int currentLevel, long new ActivityDirectiveId(curElement), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(parentNode), false)); simulatedActivities.put( - new SimulatedActivityId(curElement), - new SimulatedActivity( + new ActivityInstanceId(curElement), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(currentLevel, ChronoUnit.MINUTES), @@ -126,7 +126,7 @@ private void constructFullComplete5AryTree(int maxLevel, int currentLevel, long } } - private static void assertEqualsAsideFromChildren(SimulatedActivity expected, SimulatedActivity actual){ + private static void assertEqualsAsideFromChildren(ActivityInstance expected, ActivityInstance actual){ assertEquals(expected.type(), actual.type()); assertEquals(expected.arguments(), actual.arguments()); assertEquals(expected.start(), actual.start()); @@ -141,7 +141,7 @@ private static void assertEqualsAsideFromChildren(SimulatedActivity expected, Si public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { final var minusOneMinute = Duration.of(-60, Duration.SECONDS); final var resolveToPlanStartAnchors = new HashMap(415); - final Map simulatedActivities = new HashMap<>(415); + final Map simulatedActivities = new HashMap<>(415); // Anchored to Plan Start (only positive is allowed) for (long l = 0; l < 5; l++) { @@ -149,7 +149,7 @@ public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { resolveToPlanStartAnchors.put( activityDirectiveId, new ActivityDirective(Duration.of(l, Duration.SECONDS), serializedDelayDirective, null, true)); - simulatedActivities.put(new SimulatedActivityId(l), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(l), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(l, ChronoUnit.SECONDS), @@ -166,7 +166,7 @@ public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { resolveToPlanStartAnchors.put( activityDirectiveId, new ActivityDirective(Duration.of(-l, Duration.MINUTES), serializedDelayDirective, null, false)); // Minutes so they finish by simulation end - simulatedActivities.put(new SimulatedActivityId(l), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(l), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(10, ChronoUnit.DAYS).minus(l, ChronoUnit.MINUTES), @@ -182,7 +182,7 @@ public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { resolveToPlanStartAnchors.put( new ActivityDirectiveId(15), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(0), true)); - simulatedActivities.put(new SimulatedActivityId(15), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(15), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -199,7 +199,7 @@ public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { resolveToPlanStartAnchors.put( activityDirectiveId, new ActivityDirective(oneMinute, serializedDelayDirective, new ActivityDirectiveId(l - 1), true)); - simulatedActivities.put(new SimulatedActivityId(l), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(l), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -213,7 +213,7 @@ public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { resolveToPlanStartAnchors.put( activityDirectiveId, new ActivityDirective(minusOneMinute, serializedDelayDirective, new ActivityDirectiveId(l - 1), true)); - simulatedActivities.put(new SimulatedActivityId(l), new SimulatedActivity( + simulatedActivities.put(new ActivityInstanceId(l), new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, @@ -248,7 +248,7 @@ public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { public void activitiesAnchoredToOtherActivities() throws SchedulingInterruptedException { final var allEndTimeAnchors = new HashMap(400); final var endTimeAnchorEveryFifth = new HashMap(400); - final Map simulatedActivities = new HashMap<>(800); + final Map simulatedActivities = new HashMap<>(800); final var activitiesToSimulate = new HashMap(800); allEndTimeAnchors.put( @@ -258,8 +258,8 @@ public void activitiesAnchoredToOtherActivities() throws SchedulingInterruptedEx new ActivityDirectiveId(400), new ActivityDirective(oneMinute, serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(0), - new SimulatedActivity( + new ActivityInstanceId(0), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -269,8 +269,8 @@ public void activitiesAnchoredToOtherActivities() throws SchedulingInterruptedEx Optional.of(new ActivityDirectiveId(0)), computedAttributes)); simulatedActivities.put( - new SimulatedActivityId(400), - new SimulatedActivity( + new ActivityInstanceId(400), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), @@ -292,8 +292,8 @@ public void activitiesAnchoredToOtherActivities() throws SchedulingInterruptedEx new ActivityDirectiveId(l - 1), false)); simulatedActivities.put( - new SimulatedActivityId(l), - new SimulatedActivity( + new ActivityInstanceId(l), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus((2*l)+1, ChronoUnit.MINUTES), @@ -322,8 +322,8 @@ public void activitiesAnchoredToOtherActivities() throws SchedulingInterruptedEx true)); } simulatedActivities.put( - new SimulatedActivityId(k), - new SimulatedActivity( + new ActivityInstanceId(k), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(l+c, ChronoUnit.MINUTES), @@ -380,7 +380,7 @@ public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedExcept final var activitiesToSimulate = new HashMap(23); // NOTE: This list is intentionally keyed on ActivityDirectiveId, not on SimulatedActivityId. // Additionally, because we do not know the order the child activities will generate in, DecompositionDirectives will have a List.of() rather than the correct value - final var topLevelSimulatedActivities = new HashMap(23); + final var topLevelSimulatedActivities = new HashMap(23); final var threeMinutes = Duration.of(3, Duration.MINUTES); // ND <-s- D <-s- D @@ -389,131 +389,131 @@ public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedExcept activitiesToSimulate.put(new ActivityDirectiveId(3), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(2), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(1), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(1)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(1)), computedAttributes)); topLevelSimulatedActivities.put( new ActivityDirectiveId(2), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(2)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(2)), computedAttributes)); topLevelSimulatedActivities.put( new ActivityDirectiveId(3), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(3)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(3)), computedAttributes)); // ND <-s- D <-e- D activitiesToSimulate.put(new ActivityDirectiveId(4), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(2), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(4), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(4)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(4)), computedAttributes)); // ND <-s- D <-s- ND activitiesToSimulate.put(new ActivityDirectiveId(5), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(2), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(5), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(5)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(5)), computedAttributes)); // ND <-s- D <-e- ND activitiesToSimulate.put(new ActivityDirectiveId(6), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(2), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(6), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(6)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(6)), computedAttributes)); // ND <-e- D <-s- D activitiesToSimulate.put(new ActivityDirectiveId(7), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(1), false)); activitiesToSimulate.put(new ActivityDirectiveId(8), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(7), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(7), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(7)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(7)), computedAttributes)); topLevelSimulatedActivities.put( new ActivityDirectiveId(8), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(8)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(8)), computedAttributes)); // ND <-e- D <-e- D activitiesToSimulate.put(new ActivityDirectiveId(9), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(7), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(9), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(9)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(9)), computedAttributes)); // ND <-e- D <-s- ND activitiesToSimulate.put(new ActivityDirectiveId(10), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(7), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(10), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(10)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(10)), computedAttributes)); // ND <-e- D <-e- ND activitiesToSimulate.put(new ActivityDirectiveId(11), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(7), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(11), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(11)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(11)), computedAttributes)); // D <-s- D <-s- D activitiesToSimulate.put(new ActivityDirectiveId(12), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(3), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(12), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(12)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(12)), computedAttributes)); // D <-s- D <-e- D activitiesToSimulate.put(new ActivityDirectiveId(13), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(3), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(13), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(13)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(13)), computedAttributes)); // D <-s- D <-s- ND activitiesToSimulate.put(new ActivityDirectiveId(14), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(3), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(14), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(14)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(14)), computedAttributes)); // D <-s- D <-e- ND activitiesToSimulate.put(new ActivityDirectiveId(15), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(3), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(15), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(15)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(15)), computedAttributes)); // D <-e- D <-s- D activitiesToSimulate.put(new ActivityDirectiveId(16), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(4), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(16), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(16)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(16)), computedAttributes)); // D <-e- D <-e- D activitiesToSimulate.put(new ActivityDirectiveId(17), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(4), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(17), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(6, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(17)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(6, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(17)), computedAttributes)); // D <-e- D <-s- ND activitiesToSimulate.put(new ActivityDirectiveId(18), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(4), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(18), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(18)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(18)), computedAttributes)); // D <-e- D <-e- ND activitiesToSimulate.put(new ActivityDirectiveId(19), new ActivityDirective(Duration.ZERO, serializedDelayDirective, new ActivityDirectiveId(4), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(19), - new SimulatedActivity(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(6, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(19)), computedAttributes)); + new ActivityInstance(serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(6, ChronoUnit.MINUTES), oneMinute, null, List.of(), Optional.of(new ActivityDirectiveId(19)), computedAttributes)); // D <-s- ND <-s- D activitiesToSimulate.put(new ActivityDirectiveId(20), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(14), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(20), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(20)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH, threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(20)), computedAttributes)); // D <-s- ND <-e- D activitiesToSimulate.put(new ActivityDirectiveId(21), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(14), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(21), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(21)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(1, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(21)), computedAttributes)); // D <-e- ND <-s- D activitiesToSimulate.put(new ActivityDirectiveId(22), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(15), true)); topLevelSimulatedActivities.put( new ActivityDirectiveId(22), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(22)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(3, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(22)), computedAttributes)); // D <-e- ND <-e- D activitiesToSimulate.put(new ActivityDirectiveId(23), new ActivityDirective(Duration.ZERO, serializedDecompositionDirective, new ActivityDirectiveId(15), false)); topLevelSimulatedActivities.put( new ActivityDirectiveId(23), - new SimulatedActivity(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(23)), computedAttributes)); + new ActivityInstance(serializedDecompositionDirective.getTypeName(), Map.of(), Instant.EPOCH.plus(4, ChronoUnit.MINUTES), threeMinutes, null, List.of(), Optional.of(new ActivityDirectiveId(23)), computedAttributes)); final var actualSimResults = simulateActivities(activitiesToSimulate).computeResults(); @@ -524,8 +524,8 @@ public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedExcept assertEquals(modelTopicList.get(i), actualSimResults.topics.get(i)); } - final var childSimulatedActivities = new HashMap(28); - final var otherSimulatedActivities = new HashMap(23); + final var childSimulatedActivities = new HashMap(28); + final var otherSimulatedActivities = new HashMap(23); assertEquals(51, actualSimResults.simulatedActivities.size()); // 23 + 2*(14 Decomposing activities) for(final var entry : actualSimResults.simulatedActivities.entrySet()) { @@ -557,7 +557,7 @@ public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedExcept if(firstChild.start().isBefore(secondChild.start())){ assertEqualsAsideFromChildren( - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), entry.getValue().start(), @@ -568,7 +568,7 @@ public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedExcept computedAttributes), firstChild); assertEqualsAsideFromChildren( - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), entry.getValue().start().plus(2, ChronoUnit.MINUTES), @@ -580,7 +580,7 @@ public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedExcept secondChild); } else { assertEqualsAsideFromChildren( - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), entry.getValue().start().plus(2, ChronoUnit.MINUTES), @@ -591,7 +591,7 @@ public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedExcept computedAttributes), firstChild); assertEqualsAsideFromChildren( - new SimulatedActivity( + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), entry.getValue().start(), @@ -616,14 +616,14 @@ public void naryTreeAnchorChain() throws SchedulingInterruptedException{ // Number of activity directives = 5^0 + 5^1 + 5^2 + 5^3 + 5^4 + 5^5 = 3906 final var activitiesToSimulate = new HashMap(3906); - final var simulatedActivities = new HashMap(3906); + final var simulatedActivities = new HashMap(3906); activitiesToSimulate.put( new ActivityDirectiveId(0), new ActivityDirective(Duration.ZERO, serializedDelayDirective, null, true)); simulatedActivities.put( - new SimulatedActivityId(0), - new SimulatedActivity( + new ActivityInstanceId(0), + new ActivityInstance( serializedDelayDirective.getTypeName(), Map.of(), Instant.EPOCH, diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacadeTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacadeTest.java index 1753eba5d4..6425adbd4f 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacadeTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacadeTest.java @@ -4,13 +4,14 @@ import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.framework.ThreadedTask; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.scheduler.DirectiveIdGenerator; import gov.nasa.jpl.aerie.scheduler.SchedulingInterruptedException; import gov.nasa.jpl.aerie.scheduler.SimulationUtility; import gov.nasa.jpl.aerie.scheduler.TimeUtility; import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -23,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; public class CheckpointSimulationFacadeTest { + private static final DirectiveIdGenerator idGenerator = new DirectiveIdGenerator(0); private SimulationFacade newSimulationFacade; private final static PlanningHorizon H = new PlanningHorizon(TimeUtility.fromDOY("2025-001T00:00:00.000"), TimeUtility.fromDOY("2025-005T00:00:00.000")); private Map activityTypes; @@ -33,9 +35,9 @@ public class CheckpointSimulationFacadeTest { private static PlanInMemory makePlanA012(Map activityTypeMap) { final var plan = new PlanInMemory(); final var actTypeA = activityTypeMap.get("BasicActivity"); - plan.add(SchedulingActivityDirective.of(actTypeA, t0, null, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t1hr, null, null, true)); - plan.add(SchedulingActivityDirective.of(actTypeA, t2hr, null, null, true)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t0, null, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t1hr, null, null, true, false)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t2hr, null, null, true, false)); return plan; } @BeforeEach @@ -101,7 +103,7 @@ public void testStopsAtEndOfPlanningHorizon() { final var plan = new PlanInMemory(); final var actTypeA = activityTypes.get("ControllableDurationActivity"); - plan.add(SchedulingActivityDirective.of(actTypeA, t0, HOUR.times(200), null, true)); + plan.add(SchedulingActivity.of(idGenerator.next(), actTypeA, t0, HOUR.times(200), null, true, false)); final var results = newSimulationFacade.simulateNoResultsAllActivities(plan).computeResults(); assertEquals(H.getEndAerie(), results.duration); assert(results.unfinishedActivities.size() == 1); diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/InstantiateArgumentsTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/InstantiateArgumentsTest.java index 57a45b7c18..52e077e2d2 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/InstantiateArgumentsTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/InstantiateArgumentsTest.java @@ -24,7 +24,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Unit; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.scheduler.model.ActivityType; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import org.junit.jupiter.api.Test; import java.time.Instant; @@ -85,7 +85,7 @@ public void instantiateArgumentsSingletonBoundsTest(){ Map.entry("duration", new ProfileExpression<>(new DiscreteValue(SerializedValue.of(Duration.of(1, HOUR).in(MICROSECONDS)))))) ); - final var arguments = SchedulingActivityDirective.instantiateArguments(sea.fields(), Duration.of(1, HOUR), simulationResults, environment, fauxType); + final var arguments = SchedulingActivity.instantiateArguments(sea.fields(), Duration.of(1, HOUR), simulationResults, environment, fauxType); assertEquals(4, arguments.size()); diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationResultsComparisonUtils.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationResultsComparisonUtils.java index 43918e54fa..227e93b89e 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationResultsComparisonUtils.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationResultsComparisonUtils.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.scheduler.simulation; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.engine.ProfileSegment; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -156,10 +156,10 @@ public static void assertEqualsTSA(final Set expected, // Representation of simulated activities as trees of activities public record TreeSimulatedActivity(StrippedSimulatedActivity activity, Set children){ - public static TreeSimulatedActivity fromSimulatedActivity(SimulatedActivity simulatedActivity, SimulationResults simulationResults){ - final var stripped = StrippedSimulatedActivity.fromSimulatedActivity(simulatedActivity); + public static TreeSimulatedActivity fromSimulatedActivity(ActivityInstance activityInstance, SimulationResults simulationResults){ + final var stripped = StrippedSimulatedActivity.fromSimulatedActivity(activityInstance); final HashSet children = new HashSet<>(); - for(final var childId: simulatedActivity.childIds()) { + for(final var childId: activityInstance.childIds()) { final var child = fromSimulatedActivity(simulationResults.simulatedActivities.get(childId), simulationResults); children.add(child); } @@ -176,13 +176,13 @@ public record StrippedSimulatedActivity( Duration duration, SerializedValue computedAttributes ){ - public static StrippedSimulatedActivity fromSimulatedActivity(SimulatedActivity simulatedActivity){ + public static StrippedSimulatedActivity fromSimulatedActivity(ActivityInstance activityInstance){ return new StrippedSimulatedActivity( - simulatedActivity.type(), - simulatedActivity.arguments(), - simulatedActivity.start(), - simulatedActivity.duration(), - simulatedActivity.computedAttributes() + activityInstance.type(), + activityInstance.arguments(), + activityInstance.start(), + activityInstance.duration(), + activityInstance.computedAttributes() ); } } diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/SchedulerAppDriver.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/SchedulerAppDriver.java index 1e29680460..5be5baddc5 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/SchedulerAppDriver.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/SchedulerAppDriver.java @@ -14,7 +14,7 @@ import gov.nasa.jpl.aerie.scheduler.server.remotes.postgres.PostgresResultsCellRepository; import gov.nasa.jpl.aerie.scheduler.server.remotes.postgres.PostgresSpecificationRepository; import gov.nasa.jpl.aerie.scheduler.server.services.GenerateSchedulingLibAction; -import gov.nasa.jpl.aerie.scheduler.server.services.GraphQLMerlinService; +import gov.nasa.jpl.aerie.scheduler.server.services.GraphQLMerlinDatabaseService; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleAction; import gov.nasa.jpl.aerie.scheduler.server.services.SchedulerService; import gov.nasa.jpl.aerie.scheduler.server.services.SpecificationService; @@ -48,7 +48,7 @@ public static void main(final String[] args) { //load the service configuration options final var config = loadConfiguration(); - final var merlinService = new GraphQLMerlinService(config.merlinGraphqlURI(), config.hasuraGraphQlAdminSecret()); + final var merlinDatabaseService = new GraphQLMerlinDatabaseService(config.merlinGraphqlURI(), config.hasuraGraphQlAdminSecret()); final var permissionsService = new PermissionsService(new GraphQLPermissionsService(config.merlinGraphqlURI(), config.hasuraGraphQlAdminSecret())); final var stores = loadStores(config); @@ -58,7 +58,7 @@ public static void main(final String[] args) { final var schedulerService = new SchedulerService(stores.results()); final var scheduleAction = new ScheduleAction(specificationService, schedulerService); - final var generateSchedulingLibAction = new GenerateSchedulingLibAction(merlinService); + final var generateSchedulingLibAction = new GenerateSchedulingLibAction(merlinDatabaseService); //establish bindings to the service layers final var bindings = new SchedulerBindings( diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/http/ActivityTemplateJsonParser.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/http/ActivityTemplateJsonParser.java index 9f39ec076f..5d25b5f3e5 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/http/ActivityTemplateJsonParser.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/http/ActivityTemplateJsonParser.java @@ -11,7 +11,7 @@ import gov.nasa.jpl.aerie.json.SchemaCache; import gov.nasa.jpl.aerie.scheduler.server.models.ActivityType; import gov.nasa.jpl.aerie.scheduler.server.models.SchedulingDSL; -import gov.nasa.jpl.aerie.scheduler.server.services.MerlinService; +import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import static gov.nasa.jpl.aerie.constraints.json.ConstraintParsers.profileExpressionP; import static gov.nasa.jpl.aerie.constraints.json.ConstraintParsers.structExpressionF; @@ -20,7 +20,7 @@ public class ActivityTemplateJsonParser implements JsonParser activityTypesByName = new HashMap<>(); - public ActivityTemplateJsonParser(MerlinService.MissionModelTypes activityTypes){ + public ActivityTemplateJsonParser(MerlinDatabaseService.MissionModelTypes activityTypes){ activityTypes.activityTypes().forEach((actType)-> activityTypesByName.put(actType.name(), actType)); } diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/SchedulingDSL.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/SchedulingDSL.java index 2cfe67c554..04044b150a 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/SchedulingDSL.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/SchedulingDSL.java @@ -13,7 +13,7 @@ import gov.nasa.jpl.aerie.scheduler.constraints.timeexpressions.TimeAnchor; import gov.nasa.jpl.aerie.scheduler.model.PersistentTimeAnchor; import gov.nasa.jpl.aerie.scheduler.server.http.ActivityTemplateJsonParser; -import gov.nasa.jpl.aerie.scheduler.server.services.MerlinService; +import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import org.apache.commons.lang3.tuple.Pair; import java.util.List; @@ -58,7 +58,7 @@ public class SchedulingDSL { $ -> tuple($.duration(), $.occurrence())); private static JsonObjectParser recurrenceGoalDefinitionP( - MerlinService.MissionModelTypes activityTypes) + MerlinDatabaseService.MissionModelTypes activityTypes) { return productP .field("activityTemplate", new ActivityTemplateJsonParser(activityTypes)) @@ -113,7 +113,7 @@ private static JsonObjectParser recurren (TimingConstraint.ActivityTimingConstraintFlexibleRange $) -> tuple($.lowerBound(), $.upperBound(), $.singleton())); private static JsonObjectParser coexistenceGoalDefinitionP( - MerlinService.MissionModelTypes activityTypes) + MerlinDatabaseService.MissionModelTypes activityTypes) { return productP @@ -148,7 +148,7 @@ private static JsonObjectParser coexist } private static JsonObjectParser cardinalityGoalDefinitionP( - MerlinService.MissionModelTypes activityTypes) { + MerlinDatabaseService.MissionModelTypes activityTypes) { return productP .field("activityTemplate", new ActivityTemplateJsonParser(activityTypes)) @@ -197,7 +197,7 @@ private static JsonObjectParser goalApplyWhenF(fina } - private static JsonParser goalSpecifierF(MerlinService.MissionModelTypes missionModelTypes) { + private static JsonParser goalSpecifierF(MerlinDatabaseService.MissionModelTypes missionModelTypes) { return recursiveP(self -> SumParsers.sumP("kind", GoalSpecifier.class, List.of( SumParsers.variant( "ActivityRecurrenceGoal", @@ -245,7 +245,7 @@ private static JsonObjectParser conditionAndF(f globalSchedulingConditionP) ))); - public static JsonParser schedulingJsonP(MerlinService.MissionModelTypes missionModelTypes){ + public static JsonParser schedulingJsonP(MerlinDatabaseService.MissionModelTypes missionModelTypes){ return goalSpecifierF(missionModelTypes); } diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GoalBuilder.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GoalBuilder.java index e46ab75afe..ab0fe3a881 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GoalBuilder.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GoalBuilder.java @@ -185,14 +185,14 @@ public Boolean apply( final SimulationResults simResults, final EvaluationEnvironment environment) { - final var startTime = activityInstance.interval.start; - if (!activityInstance.type.equals(c.type())) return false; + final var startTime = activityInstance.interval().start; + if (!activityInstance.type().equals(c.type())) return false; for (final var arg : c .arguments() .map(expr -> expr.evaluateMap(simResults, startTime, environment)) .orElse(Map.of()) .entrySet()) { - if (!arg.getValue().equals(activityInstance.parameters.get(arg.getKey()))) return false; + if (!arg.getValue().equals(activityInstance.parameters().get(arg.getKey()))) return false; } return true; } diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/ConstraintsTypescriptCodeGenerationHelper.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/ConstraintsTypescriptCodeGenerationHelper.java index 79469321c4..d6b59b65dc 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/ConstraintsTypescriptCodeGenerationHelper.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/ConstraintsTypescriptCodeGenerationHelper.java @@ -9,7 +9,7 @@ public final class ConstraintsTypescriptCodeGenerationHelper { private ConstraintsTypescriptCodeGenerationHelper() { } - public static Map activityTypes(final MerlinService.MissionModelTypes missionModelTypes) { + public static Map activityTypes(final MerlinDatabaseService.MissionModelTypes missionModelTypes) { return missionModelTypes .activityTypes() .stream() @@ -27,7 +27,7 @@ public static Map activity .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } - public static Map resources(final MerlinService.MissionModelTypes missionModelTypes) { + public static Map resources(final MerlinDatabaseService.MissionModelTypes missionModelTypes) { return missionModelTypes .resourceTypes() .stream() diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GenerateSchedulingLibAction.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GenerateSchedulingLibAction.java index d1c61dfaef..ff38298154 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GenerateSchedulingLibAction.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GenerateSchedulingLibAction.java @@ -14,10 +14,10 @@ import gov.nasa.jpl.aerie.scheduler.server.models.PlanId; public record GenerateSchedulingLibAction( - MerlinService.ReaderRole merlinService + MerlinDatabaseService.ReaderRole merlinDatabaseService ) { public GenerateSchedulingLibAction { - Objects.requireNonNull(merlinService); + Objects.requireNonNull(merlinDatabaseService); } /** @@ -45,10 +45,10 @@ public Response run(final MissionModelId missionModelId, final Optional final var temporalPolyfillTypes = getTypescriptResource("constraints/TemporalPolyfillTypes.ts"); - var missionModelTypes = merlinService.getMissionModelTypes(missionModelId); + var missionModelTypes = merlinDatabaseService.getMissionModelTypes(missionModelId); if(planId.isPresent()) { - final var allResourceTypes = merlinService.getResourceTypes(planId.get()); - missionModelTypes = new MerlinService.MissionModelTypes(missionModelTypes.activityTypes(), allResourceTypes); + final var allResourceTypes = merlinDatabaseService.getResourceTypes(planId.get()); + missionModelTypes = new MerlinDatabaseService.MissionModelTypes(missionModelTypes.activityTypes(), allResourceTypes); } final var generatedSchedulerCode = TypescriptCodeGenerationService.generateTypescriptTypesFromMissionModel(missionModelTypes); diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinService.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinDatabaseService.java similarity index 90% rename from scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinService.java rename to scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinDatabaseService.java index 6d6d6ec076..a2be8388c6 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinService.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinDatabaseService.java @@ -6,8 +6,8 @@ import gov.nasa.jpl.aerie.json.JsonParser; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivity; -import gov.nasa.jpl.aerie.merlin.driver.SimulatedActivityId; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.UnfinishedActivity; import gov.nasa.jpl.aerie.merlin.driver.engine.EventRecord; @@ -24,8 +24,7 @@ import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.Problem; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.server.exceptions.NoSuchMissionModelException; import gov.nasa.jpl.aerie.scheduler.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.scheduler.server.graphql.GraphQLParsers; @@ -96,7 +95,7 @@ * * @param merlinGraphqlURI endpoint of the merlin graphql service that should be used to access all plan data */ -public record GraphQLMerlinService(URI merlinGraphqlURI, String hasuraGraphQlAdminSecret) implements MerlinService.OwnerRole { +public record GraphQLMerlinDatabaseService(URI merlinGraphqlURI, String hasuraGraphQlAdminSecret) implements MerlinDatabaseService.OwnerRole { /** * timeout for http graphql requests issued to aerie @@ -359,10 +358,10 @@ public String getNextPlanName() { * @return */ @Override - public Pair> createNewPlanWithActivityDirectives( + public Pair> createNewPlanWithActivityDirectives( final PlanMetadata planMetadata, final Plan plan, - final Map activityToGoalId, + final Map activityToGoalId, final SchedulerModel schedulerModel ) throws IOException, NoSuchPlanException, MerlinServiceException @@ -371,7 +370,7 @@ public Pair> creat final var planId = createEmptyPlan( planName, planMetadata.modelId(), planMetadata.horizon().getStartInstant(), planMetadata.horizon().getEndAerie()); - final Map activityToId = createAllPlanActivityDirectives(planId, plan, activityToGoalId, schedulerModel); + final Map activityToId = createAllPlanActivityDirectives(planId, plan, activityToGoalId, schedulerModel); return Pair.of(planId, activityToId); } @@ -411,52 +410,49 @@ public PlanId createEmptyPlan(final String name, final long modelId, final Insta * @return */ @Override - public Map updatePlanActivityDirectives( + public Map updatePlanActivityDirectives( final PlanId planId, - final Map idsFromInitialPlan, final MerlinPlan initialPlan, final Plan plan, - final Map activityToGoalId, + final Map activityToGoalId, final SchedulerModel schedulerModel ) throws IOException, NoSuchPlanException, MerlinServiceException { - final var ids = new HashMap(); + final var ids = new HashMap(); //creation are done in batch as that's what the scheduler does the most - final var toAdd = new ArrayList(); + final var toAdd = new ArrayList(); for (final var activity : plan.getActivities()) { if(activity.getParentActivity().isPresent()) continue; // Skip generated activities - final var idActFromInitialPlan = idsFromInitialPlan.get(activity.getId()); - if (idActFromInitialPlan != null) { + if (!activity.isNew()) { //add duration to parameters if controllable if (activity.getType().getDurationType() instanceof DurationType.Controllable durationType){ if (!activity.arguments().containsKey(durationType.parameterName())){ activity.addArgument(durationType.parameterName(), schedulerModel.serializeDuration(activity.duration())); } } - final var actFromInitialPlan = initialPlan.getActivityById(idActFromInitialPlan); + final var actFromInitialPlan = initialPlan.getActivityById(activity.id()); //if act was present in initial plan final var activityDirectiveFromSchedulingDirective = new ActivityDirective( activity.startOffset(), activity.type().getName(), activity.arguments(), - (activity.anchorId() != null ? new ActivityDirectiveId(-activity.anchorId().id()) : null), + activity.anchorId(), activity.anchoredToStart() ); - final var activityDirectiveId = idsFromInitialPlan.get(activity.getId()); if (!activityDirectiveFromSchedulingDirective.equals(actFromInitialPlan.get())) { throw new MerlinServiceException("The scheduler should not be updating activity instances"); //updateActivityDirective(planId, schedulerActIntoMerlinAct, activityDirectiveId, activityToGoalId.get(activity)); } - ids.put(activity, activityDirectiveId); + ids.put(activity.id(), activity.id()); } else { //act was not present in initial plan, create new activity toAdd.add(activity); } } final var actsFromNewPlan = plan.getActivitiesById(); - for (final var idActInInitialPlan : idsFromInitialPlan.entrySet()) { - if (!actsFromNewPlan.containsKey(idActInInitialPlan.getKey())) { + for (final var idInInitialPlan : initialPlan.getActivitiesById().keySet()) { + if (!actsFromNewPlan.containsKey(idInInitialPlan)) { throw new MerlinServiceException("The scheduler should not be deleting activity instances"); //deleteActivityDirective(idActInInitialPlan.getValue()); } @@ -468,17 +464,19 @@ public Map updatePlanActivityD } @Override - public void updatePlanActivityDirectiveAnchors(final PlanId planId, final List acts, final Map instancesToIds) + public void updatePlanActivityDirectiveAnchors(final PlanId planId, final Plan plan, final Map uploadIdMap) throws MerlinServiceException, IOException { - for (SchedulingActivityDirective act: acts) { - final var request = """ - mutation { - update_activity_directive_by_pk(pk_columns: {id: %d, plan_id: %d}, _set: {anchor_id: %d}) { - id - } - }""".formatted(instancesToIds.get(act).id(), planId.id(), act.anchorId().id()); - final var response = postRequest(request); + for (final SchedulingActivity act: plan.getActivities()) { + if (act.isNew() && act.anchorId() != null) { + final var request = """ + mutation { + update_activity_directive_by_pk(pk_columns: {id: %d, plan_id: %d}, _set: {anchor_id: %d}) { + id + } + }""".formatted(uploadIdMap.get(act.id()).id(), planId.id(), uploadIdMap.get(act.anchorId()).id()); + final var response = postRequest(request); + } } } @@ -537,10 +535,10 @@ public void clearPlanActivityDirectives(final PlanId planId) throws IOException, * @return */ @Override - public Map createAllPlanActivityDirectives( + public Map createAllPlanActivityDirectives( final PlanId planId, final Plan plan, - final Map activityToGoalId, + final Map activityToGoalId, final SchedulerModel schedulerModel ) throws IOException, NoSuchPlanException, MerlinServiceException @@ -548,10 +546,10 @@ public Map createAllPlanActivi return createActivityDirectives(planId, plan.getActivitiesByTime(), activityToGoalId, schedulerModel); } - public Map createActivityDirectives( + public Map createActivityDirectives( final PlanId planId, - final List orderedActivities, - final Map activityToGoalId, + final List orderedActivities, + final Map activityToGoalId, final SchedulerModel schedulerModel ) throws IOException, NoSuchPlanException, MerlinServiceException @@ -608,7 +606,7 @@ mutation createAllPlanActivityDirectives($activities: [activity_directive_insert final var response = postRequest(query, arguments).orElseThrow(() -> new NoSuchPlanException(planId)); - final Map instanceToInstanceId = new HashMap<>(); + final Map activityToDirectiveId = new HashMap<>(); try { final var numCreated = response .getJsonObject("data").getJsonObject("insert_activity_directive").getJsonNumber("affected_rows").longValueExact(); @@ -619,16 +617,17 @@ mutation createAllPlanActivityDirectives($activities: [activity_directive_insert .getJsonObject("data").getJsonObject("insert_activity_directive").getJsonArray("returning"); //make sure we associate the right id with the right activity for(int i = 0; i < ids.size(); i++) { - instanceToInstanceId.put(orderedActivities.get(i), new ActivityDirectiveId(ids.getJsonObject(i).getInt("id"))); + final var newId = new ActivityDirectiveId(ids.getJsonObject(i).getInt("id")); + activityToDirectiveId.put(orderedActivities.get(i).id(), newId); } } catch (ClassCastException | ArithmeticException e) { throw new NoSuchPlanException(planId); } - return instanceToInstanceId; + return activityToDirectiveId; } @Override - public MerlinService.MissionModelTypes getMissionModelTypes(final PlanId planId) + public MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final PlanId planId) throws IOException, MerlinServiceException { final var request = """ @@ -663,7 +662,7 @@ public MerlinService.MissionModelTypes getMissionModelTypes(final PlanId planId) .getJsonObject("mission_model") .getInt("id")); - return new MerlinService.MissionModelTypes(activityTypes, getResourceTypes(missionModelId)); + return new MerlinDatabaseService.MissionModelTypes(activityTypes, getResourceTypes(missionModelId)); } private static List parseActivityTypes(final JsonArray activityTypesJsonArray) { @@ -704,7 +703,7 @@ private static List parseActivityTypes(final JsonArray activityTyp } @Override - public MerlinService.MissionModelTypes getMissionModelTypes(final MissionModelId missionModelId) + public MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final MissionModelId missionModelId) throws IOException, NoSuchMissionModelException, MerlinServiceException { final var request = """ @@ -730,7 +729,7 @@ public MerlinService.MissionModelTypes getMissionModelTypes(final MissionModelId .getJsonArray("activity_types"); final var activityTypes = parseActivityTypes(activityTypesJsonArray); - return new MerlinService.MissionModelTypes(activityTypes, getResourceTypes(missionModelId)); + return new MerlinDatabaseService.MissionModelTypes(activityTypes, getResourceTypes(missionModelId)); } public Collection getResourceTypes(final MissionModelId missionModelId) @@ -803,11 +802,11 @@ public SimulationId getSimulationId(PlanId planId) throws MerlinServiceException } @Override - public DatasetId storeSimulationResults(final PlanMetadata planMetadata, - final SimulationResults results, - final Map simulationActivityDirectiveIdToMerlinActivityDirectiveId) throws - MerlinServiceException, IOException - { + public DatasetId storeSimulationResults( + final PlanMetadata planMetadata, + final SimulationResults results, + final Map uploadIdMap + ) throws MerlinServiceException, IOException { final var simulationId = getSimulationId(planMetadata.planId()); final var datasetIds = createSimulationDataset(simulationId, planMetadata); final var profileSet = ProfileSet.of(results.realProfiles, results.discreteProfiles); @@ -816,14 +815,14 @@ public DatasetId storeSimulationResults(final PlanMetadata planMetadata, profileSet.realProfiles(), profileSet.discreteProfiles()); postProfileSegments(datasetIds.datasetId(), profileRecords, profileSet); - postActivities(datasetIds.datasetId(), results.simulatedActivities, results.unfinishedActivities, results.startTime, simulationActivityDirectiveIdToMerlinActivityDirectiveId); + postActivities(datasetIds.datasetId(), results.simulatedActivities, results.unfinishedActivities, results.startTime, uploadIdMap); insertSimulationTopics(datasetIds.datasetId(), results.topics); insertSimulationEvents(datasetIds.datasetId(), results.events); setSimulationDatasetStatus(datasetIds.simulationDatasetId(), SimulationStateRecord.success()); return datasetIds.datasetId(); } - private Map getSimulatedActivities(SimulationDatasetId datasetId, Instant startSimulation) + private Map getSimulatedActivities(SimulationDatasetId datasetId, Instant startSimulation) throws MerlinServiceException, IOException, InvalidJsonException { final var request = """ @@ -887,7 +886,7 @@ private ProfileSet getProfilesWithSegments(DatasetId datasetId) throws MerlinSer return parseProfiles(data); } - private Map getSpans(DatasetId datasetId, Instant startTime) throws + private Map getSpans(DatasetId datasetId, Instant startTime) throws MerlinServiceException, IOException { final var request = """ query{ @@ -913,10 +912,10 @@ public Optional> getSimulationResults(PlanMet final var simulationDatasetId = getSuitableSimulationResults(planMetadata); if(simulationDatasetId.isEmpty()) return Optional.empty(); try(var executorService = Executors.newFixedThreadPool(3)) { - Future> futureSimulatedActivities = executorService.submit(() -> getSimulatedActivities( + Future> futureSimulatedActivities = executorService.submit(() -> getSimulatedActivities( simulationDatasetId.get().simulationDatasetId(), planMetadata.horizon().getStartInstant())); - Future> futureSpans = executorService.submit(() -> getSpans( + Future> futureSpans = executorService.submit(() -> getSpans( simulationDatasetId.get().datasetId(), planMetadata.horizon().getStartInstant())); Future futureProfiles = executorService.submit(() -> getProfilesWithSegments(simulationDatasetId.get().datasetId())); @@ -1013,18 +1012,18 @@ private Collection extractResourceTypes(final ProfileSet profileSe return resourceTypes; } - private Map parseUnfinishedActivities(JsonArray unfinishedActivitiesJson, Instant simulationStart){ - final var unfinishedActivities = new HashMap(); + private Map parseUnfinishedActivities(JsonArray unfinishedActivitiesJson, Instant simulationStart){ + final var unfinishedActivities = new HashMap(); for(final var unfinishedActivityJson: unfinishedActivitiesJson){ final var activityAttributes = activityAttributesP.parse(unfinishedActivityJson.asJsonObject().getJsonObject("attributes")).getSuccessOrThrow(); - SimulatedActivityId parentId = null; + ActivityInstanceId parentId = null; if(!unfinishedActivityJson.asJsonObject().isNull("parent_id")){ - parentId = new SimulatedActivityId(unfinishedActivityJson.asJsonObject().getJsonNumber("parent_id").longValue()); + parentId = new ActivityInstanceId(unfinishedActivityJson.asJsonObject().getJsonNumber("parent_id").longValue()); } final var activityType = unfinishedActivityJson.asJsonObject().getJsonString("type").getString(); final var start = instantFromStart(simulationStart, durationFromPGInterval(unfinishedActivityJson.asJsonObject().getJsonString("start_offset").getString())); - final var id = new SimulatedActivityId(unfinishedActivityJson.asJsonObject().getJsonNumber("id").longValue()); + final var id = new ActivityInstanceId(unfinishedActivityJson.asJsonObject().getJsonNumber("id").longValue()); Optional actDirectiveId = Optional.empty(); if(activityAttributes.directiveId().isPresent()){ actDirectiveId = Optional.of(new ActivityDirectiveId(activityAttributes.directiveId().get())); @@ -1126,18 +1125,18 @@ public ResourceProfile> parseProfile(JsonObject pr return ResourceProfile.of(type, segments); } - private Map parseSimulatedActivities(JsonArray simulatedActivitiesArray, Instant simulationStart) + private Map parseSimulatedActivities(JsonArray simulatedActivitiesArray, Instant simulationStart) throws InvalidJsonException { - final var simulatedActivities = new HashMap(); + final var simulatedActivities = new HashMap(); for(final var simulatedActivityJson: simulatedActivitiesArray) { //if no duration, this is an unfinished activity if(simulatedActivityJson.asJsonObject().isNull("duration")) continue; final var activityDuration = GraphQLParsers.durationP.parse(simulatedActivityJson.asJsonObject().get("duration")).getSuccessOrThrow(); final var activityId = simulatedActivityJson.asJsonObject().getJsonNumber("id").longValue(); - SimulatedActivityId parentId = null; + ActivityInstanceId parentId = null; if(!simulatedActivityJson.asJsonObject().isNull("parent_id")){ - parentId = new SimulatedActivityId(simulatedActivityJson.asJsonObject().getJsonNumber("parent_id").longValue()); + parentId = new ActivityInstanceId(simulatedActivityJson.asJsonObject().getJsonNumber("parent_id").longValue()); } final var startOffset = instantFromStart(simulationStart,durationFromPGInterval(simulatedActivityJson.asJsonObject().getString("start_offset"))); final var computedAttributes = serializedValueP.parse(simulatedActivityJson.asJsonObject().get("attributes")).getSuccessOrThrow(); @@ -1149,7 +1148,7 @@ private Map parseSimulatedActivities(Jso .parse(activityDirectiveArguments) .getSuccessOrThrow((reason) -> new InvalidJsonException(new InvalidEntityException(List.of(reason)))); final var activityType = activityDirective.getString("type"); - final var simulatedActivity = new SimulatedActivity( + final var simulatedActivity = new ActivityInstance( activityType, deserializedArguments, startOffset, @@ -1159,7 +1158,7 @@ private Map parseSimulatedActivities(Jso Optional.of(activityDirectiveId), computedAttributes ); - simulatedActivities.put(new SimulatedActivityId(activityId), simulatedActivity); + simulatedActivities.put(new ActivityInstanceId(activityId), simulatedActivity); } return simulatedActivities; } @@ -1543,25 +1542,27 @@ private JsonArrayBuilder batchInsertEventGraph( private void postActivities( final DatasetId datasetId, - final Map simulatedActivities, - final Map unfinishedActivities, + final Map simulatedActivities, + final Map unfinishedActivities, final Instant simulationStart, - final Map simulationActivityDirectiveIdToMerlinActivityDirectiveId + final Map uploadIdMap ) throws MerlinServiceException, IOException { final var simulatedActivityRecords = simulatedActivities.entrySet().stream() .collect(Collectors.toMap( e -> e.getKey().id(), - e -> simulatedActivityToRecord(e.getValue(), simulationActivityDirectiveIdToMerlinActivityDirectiveId))); + e -> simulatedActivityToRecord(e.getValue()))); final var allActivityRecords = unfinishedActivities.entrySet().stream() .collect(Collectors.toMap( e -> e.getKey().id(), - e -> unfinishedActivityToRecord(e.getValue(), simulationActivityDirectiveIdToMerlinActivityDirectiveId))); + e -> unfinishedActivityToRecord(e.getValue()))); allActivityRecords.putAll(simulatedActivityRecords); postSpans( datasetId, allActivityRecords, - simulationStart); + simulationStart, + uploadIdMap + ); updateSimulatedActivityParentsAction( datasetId, simulatedActivityRecords); @@ -1613,37 +1614,36 @@ public void updateSimulatedActivityParentsAction( } } - private static SpanRecord simulatedActivityToRecord(final SimulatedActivity activity, - final Map simulationActivityDirectiveIdToMerlinActivityDirectiveId) { + private static SpanRecord simulatedActivityToRecord(final ActivityInstance activity) { return new SpanRecord( activity.type(), activity.start(), Optional.of(activity.duration()), - Optional.ofNullable(activity.parentId()).map(SimulatedActivityId::id), - activity.childIds().stream().map(SimulatedActivityId::id).collect(Collectors.toList()), + Optional.ofNullable(activity.parentId()).map(ActivityInstanceId::id), + activity.childIds().stream().map(ActivityInstanceId::id).collect(Collectors.toList()), new ActivityAttributesRecord( - activity.directiveId().map(id -> simulationActivityDirectiveIdToMerlinActivityDirectiveId.get(id).id()), + activity.directiveId().map(ActivityDirectiveId::id), activity.arguments(), Optional.of(activity.computedAttributes()))); } - private static SpanRecord unfinishedActivityToRecord(final UnfinishedActivity activity, - final Map simulationActivityDirectiveIdToMerlinActivityDirectiveId) { + private static SpanRecord unfinishedActivityToRecord(final UnfinishedActivity activity) { return new SpanRecord( activity.type(), activity.start(), Optional.empty(), - Optional.ofNullable(activity.parentId()).map(SimulatedActivityId::id), - activity.childIds().stream().map(SimulatedActivityId::id).collect(Collectors.toList()), + Optional.ofNullable(activity.parentId()).map(ActivityInstanceId::id), + activity.childIds().stream().map(ActivityInstanceId::id).collect(Collectors.toList()), new ActivityAttributesRecord( - activity.directiveId().map(id -> simulationActivityDirectiveIdToMerlinActivityDirectiveId.get(id).id()), + activity.directiveId().map(ActivityDirectiveId::id), activity.arguments(), Optional.empty())); } public void postSpans(final DatasetId datasetId, final Map spans, - final Instant simulationStart + final Instant simulationStart, + final Map uploadIdMap ) throws MerlinServiceException, IOException { final var req = """ @@ -1667,7 +1667,11 @@ public void postSpans(final DatasetId datasetId, .add("start_offset", startTime.toString()) .add("duration", act.duration.isPresent() ? graphQLIntervalFromDuration(act.duration().get()).toString() : "null") .add("type", act.type()) - .add("attributes", buildAttributes(act.attributes().directiveId(), act.attributes().arguments(), act.attributes().computedAttributes())) + .add("attributes", buildAttributes( + act.attributes().directiveId().map($ -> uploadIdMap.get(new ActivityDirectiveId($)).id()), + act.attributes().arguments(), + act.attributes().computedAttributes() + )) .build()); } final var arguments = Json.createObjectBuilder() diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinService.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinDatabaseService.java similarity index 85% rename from scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinService.java rename to scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinDatabaseService.java index e2ec0db998..8120ce5d95 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinService.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinDatabaseService.java @@ -7,8 +7,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.Problem; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.server.exceptions.NoSuchActivityInstanceException; import gov.nasa.jpl.aerie.scheduler.server.exceptions.NoSuchMissionModelException; import gov.nasa.jpl.aerie.scheduler.server.exceptions.NoSuchPlanException; @@ -27,18 +26,17 @@ import java.io.IOException; import java.time.Instant; import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.Optional; -public interface MerlinService { +public interface MerlinDatabaseService { record MissionModelTypes(Collection activityTypes, Collection resourceTypes) {} interface ReaderRole { - MerlinService.MissionModelTypes getMissionModelTypes(final PlanId planId) + MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final PlanId planId) throws IOException, MerlinServiceException; - MerlinService.MissionModelTypes getMissionModelTypes(final MissionModelId missionModelId) + MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final MissionModelId missionModelId) throws IOException, MerlinServiceException, NoSuchMissionModelException; @@ -124,10 +122,10 @@ interface WriterRole { * @return the database id of the newly created aerie plan container * @throws NoSuchPlanException when the plan container could not be found in aerie after creation */ - Pair> createNewPlanWithActivityDirectives( + Pair> createNewPlanWithActivityDirectives( final PlanMetadata planMetadata, final Plan plan, - final Map activityToGoalId, + final Map activityToGoalId, final SchedulerModel schedulerModel ) throws IOException, NoSuchPlanException, MerlinServiceException; @@ -157,12 +155,11 @@ PlanId createEmptyPlan(final String name, final long modelId, final Instant star * @return * @throws NoSuchPlanException when the plan container does not exist in aerie */ - Map updatePlanActivityDirectives( + Map updatePlanActivityDirectives( PlanId planId, - Map idsFromInitialPlan, MerlinPlan initialPlan, Plan plan, - Map activityToGoalId, + Map activityToGoalId, SchedulerModel schedulerModel ) throws IOException, NoSuchPlanException, MerlinServiceException, NoSuchActivityInstanceException; @@ -170,11 +167,10 @@ Map updatePlanActivityDirectiv /** * update the list of SchedulingActivityDirectives with anchors, replacing the anchorIds generated by the * scheduler by the new ids generated by the database - * @param acts list of schedulingactivitydirectives with updated anchor ids * @throws MerlinServiceException * @throws IOException */ - void updatePlanActivityDirectiveAnchors(final PlanId planId, final List acts, final Map instancesToIds) + void updatePlanActivityDirectiveAnchors(final PlanId planId, final Plan plan, final Map uploadIdMap) throws MerlinServiceException, IOException; /** @@ -200,10 +196,10 @@ void clearPlanActivityDirectives(final PlanId planId) * @return * @throws NoSuchPlanException when the plan container does not exist in aerie */ - Map createAllPlanActivityDirectives( + Map createAllPlanActivityDirectives( final PlanId planId, final Plan plan, - final Map activityToGoalId, + final Map activityToGoalId, final SchedulerModel schedulerModel ) throws IOException, NoSuchPlanException, MerlinServiceException; @@ -213,14 +209,8 @@ Map createAllPlanActivityDirec * * @param planMetadata the plan metadata * @param results the simulation results - * @param simulationActivityDirectiveIdToMerlinActivityDirectiveId the translation between activity ids in the - * local simulation and the merlin activity ids - * @return - * @throws MerlinServiceException - * @throws IOException */ - DatasetId storeSimulationResults(final PlanMetadata planMetadata, final SimulationResults results, - final Map simulationActivityDirectiveIdToMerlinActivityDirectiveId) throws + DatasetId storeSimulationResults(final PlanMetadata planMetadata, final SimulationResults results, Map uploadIdMap) throws MerlinServiceException, IOException; } diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/TypescriptCodeGenerationService.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/TypescriptCodeGenerationService.java index ef0a02f61c..b18e0bf61c 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/TypescriptCodeGenerationService.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/TypescriptCodeGenerationService.java @@ -17,7 +17,7 @@ public final class TypescriptCodeGenerationService { private TypescriptCodeGenerationService() { } - public static String generateTypescriptTypesFromMissionModel(final MerlinService.MissionModelTypes missionModelTypes) { + public static String generateTypescriptTypesFromMissionModel(final MerlinDatabaseService.MissionModelTypes missionModelTypes) { final var activityTypeCodes = new ArrayList(); for (final var activityType : missionModelTypes.activityTypes()) { activityTypeCodes.add(getActivityTypeInformation(activityType)); diff --git a/scheduler-server/src/testFixtures/java/gov/nasa/jpl/aerie/scheduler/server/services/TypescriptCodeGenerationServiceTestFixtures.java b/scheduler-server/src/testFixtures/java/gov/nasa/jpl/aerie/scheduler/server/services/TypescriptCodeGenerationServiceTestFixtures.java index c64557a89a..e4688dd81b 100644 --- a/scheduler-server/src/testFixtures/java/gov/nasa/jpl/aerie/scheduler/server/services/TypescriptCodeGenerationServiceTestFixtures.java +++ b/scheduler-server/src/testFixtures/java/gov/nasa/jpl/aerie/scheduler/server/services/TypescriptCodeGenerationServiceTestFixtures.java @@ -10,8 +10,8 @@ public final class TypescriptCodeGenerationServiceTestFixtures { - public static final MerlinService.MissionModelTypes MISSION_MODEL_TYPES = - new MerlinService.MissionModelTypes( + public static final MerlinDatabaseService.MissionModelTypes MISSION_MODEL_TYPES = + new MerlinDatabaseService.MissionModelTypes( List.of( new ActivityType( "SampleActivity1", diff --git a/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/SchedulerWorkerAppDriver.java b/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/SchedulerWorkerAppDriver.java index 7ce8c8a618..9e1a35ef6e 100644 --- a/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/SchedulerWorkerAppDriver.java +++ b/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/SchedulerWorkerAppDriver.java @@ -17,7 +17,7 @@ import gov.nasa.jpl.aerie.scheduler.server.remotes.postgres.PostgresResultsCellRepository; import gov.nasa.jpl.aerie.scheduler.server.remotes.postgres.PostgresSpecificationRepository; import gov.nasa.jpl.aerie.scheduler.server.remotes.postgres.SpecificationRevisionData; -import gov.nasa.jpl.aerie.scheduler.server.services.GraphQLMerlinService; +import gov.nasa.jpl.aerie.scheduler.server.services.GraphQLMerlinDatabaseService; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleRequest; import gov.nasa.jpl.aerie.scheduler.server.services.SpecificationService; import gov.nasa.jpl.aerie.scheduler.server.services.UnexpectedSubtypeError; @@ -34,7 +34,7 @@ public final class SchedulerWorkerAppDriver { public static void main(String[] args) throws Exception { final var config = loadConfiguration(); - final var merlinService = new GraphQLMerlinService(config.merlinGraphqlURI(), config.hasuraGraphQlAdminSecret()); + final var merlinDatabaseService = new GraphQLMerlinDatabaseService(config.merlinGraphqlURI(), config.hasuraGraphQlAdminSecret()); final SchedulingDSLCompilationService schedulingDSLCompilationService; try { @@ -69,7 +69,7 @@ public static void main(String[] args) throws Exception { final var specificationService = new SpecificationService(stores.specifications()); final var scheduleAgent = new SynchronousSchedulerAgent(specificationService, - merlinService, + merlinDatabaseService, config.merlinFileStore(), config.missionRuleJarPath(), config.outputMode(), diff --git a/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationService.java b/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationService.java index c86f5f8c48..b53a6a9703 100644 --- a/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationService.java +++ b/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationService.java @@ -8,7 +8,7 @@ import gov.nasa.jpl.aerie.scheduler.server.models.SchedulingCompilationError; import gov.nasa.jpl.aerie.scheduler.server.models.SchedulingDSL; import gov.nasa.jpl.aerie.scheduler.server.services.ConstraintsTypescriptCodeGenerationHelper; -import gov.nasa.jpl.aerie.scheduler.server.services.MerlinService; +import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import gov.nasa.jpl.aerie.scheduler.server.services.MerlinServiceException; import gov.nasa.jpl.aerie.scheduler.server.services.TypescriptCodeGenerationService; @@ -51,13 +51,13 @@ public void close() { this.nodeProcess.destroy(); } - public SchedulingDSLCompilationResult compileGlobalSchedulingCondition(final MerlinService.ReaderRole merlinService, final PlanId planId, final String conditionTypescript, final + public SchedulingDSLCompilationResult compileGlobalSchedulingCondition(final MerlinDatabaseService.ReaderRole merlinDatabaseService, final PlanId planId, final String conditionTypescript, final Collection additionalResourceTypes) { try{ - final var missionModelTypes = merlinService.getMissionModelTypes(planId); + final var missionModelTypes = merlinDatabaseService.getMissionModelTypes(planId); final var aggregatedResourceTypes = new ArrayList<>(missionModelTypes.resourceTypes()); aggregatedResourceTypes.addAll(additionalResourceTypes); - final var planTypes = new MerlinService.MissionModelTypes(missionModelTypes.activityTypes(), aggregatedResourceTypes); + final var planTypes = new MerlinDatabaseService.MissionModelTypes(missionModelTypes.activityTypes(), aggregatedResourceTypes); return compile(planTypes, conditionTypescript, SchedulingDSL.conditionSpecifierP, "GlobalSchedulingCondition"); } catch (IOException | MerlinServiceException e) { throw new Error(e); @@ -65,26 +65,26 @@ public SchedulingDSLCompilationResult compileG } public SchedulingDSLCompilationResult compileSchedulingGoalDSL( - final MerlinService.ReaderRole merlinService, + final MerlinDatabaseService.ReaderRole merlinDatabaseService, final PlanId planId, final String goalTypescript){ - return compileSchedulingGoalDSL(merlinService, planId, goalTypescript, List.of()); + return compileSchedulingGoalDSL(merlinDatabaseService, planId, goalTypescript, List.of()); } /** * NOTE: This method is not re-entrant (assumes only one call to this method is running at any given time) */ public SchedulingDSLCompilationResult compileSchedulingGoalDSL( - final MerlinService.ReaderRole merlinService, + final MerlinDatabaseService.ReaderRole merlinDatabaseService, final PlanId planId, final String goalTypescript, final Collection additionalResourceTypes) { try { - final var missionModelTypes = merlinService.getMissionModelTypes(planId); + final var missionModelTypes = merlinDatabaseService.getMissionModelTypes(planId); final var aggregatedResourceTypes = new ArrayList<>(missionModelTypes.resourceTypes()); aggregatedResourceTypes.addAll(additionalResourceTypes); - final var augmentedMissionModelTypes = new MerlinService.MissionModelTypes(missionModelTypes.activityTypes(), aggregatedResourceTypes); + final var augmentedMissionModelTypes = new MerlinDatabaseService.MissionModelTypes(missionModelTypes.activityTypes(), aggregatedResourceTypes); return compile(augmentedMissionModelTypes, goalTypescript, SchedulingDSL.schedulingJsonP(augmentedMissionModelTypes), "Goal"); } catch (IOException | MerlinServiceException e) { throw new Error(e); @@ -92,7 +92,7 @@ public SchedulingDSLCompilationResult compileSchedu } private SchedulingDSLCompilationResult compile( - final MerlinService.MissionModelTypes missionModelTypes, + final MerlinDatabaseService.MissionModelTypes missionModelTypes, final String goalTypescript, final JsonParser parser, final String expectedReturnType) diff --git a/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SynchronousSchedulerAgent.java b/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SynchronousSchedulerAgent.java index 3ea1917c6e..dfc27ccaaa 100644 --- a/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SynchronousSchedulerAgent.java +++ b/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SynchronousSchedulerAgent.java @@ -38,8 +38,7 @@ import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.Problem; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.model.SchedulingCondition; import gov.nasa.jpl.aerie.scheduler.server.ResultsProtocol; import gov.nasa.jpl.aerie.scheduler.server.config.PlanOutputMode; @@ -62,7 +61,7 @@ import gov.nasa.jpl.aerie.scheduler.server.models.SchedulingDSL; import gov.nasa.jpl.aerie.scheduler.server.models.Specification; import gov.nasa.jpl.aerie.scheduler.server.remotes.postgres.GoalBuilder; -import gov.nasa.jpl.aerie.scheduler.server.services.MerlinService; +import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import gov.nasa.jpl.aerie.scheduler.server.services.MerlinServiceException; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleRequest; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleResults; @@ -70,19 +69,16 @@ import gov.nasa.jpl.aerie.scheduler.server.services.SpecificationService; import gov.nasa.jpl.aerie.scheduler.simulation.CheckpointSimulationFacade; import gov.nasa.jpl.aerie.scheduler.simulation.InMemoryCachedEngineStore; -import gov.nasa.jpl.aerie.scheduler.simulation.SimulationFacade; +import gov.nasa.jpl.aerie.scheduler.simulation.SimulationData; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; -import org.apache.commons.collections4.BidiMap; -import org.apache.commons.collections4.bidimap.DualHashBidiMap; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashSet; /** * agent that handles posed scheduling requests by blocking the requester thread until scheduling is complete * - * @param merlinService interface for querying plan and mission model details from merlin + * @param merlinDatabaseService interface for querying plan and mission model details from merlin * @param modelJarsDir path to parent directory for mission model jars (interim backdoor jar file access) * @param goalsJarPath path to jar file to load scheduling goals from (interim solution for user input goals) * @param outputMode how the scheduling output should be returned to aerie (eg overwrite or new container) @@ -90,7 +86,7 @@ //TODO: will eventually need scheduling goal service arg to pull goals from scheduler's own data store public record SynchronousSchedulerAgent( SpecificationService specificationService, - MerlinService.OwnerRole merlinService, + MerlinDatabaseService.OwnerRole merlinDatabaseService, Path modelJarsDir, Path goalsJarPath, PlanOutputMode outputMode, @@ -101,7 +97,7 @@ public record SynchronousSchedulerAgent( private static final Logger LOGGER = LoggerFactory.getLogger(SynchronousSchedulerAgent.class); public SynchronousSchedulerAgent { - Objects.requireNonNull(merlinService); + Objects.requireNonNull(merlinDatabaseService); Objects.requireNonNull(modelJarsDir); Objects.requireNonNull(goalsJarPath); Objects.requireNonNull(schedulingDSLCompilationService); @@ -112,9 +108,8 @@ public record SynchronousSchedulerAgent( * * consumes any ResultsProtocolFailure exception generated by the scheduling process and writes its message as a * failure reason to the given output port (eg aerie could not be reached, mission model could not be loaded from jar - * file, requested plan revision has changed in the database, scheduler could not find a solution, etc) - * - * any remaining exceptions passed upward represent fatal service configuration problems + * file, requested plan revision has changed in the database, scheduler could not find a solution, etc). + * Any remaining exceptions passed upward represent fatal service configuration problems */ @Override public void schedule( @@ -128,7 +123,7 @@ public void schedule( //TODO: maybe some kind of high level db transaction wrapping entire read/update of target plan revision final var specification = specificationService.getSpecification(request.specificationId()); - final var planMetadata = merlinService.getPlanMetadata(specification.planId()); + final var planMetadata = merlinDatabaseService.getPlanMetadata(specification.planId()); ensurePlanRevisionMatch(specification, planMetadata.planRev()); ensureRequestIsCurrent(specification, request); //create scheduler problem seeded with initial plan @@ -158,14 +153,14 @@ public void schedule( //seed the problem with the initial plan contents final var loadedPlanComponents = loadInitialPlan(planMetadata, problem, initialSimulationResultsAndDatasetId.map(Pair::getKey)); - problem.setInitialPlan(loadedPlanComponents.schedulerPlan(), initialSimulationResultsAndDatasetId.map(Pair::getKey), loadedPlanComponents.mapSchedulingIdsToActivityIds); + problem.setInitialPlan(loadedPlanComponents.schedulerPlan(), initialSimulationResultsAndDatasetId.map(Pair::getKey)); problem.setExternalProfile(externalProfiles.realProfiles(), externalProfiles.discreteProfiles()); //apply constraints/goals to the problem final var compiledGlobalSchedulingConditions = new ArrayList(); final var failedGlobalSchedulingConditions = new ArrayList>(); specification.schedulingConditions().forEach($ -> { final var result = schedulingDSLCompilationService.compileGlobalSchedulingCondition( - merlinService, + merlinDatabaseService, planMetadata.planId(), $.source().source(), externalProfiles.resourceTypes()); @@ -198,7 +193,7 @@ public void schedule( final var failedGoals = new ArrayList>>(); for (final var goalRecord : specification.goalsByPriority()) { final var result = compileGoalDefinition( - merlinService, + merlinDatabaseService, planMetadata.planId(), goalRecord.definition(), schedulingDSLCompilationService, @@ -238,38 +233,45 @@ public void schedule( final var solutionPlan = scheduler.getNextSolution().orElseThrow( () -> new ResultsProtocolFailure("scheduler returned no solution")); - final var activityToGoalId = new HashMap(); - for (final var entry : solutionPlan.getEvaluation().getGoalEvaluations().entrySet()) { - for (final var activity : entry.getValue().getInsertedActivities()) { - activityToGoalId.put(activity, goals.get(entry.getKey())); - } + final var activityToGoalId = new HashMap(); + for (final var entry : solutionPlan.getEvaluation().getGoalEvaluations().entrySet()) { + for (final var activity : entry.getValue().getInsertedActivities()) { + activityToGoalId.put(activity, goals.get(entry.getKey())); } - //store the solution plan back into merlin (and reconfirm no intervening mods!) - //TODO: make revision confirmation atomic part of plan mutation (plan might have been modified during scheduling!) - ensurePlanRevisionMatch(specification, getMerlinPlanRev(specification.planId())); - final var instancesToIds = storeFinalPlan( - planMetadata, - loadedPlanComponents.idMap(), - loadedPlanComponents.merlinPlan(), - solutionPlan, - activityToGoalId, - schedulerMissionModel.schedulerModel() - ); - List updatedActs = updateEverythingWithNewAnchorIds(solutionPlan, instancesToIds); - merlinService.updatePlanActivityDirectiveAnchors(specification.planId(), updatedActs, instancesToIds); + } + //store the solution plan back into merlin (and reconfirm no intervening mods!) + //TODO: make revision confirmation atomic part of plan mutation (plan might have been modified during scheduling!) + ensurePlanRevisionMatch(specification, getMerlinPlanRev(specification.planId())); + final var uploadIdMap = storeFinalPlan( + planMetadata, + loadedPlanComponents.merlinPlan(), + solutionPlan, + activityToGoalId, + schedulerMissionModel.schedulerModel() + ); - final var planMetadataAfterChanges = merlinService.getPlanMetadata(specification.planId()); + final var planMetadataAfterChanges = merlinDatabaseService.getPlanMetadata(specification.planId()); Optional datasetId = initialSimulationResultsAndDatasetId.map(Pair::getRight); - if(planMetadataAfterChanges.planRev() != specification.planRevision()) { + final var lastGoalSimulateAfter = !problem.getGoals().isEmpty() && problem.getGoals().getLast().simulateAfter; + if(lastGoalSimulateAfter && planMetadataAfterChanges.planRev() != specification.planRevision()) { datasetId = storeSimulationResults( - solutionPlan, - planningHorizon, - simulationFacade, + simulationFacade.simulateWithResults(solutionPlan, planningHorizon.getEndAerie()), + planMetadataAfterChanges, + uploadIdMap + ); + } else if (simulationFacade.getLatestSimulationData().isPresent() && simulationFacade.getLatestSimulationData() != problem.getInitialSimulationResults()) { + final var latest = simulationFacade.getLatestSimulationData().get(); + datasetId = storeSimulationResults( + latest, planMetadataAfterChanges, - instancesToIds); + uploadIdMap + ); } + + merlinDatabaseService.updatePlanActivityDirectiveAnchors(specification.planId(), solutionPlan, uploadIdMap); + //collect results and notify subscribers of success - final var results = collectResults(solutionPlan, instancesToIds, goals); + final var results = collectResults(solutionPlan, uploadIdMap, goals); LOGGER.info("Simulation cache saved " + cachedEngineStore.getTotalSavedSimulationTime() + " in simulation time"); writer.succeedWith(results, datasetId); } catch (final SpecificationLoadException e) { @@ -315,27 +317,9 @@ public void schedule( } } - public List updateEverythingWithNewAnchorIds(Plan solutionPlan, Map instancesToIds){ - final var updatedActs = new ArrayList(); - final var planActs = new HashSet<>(solutionPlan.getActivities()); - for (final var act : planActs) { - if (act.anchorId() != null) { - final var actAnchored = solutionPlan.getActivitiesById().get(act.anchorId()); - final var updatedAct = SchedulingActivityDirective.copyOf(act, new SchedulingActivityDirectiveId(instancesToIds.get(actAnchored).id()), act.anchoredToStart(), act.startOffset()); - updatedActs.add(updatedAct); - solutionPlan.replaceActivity(act, updatedAct); - final var value = instancesToIds.get(act); - instancesToIds.remove(act); - instancesToIds.put(updatedAct, value); - } - } - return updatedActs; - } - - private Optional> loadSimulationResults(final PlanMetadata planMetadata){ try { - return merlinService.getSimulationResults(planMetadata); + return merlinDatabaseService.getSimulationResults(planMetadata); } catch (MerlinServiceException | IOException | InvalidJsonException e) { throw new ResultsProtocolFailure(e); } @@ -344,52 +328,27 @@ private Optional> loadSimulationResults(final private ExternalProfiles loadExternalProfiles(final PlanId planId) throws MerlinServiceException, IOException { - return merlinService.getExternalProfiles(planId); + return merlinDatabaseService.getExternalProfiles(planId); } private Optional storeSimulationResults( - final Plan plan, - PlanningHorizon planningHorizon, - SimulationFacade simulationFacade, + SimulationData simulationData, PlanMetadata planMetadata, - final Map schedDirectiveToMerlinId) - throws MerlinServiceException, IOException, SchedulingInterruptedException - { - //finish simulation until end of horizon before posting results - try { - final var simulationData = simulationFacade.simulateWithResults(plan, planningHorizon.getEndAerie()); - final var schedID_to_MerlinID = - schedDirectiveToMerlinId.entrySet().stream() - .collect(Collectors.toMap( - (a) -> new SchedulingActivityDirectiveId(a.getKey().id().id()), Map.Entry::getValue)); - final var schedID_to_simID = - simulationData.mapSchedulingIdsToActivityIds().get(); - final var simID_to_MerlinID = - schedID_to_simID.entrySet().stream().collect(Collectors.toMap( - Map.Entry::getValue, - (a) -> schedID_to_MerlinID.get(a.getKey()))); - if(simID_to_MerlinID.values().containsAll(schedDirectiveToMerlinId.values()) && schedDirectiveToMerlinId.values().containsAll(simID_to_MerlinID.values())){ - return Optional.of(merlinService.storeSimulationResults(planMetadata, - simulationData.driverResults(), - simID_to_MerlinID)); - } else{ - //schedule in simulation is inconsistent with current state of the plan (user probably disabled simulation for some of the goals) - return Optional.empty(); - } - } catch (SimulationFacade.SimulationException e) { - throw new RuntimeException("Error while running simulation before storing simulation results after scheduling", e); - } + Map uploadIdMap + ) + throws MerlinServiceException, IOException, SchedulingInterruptedException { + return Optional.of(merlinDatabaseService.storeSimulationResults(planMetadata, simulationData.driverResults(), uploadIdMap)); } private static SchedulingDSLCompilationService.SchedulingDSLCompilationResult compileGoalDefinition( - final MerlinService.ReaderRole merlinService, + final MerlinDatabaseService.ReaderRole merlinDatabaseService, final PlanId planId, final GoalSource goalDefinition, final SchedulingDSLCompilationService schedulingDSLCompilationService, final Collection additionalResourceTypes) { return schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, planId, goalDefinition.source(), additionalResourceTypes @@ -412,7 +371,7 @@ private void ensurePlanRevisionMatch(final Specification specification, final lo private long getMerlinPlanRev(final PlanId planId) throws MerlinServiceException, NoSuchPlanException, IOException { - return merlinService.getPlanRevision(planId); + return merlinDatabaseService.getPlanRevision(planId); } /** @@ -446,13 +405,12 @@ private PlanComponents loadInitialPlan( final Optional initialSimulationResults) { //TODO: maybe paranoid check if plan rev has changed since original metadata? try { - final BidiMap mapSchedulingIdsToActivityIds = new DualHashBidiMap(); - final var merlinPlan = merlinService.getPlanActivityDirectives(planMetadata, problem); - final Map schedulingIdToDirectiveId = new HashMap<>(); + final var merlinPlan = merlinDatabaseService.getPlanActivityDirectives(planMetadata, problem); final var plan = new PlanInMemory(); final var activityTypes = problem.getActivityTypes().stream().collect(Collectors.toMap(ActivityType::getName, at -> at)); for(final var elem : merlinPlan.getActivitiesById().entrySet()){ final var activity = elem.getValue(); + final var id = elem.getKey(); if(!activityTypes.containsKey(activity.serializedActivity().getTypeName())){ throw new IllegalArgumentException("Activity type found in JSON object after request to merlin server has " + "not been found in types extracted from mission model. Probable " @@ -461,46 +419,41 @@ private PlanComponents loadInitialPlan( } final var schedulerActType = activityTypes.get(activity.serializedActivity().getTypeName()); Duration actDuration = null; - if (schedulerActType.getDurationType() instanceof DurationType.Controllable s) { - final var serializedDuration = activity.serializedActivity().getArguments().get(s.parameterName()); - if (serializedDuration != null) { - actDuration = problem.getSchedulerModel().deserializeDuration(serializedDuration); + switch (schedulerActType.getDurationType()) { + case DurationType.Controllable s -> { + final var serializedDuration = activity.serializedActivity().getArguments().get(s.parameterName()); + if (serializedDuration != null) { + actDuration = problem.getSchedulerModel().deserializeDuration(serializedDuration); + } } - } else if (schedulerActType.getDurationType() instanceof DurationType.Fixed fixedDurationType) { - actDuration = fixedDurationType.duration(); - } else if(schedulerActType.getDurationType() instanceof DurationType.Parametric parametricDurationType) { - actDuration = parametricDurationType.durationFunction().apply(activity.serializedActivity().getArguments()); - } else if(schedulerActType.getDurationType() instanceof DurationType.Uncontrollable) { - if(initialSimulationResults.isPresent()){ - for(final var simAct: initialSimulationResults.get().simulatedActivities.entrySet()){ - if(simAct.getValue().directiveId().isPresent() && - simAct.getValue().directiveId().get().equals(elem.getKey())){ - actDuration = simAct.getValue().duration(); + case DurationType.Fixed fixedDurationType -> actDuration = fixedDurationType.duration(); + case DurationType.Parametric parametricDurationType -> + actDuration = parametricDurationType.durationFunction().apply(activity + .serializedActivity() + .getArguments()); + case DurationType.Uncontrollable ignored -> { + if (initialSimulationResults.isPresent()) { + for (final var simAct : initialSimulationResults.get().simulatedActivities.entrySet()) { + if (simAct.getValue().directiveId().isPresent() && + simAct.getValue().directiveId().get().equals(id)) { + actDuration = simAct.getValue().duration(); + } } } } - } else { - throw new Error("Unhandled variant of DurationType:" + schedulerActType.getDurationType()); + case null, default -> throw new Error("Unhandled variant of DurationType:" + + schedulerActType.getDurationType()); } - final var act = SchedulingActivityDirective.fromActivityDirective(elem.getKey(), activity, schedulerActType, actDuration); - schedulingIdToDirectiveId.put(act.getId(), elem.getKey()); + final var act = SchedulingActivity.fromExistingActivityDirective(id, activity, schedulerActType, actDuration); plan.add(act); - if(initialSimulationResults.isPresent()){ - for(final var simAct: initialSimulationResults.get().simulatedActivities.entrySet()){ - if(simAct.getValue().directiveId().isPresent() && - simAct.getValue().directiveId().get().equals(elem.getKey())){ - mapSchedulingIdsToActivityIds.put(act.getId(), new ActivityDirectiveId(simAct.getKey().id())); - } - } - } } - return new PlanComponents(plan, mapSchedulingIdsToActivityIds, merlinPlan, schedulingIdToDirectiveId); + return new PlanComponents(plan, merlinPlan); } catch (Exception e) { throw new ResultsProtocolFailure(e); } } - record PlanComponents(Plan schedulerPlan, BidiMap mapSchedulingIdsToActivityIds, MerlinPlan merlinPlan, Map idMap) {} + record PlanComponents(Plan schedulerPlan, MerlinPlan merlinPlan) {} record SchedulerMissionModel(MissionModel missionModel, SchedulerModel schedulerModel) {} /** @@ -610,23 +563,22 @@ private SchedulerModelLoadException(final Path path, final String name, final St * @throws ResultsProtocolFailure when the plan could not be stored to aerie, the target plan revision has * changed, or aerie could not be reached */ - private Map storeFinalPlan( + private Map storeFinalPlan( final PlanMetadata planMetadata, - final Map idsFromInitialPlan, final MerlinPlan initialPlan, final Plan newPlan, - final Map goalToActivity, + final Map goalToActivity, final SchedulerModel schedulerModel ) { try { switch (this.outputMode) { case CreateNewOutputPlan -> { - return merlinService.createNewPlanWithActivityDirectives(planMetadata, newPlan, goalToActivity, schedulerModel).getValue(); + return merlinDatabaseService + .createNewPlanWithActivityDirectives(planMetadata, newPlan, goalToActivity, schedulerModel).getValue(); } case UpdateInputPlanWithNewActivities -> { - return merlinService.updatePlanActivityDirectives( + return merlinDatabaseService.updatePlanActivityDirectives( planMetadata.planId(), - idsFromInitialPlan, initialPlan, newPlan, goalToActivity, @@ -648,7 +600,7 @@ public static List conditionBuilder(SchedulingDSL.Condition } else if(conditionSpecifier instanceof SchedulingDSL.ConditionSpecifier.GlobalSchedulingCondition globalSchedulingCondition){ return List.of(new SchedulingCondition( globalSchedulingCondition.expression(), - globalSchedulingCondition.activityTypes().stream().map((activityExpression -> problem.getActivityType(activityExpression))).toList())); + globalSchedulingCondition.activityTypes().stream().map((problem::getActivityType)).toList())); } throw new Error("Unhandled variant of %s: %s".formatted(SchedulingDSL.ConditionSpecifier.class.getSimpleName(), conditionSpecifier)); } @@ -663,30 +615,27 @@ public static List conditionBuilder(SchedulingDSL.Condition * @param plan the target plan after the scheduling run has completed * @return summary of the state of the plan after scheduling ran; eg goal success metrics, associated instances, etc */ - private ScheduleResults collectResults(final Plan plan, final Map instancesToIds, Map goalsToIds) { + private ScheduleResults collectResults(final Plan plan, Map uploadIdMap, Map goalsToIds) { Map goalResults = new HashMap<>(); for (var goalEval : plan.getEvaluation().getGoalEvaluations().entrySet()) { var goalId = goalsToIds.get(goalEval.getKey()); //goal could be anonymous, a subgoal of a composite goal for example, and thus have no meaning for results sent back - final var activitiesById = plan.getActivitiesById(); if(goalId != null) { final var goalResult = new ScheduleResults.GoalResult( goalEval .getValue() .getInsertedActivities().stream() - .map(activityInstance -> instancesToIds.get( - activityInstance.getParentActivity() - .map(activitiesById::get) - .orElse(activityInstance)) - ).toList(), + .map(SchedulingActivity::id) + .filter(Objects::nonNull) + .map(uploadIdMap::get) + .toList(), goalEval .getValue() .getAssociatedActivities().stream() - .map(activityInstance -> instancesToIds.get( - activityInstance.getParentActivity() - .map(activitiesById::get) - .orElse(activityInstance)) - ).toList(), + .map(SchedulingActivity::id) + .filter(Objects::nonNull) + .map(uploadIdMap::get) + .toList(), goalEval.getValue().getScore() >= 0); goalResults.put(goalId, goalResult); } diff --git a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinService.java b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinDatabaseService.java similarity index 78% rename from scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinService.java rename to scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinDatabaseService.java index 4ba9057b68..aead83f693 100644 --- a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinService.java +++ b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinDatabaseService.java @@ -11,8 +11,7 @@ import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.Problem; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirective; -import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivityDirectiveId; +import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.server.models.DatasetId; import gov.nasa.jpl.aerie.scheduler.server.models.ExternalProfiles; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; @@ -21,11 +20,9 @@ import gov.nasa.jpl.aerie.scheduler.server.models.PlanId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanMetadata; import gov.nasa.jpl.aerie.scheduler.server.models.ResourceType; -import gov.nasa.jpl.aerie.scheduler.server.services.MerlinService; -import gov.nasa.jpl.aerie.scheduler.server.services.MerlinServiceException; +import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import org.apache.commons.lang3.tuple.Pair; -import java.io.IOException; import java.nio.file.Path; import java.time.Instant; import java.util.ArrayList; @@ -35,7 +32,7 @@ import java.util.Map; import java.util.Optional; -class MockMerlinService implements MerlinService.OwnerRole { +class MockMerlinDatabaseService implements MerlinDatabaseService.OwnerRole { private Optional planningHorizon; private ExternalProfiles externalProfiles = new ExternalProfiles(Map.of(), Map.of(), List.of()); @@ -44,14 +41,14 @@ public void setExternalDataset(ExternalProfiles externalProfiles) { this.externalProfiles = externalProfiles; } - record MissionModelInfo(Path libPath, Path modelPath, String modelName, MerlinService.MissionModelTypes types, Map config) {} + record MissionModelInfo(Path libPath, Path modelPath, String modelName, MerlinDatabaseService.MissionModelTypes types, Map config) {} private Optional missionModelInfo = Optional.empty(); private MerlinPlan initialPlan; Collection updatedPlan; Plan plan; - MockMerlinService() { + MockMerlinDatabaseService() { this.initialPlan = new MerlinPlan(); this.planningHorizon = Optional.of(new PlanningHorizon( TimeUtility.fromDOY("2021-001T00:00:00"), @@ -106,10 +103,10 @@ public MerlinPlan getPlanActivityDirectives(final PlanMetadata planMetadata, fin } @Override - public Pair> createNewPlanWithActivityDirectives( + public Pair> createNewPlanWithActivityDirectives( final PlanMetadata planMetadata, final Plan plan, - final Map activityToGoal, + final Map activityToGoal, final SchedulerModel schedulerModel ) { @@ -123,27 +120,26 @@ public PlanId createEmptyPlan(final String name, final long modelId, final Insta } @Override - public Map updatePlanActivityDirectives( + public Map updatePlanActivityDirectives( final PlanId planId, - final Map idsFromInitialPlan, final MerlinPlan initialPlan, final Plan plan, - final Map activityToGoal, + final Map activityToGoal, final SchedulerModel schedulerModel ) { this.updatedPlan = extractActivityDirectives(plan, schedulerModel); this.plan = plan; - final var res = new HashMap(); + final var res = new HashMap(); for (final var activity : plan.getActivities()) { - res.put(activity, new ActivityDirectiveId(activity.id().id())); + res.put(activity.id(), activity.id()); } return res; } @Override - public void updatePlanActivityDirectiveAnchors(final PlanId planId, final List acts, final Map instancesToIds) - throws MerlinServiceException, IOException {} + public void updatePlanActivityDirectiveAnchors(final PlanId planId, final Plan plan, final Map uploadIdMap) + {} @Override public void ensurePlanExists(final PlanId planId) { @@ -174,10 +170,10 @@ public void clearPlanActivityDirectives(final PlanId planId) } @Override - public Map createAllPlanActivityDirectives( + public Map createAllPlanActivityDirectives( final PlanId planId, final Plan plan, - final Map activityToGoalId, + final Map activityToGoalId, final SchedulerModel schedulerModel ) { @@ -188,20 +184,20 @@ public Map createAllPlanActivi public DatasetId storeSimulationResults( final PlanMetadata planMetadata, final SimulationResults results, - final Map activityIdCorrespondance) - { + final Map uploadIdMap + ) { return new DatasetId(0); } @Override - public MerlinService.MissionModelTypes getMissionModelTypes(final PlanId planId) + public MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final PlanId planId) { if (this.missionModelInfo.isEmpty()) throw new RuntimeException("Make sure to call setMissionModel before running a test"); return this.missionModelInfo.get().types(); } @Override - public MerlinService.MissionModelTypes getMissionModelTypes(final MissionModelId missionModelId) + public MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final MissionModelId missionModelId) { if (this.missionModelInfo.isEmpty()) throw new RuntimeException("Make sure to call setMissionModel before running a test"); return this.missionModelInfo.get().types(); @@ -225,7 +221,7 @@ private static Collection extractActivityDirectives(final Pla activity.startOffset(), activity.getType().getName(), arguments, - (activity.anchorId() != null ? new ActivityDirectiveId(-activity.anchorId().id()) : null), + activity.anchorId(), activity.anchoredToStart())); } return activityDirectives; diff --git a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationServiceTests.java b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationServiceTests.java index 830ab890ad..2abe597293 100644 --- a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationServiceTests.java +++ b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationServiceTests.java @@ -40,7 +40,7 @@ import gov.nasa.jpl.aerie.scheduler.server.models.PlanMetadata; import gov.nasa.jpl.aerie.scheduler.server.models.ResourceType; import gov.nasa.jpl.aerie.scheduler.server.models.SchedulingDSL; -import gov.nasa.jpl.aerie.scheduler.server.services.MerlinService; +import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import gov.nasa.jpl.aerie.scheduler.server.services.MerlinServiceException; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.AfterAll; @@ -65,15 +65,15 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) class SchedulingDSLCompilationServiceTests { private static final PlanId PLAN_ID = new PlanId(1L); - private static final MerlinService.ReaderRole merlinService = new MerlinService.ReaderRole() { + private static final MerlinDatabaseService.ReaderRole merlinDatabaseService = new MerlinDatabaseService.ReaderRole() { @Override - public MerlinService.MissionModelTypes getMissionModelTypes(final PlanId missionModelId) + public MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final PlanId missionModelId) { return MISSION_MODEL_TYPES; } @Override - public MerlinService.MissionModelTypes getMissionModelTypes(final MissionModelId missionModelId) + public MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final MissionModelId missionModelId) { return MISSION_MODEL_TYPES; } @@ -137,7 +137,7 @@ void tearDown() { void testSchedulingDSL_mutex() { final var result = schedulingDSLCompilationService.compileGlobalSchedulingCondition( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myCondition() { return GlobalSchedulingCondition.mutex([ActivityTypes.SampleActivity2], [ActivityTypes.SampleActivity1]) @@ -222,7 +222,7 @@ private static StructExpressionAt getSampleActivity3PresetParameters() { void testSchedulingDSL_basic() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -254,7 +254,7 @@ export default function myGoal() { void testSchedulingDSL_recurrence_activityFinder() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -289,7 +289,7 @@ export default function myGoal() { void testSchedulingDSL_partial() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -321,7 +321,7 @@ export default function myGoal() { void testSchedulingDSL_helper_function() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return myHelper(ActivityTemplates.SampleActivity1({ @@ -356,7 +356,7 @@ function myHelper(activityTemplate) { void testSchedulingDSL_variable_not_defined() { final SchedulingDSLCompilationService.SchedulingDSLCompilationResult.Error actualErrors; actualErrors = (SchedulingDSLCompilationService.SchedulingDSLCompilationResult.Error) schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { const x = 4 - 2 @@ -384,7 +384,7 @@ function myHelper(activityTemplate) { void testSchedulingDSL_applyWhen() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -423,7 +423,7 @@ export default function myGoal() { void testSchedulingDSL_wrong_return_type() { final SchedulingDSLCompilationService.SchedulingDSLCompilationResult.Error actualErrors; actualErrors = (SchedulingDSLCompilationService.SchedulingDSLCompilationResult.Error) schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return 5 @@ -440,7 +440,7 @@ export default function myGoal() { void testSchedulingDSL_temporal() { final SchedulingDSLCompilationService.SchedulingDSLCompilationResult result; result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default () => Goal.ActivityRecurrenceGoal({ @@ -473,7 +473,7 @@ export default () => Goal.ActivityRecurrenceGoal({ void testHugeGoal() { // This test is intended to create a Goal that is bigger than the node subprocess's standard input buffer final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -505,7 +505,7 @@ export default function myGoal() { @Test void testCoexistenceGoalActivityExpression() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function() { return Goal.CoexistenceGoal({ @@ -545,7 +545,7 @@ export default function() { @Test void testCoexistenceGoalFlexibleTimingConstraint() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function() { return Goal.CoexistenceGoal({ @@ -590,7 +590,7 @@ export default function() { @Test void testCoexistenceGoalActivityFinder() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function() { return Goal.CoexistenceGoal({ @@ -633,7 +633,7 @@ export default function() { @Test void testCoexistenceGoalParameterReference() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function() { return Goal.CoexistenceGoal({ @@ -681,7 +681,7 @@ export default function() { @Test void testCoexistenceGoalParameterReferenceValueAt() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function() { return Goal.CoexistenceGoal({ @@ -729,7 +729,7 @@ export default function() { @Test void strictTypeCheckingTest_astNode() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ interface FakeGoal { @@ -762,7 +762,7 @@ export default function() { @Test void strictTypeCheckingTest_transition() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function() { @@ -791,7 +791,7 @@ export default function() { void testSchedulingDSL_emptyActivityCorrect() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -820,7 +820,7 @@ export default function myGoal() { void testSchedulingDSL_emptyActivityBogus() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -844,7 +844,7 @@ else if (result instanceof SchedulingDSLCompilationService.SchedulingDSLCompilat @Test void testCoexistenceGoalStateConstraint() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ const micro = (m: number) => Temporal.Duration.from({microseconds: m}); @@ -885,7 +885,7 @@ export default function() { @Test void testCoexistenceGoalReferenceWindowDuration() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ const micro = (m: number) => Temporal.Duration.from({microseconds: m}); @@ -926,7 +926,7 @@ export default function() { @Test void testWindowsExpression() { final var result = schedulingDSLCompilationService.compileGlobalSchedulingCondition( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function() { @@ -950,7 +950,7 @@ export default function() { @Test void testAndGoal(){ final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -995,7 +995,7 @@ export default function myGoal() { @Test void testOrGoal(){ final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default function myGoal() { return Goal.ActivityRecurrenceGoal({ @@ -1040,7 +1040,7 @@ export default function myGoal() { @Test void testActivityPreset() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default (): Goal => { return Goal.ActivityRecurrenceGoal({ @@ -1068,7 +1068,7 @@ export default (): Goal => { void testSchedulingDSLMutatingPreset() { final var result1 = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default (): Goal => { let preset = ActivityPresets.SampleActivity2["my preset"]; @@ -1094,7 +1094,7 @@ export default (): Goal => { } final var result2 = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default (): Goal => { let preset = { @@ -1127,7 +1127,7 @@ export default (): Goal => { @Test void testPresetWithEnum() { final var result = schedulingDSLCompilationService.compileSchedulingGoalDSL( - merlinService, + merlinDatabaseService, PLAN_ID, """ export default (): Goal => { return Goal.ActivityRecurrenceGoal({ diff --git a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingIntegrationTests.java b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingIntegrationTests.java index 9a7dcc7d34..482d514969 100644 --- a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingIntegrationTests.java +++ b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingIntegrationTests.java @@ -12,6 +12,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -52,7 +53,7 @@ import gov.nasa.jpl.aerie.scheduler.server.models.SpecificationId; import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; import gov.nasa.jpl.aerie.scheduler.server.remotes.postgres.SpecificationRevisionData; -import gov.nasa.jpl.aerie.scheduler.server.services.MerlinService; +import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleRequest; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleResults; import gov.nasa.jpl.aerie.scheduler.model.Plan; @@ -641,7 +642,7 @@ export default () => Goal.CoexistenceGoal({ var foundSatisfactionAct = false; for (final var activity : goalResult.satisfyingActivities()) { assertNotNull(activity); - final var element = results.idToAct.get(new ActivityDirectiveId(-activity.id())); + final var element = results.idToAct.get(new ActivityDirectiveId(activity.id())); if(element != null && element.equals(expectedSatisfactionAct)){ foundSatisfactionAct = true; } @@ -712,7 +713,7 @@ export default () => Goal.ActivityRecurrenceGoal({ var foundFirst = false; var foundSecond = false; for(final var satisfyingActivity: goalResult.satisfyingActivities()){ - final var element = results.idToAct.get(new ActivityDirectiveId(-satisfyingActivity.id())); + final var element = results.idToAct.get(new ActivityDirectiveId(satisfyingActivity.id())); if(element != null && element.equals(expectedMatch1)){ foundFirst = true; } @@ -2084,10 +2085,10 @@ export default () => Goal.ActivityRecurrenceGoal({ return result; } - private static MockMerlinService.MissionModelInfo getMissionModelInfo(final MissionModelDescription desc) { + private static MockMerlinDatabaseService.MissionModelInfo getMissionModelInfo(final MissionModelDescription desc) { final var jarFile = getLatestJarFile(desc.libPath()); try { - return new MockMerlinService.MissionModelInfo( + return new MockMerlinDatabaseService.MissionModelInfo( desc.libPath(), Path.of(jarFile.getName()), desc.name(), @@ -2187,7 +2188,7 @@ private SchedulingRunResults runScheduler( final Optional externalProfiles, final int cachedEngineStoreCapacity ) { - final var mockMerlinService = new MockMerlinService(); + final var mockMerlinService = new MockMerlinDatabaseService(); mockMerlinService.setMissionModel(getMissionModelInfo(desc)); mockMerlinService.setInitialPlan(plannedActivities); mockMerlinService.setPlanningHorizon(planningHorizon); @@ -2239,7 +2240,7 @@ record SchedulingRunResults( Plan plan, Map idToAct) {} - static MerlinService.MissionModelTypes loadMissionModelTypesFromJar( + static MerlinDatabaseService.MissionModelTypes loadMissionModelTypesFromJar( final String jarPath, final Map configuration) throws MissionModelLoader.MissionModelLoadException @@ -2273,7 +2274,7 @@ static MerlinService.MissionModelTypes loadMissionModelTypesFromJar( resourceTypes.add(new ResourceType(name, resource.getOutputType().getSchema())); } - return new MerlinService.MissionModelTypes(activityTypes, resourceTypes); + return new MerlinDatabaseService.MissionModelTypes(activityTypes, resourceTypes); } @Test @@ -2504,7 +2505,7 @@ export default function myGoal() { planningHorizon); final var planByActivityType = partitionByActivityType(results.updatedPlan()); final var parentActs = planByActivityType.get("parent"); - final var childActs = planByActivityType.get("child").stream().map((bb) -> bb.startOffset()).toList(); + final var childActs = planByActivityType.get("child").stream().map(ActivityDirective::startOffset).toList(); //goal should be satisfied assertTrue(results.scheduleResults.goalResults().entrySet().iterator().next().getValue().satisfied()); //ensure no new child activity has been inserted @@ -3196,18 +3197,22 @@ export default () => Goal.CoexistenceGoal({ final var planByActivityType = partitionByActivityType(results.updatedPlan()); final var growBananas = planByActivityType.get("GrowBanana"); - final var gbIterator = growBananas.iterator(); assertNull(planByActivityType.get("PeelBanana")); assertEquals(2, growBananas.size()); - final var growBanana1 = gbIterator.next(); - assertEquals(Duration.of(-10, MINUTES), growBanana1.startOffset()); - assertEquals(SerializedValue.of(1), growBanana1.serializedActivity().getArguments().get("quantity")); - - final var growBanana2 = gbIterator.next(); - assertEquals(Duration.of(10, MINUTES), growBanana2.startOffset()); - assertEquals(SerializedValue.of(2), growBanana2.serializedActivity().getArguments().get("quantity")); + assertTrue( + growBananas.stream().anyMatch( + $ -> Objects.equals($.startOffset(), Duration.of(-10, MINUTES)) + && SerializedValue.of(1).equals($.serializedActivity().getArguments().get("quantity")) + ) + ); + assertTrue( + growBananas.stream().anyMatch( + $ -> Objects.equals($.startOffset(), Duration.of(10, MINUTES)) + && SerializedValue.of(2).equals($.serializedActivity().getArguments().get("quantity")) + ) + ); } /**