diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/Resources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/Resources.java index 087815118a..c0e72fcea0 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/Resources.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/Resources.java @@ -1,11 +1,13 @@ package gov.nasa.jpl.aerie.contrib.streamline.core; import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.InstantClock; import gov.nasa.jpl.aerie.merlin.framework.Condition; import gov.nasa.jpl.aerie.merlin.framework.Scoped; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.Unit; +import java.time.Instant; import java.util.Collection; import java.util.Objects; import java.util.Optional; @@ -20,6 +22,7 @@ import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Dependencies.addDependency; import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Naming.*; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock.clock; +import static gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.InstantClockResources.addToInstant; import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.*; import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.ZERO; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete.discrete; @@ -38,22 +41,26 @@ private Resources() {} * This method is idempotent; calling it multiple times is the same as calling it once. *

*/ - public static void init() { - currentTime(); + public static void init(Instant planStart) { + CLOCK = resource(clock(ZERO)); + ABSOLUTE_CLOCK = name(addToInstant(planStart, CLOCK), "Global Absolute Simulation Clock"); } // TODO if Aerie provides either a `getElapsedTime` method or dynamic allocation of Cells, we can avoid this mutable static variable - private static Resource CLOCK = resource(clock(ZERO)); + private static Resource CLOCK; + private static Resource ABSOLUTE_CLOCK; public static Duration currentTime() { - try { - return currentValue(CLOCK); - } catch (Scoped.EmptyDynamicCellException | IllegalArgumentException e) { - // If we're running unit tests, several simulations can happen without reloading the Resources class. - // In that case, we'll have discarded the clock resource we were using, and get the above exception. - // REVIEW: Is there a cleaner way to make sure this resource gets (re-)initialized? - CLOCK = resource(clock(ZERO)); - return currentValue(CLOCK); - } + return currentValue(CLOCK); + } + public static Instant currentInstant() { + return currentValue(ABSOLUTE_CLOCK); + } + + public static Resource simulationClock() { + return CLOCK; + } + public static Resource absoluteClock() { + return ABSOLUTE_CLOCK; } public static D currentData(Resource resource) { diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registrar.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registrar.java index a8ab5ecce3..77545fc939 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registrar.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registrar.java @@ -15,6 +15,8 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.RealDynamics; import gov.nasa.jpl.aerie.merlin.protocol.types.Unit; +import java.time.Instant; + import static gov.nasa.jpl.aerie.contrib.streamline.core.Reactions.whenever; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentData; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue; @@ -54,8 +56,8 @@ public enum ErrorBehavior { Throw } - public Registrar(final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, final ErrorBehavior errorBehavior) { - Resources.init(); + public Registrar(final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, final Instant planStart, final ErrorBehavior errorBehavior) { + Resources.init(planStart); Logging.init(baseRegistrar); this.baseRegistrar = baseRegistrar; this.errorBehavior = errorBehavior; diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClock.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClock.java new file mode 100644 index 0000000000..e6c866fd23 --- /dev/null +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClock.java @@ -0,0 +1,24 @@ +package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; + +import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.addToInstant; + +/** + * A variation on {@link Clock} that represents an absolute {@link Instant} + * instead of a relative {@link Duration}. + */ +public record InstantClock(Instant extract) implements Dynamics { + @Override + public InstantClock step(Duration t) { + return new InstantClock(addToInstant(extract, t)); + } + + static Duration durationBetween(Instant start, Instant end) { + return Duration.of(ChronoUnit.MICROS.between(start, end), Duration.MICROSECONDS); + } +} diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClockResources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClockResources.java new file mode 100644 index 0000000000..204ef2c3c2 --- /dev/null +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClockResources.java @@ -0,0 +1,56 @@ +package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; + +import gov.nasa.jpl.aerie.contrib.streamline.core.*; +import gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; + +import java.time.Instant; + +import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; +import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad.map; +import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Naming.name; +import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources.constant; + +public class InstantClockResources { + /** + * Create an absolute clock that starts now at the given start time. + */ + public static MutableResource absoluteClock(Instant startTime) { + return resource(new InstantClock(startTime)); + } + + public static Resource addToInstant(Instant zeroTime, Resource relativeClock) { + return addToInstant(constant(zeroTime), relativeClock); + } + + public static Resource addToInstant(Resource> zeroTime, Resource relativeClock) { + return name( + map(zeroTime, relativeClock, (zero, clock) -> + new InstantClock(Duration.addToInstant(zero.extract(), clock.extract()))), + "%s + %s", + zeroTime, + relativeClock); + } + + public static Resource relativeTo(Resource clock, Resource> zeroTime) { + return name(ResourceMonad.map(clock, zeroTime, (c, t) -> new Clock(InstantClock.durationBetween(t.extract(), c.extract()))), + "%s relative to %s", clock, zeroTime); + } + + public static Resource> lessThan(Resource clock, Resource> threshold) { + return ClockResources.lessThan(relativeTo(clock, threshold), constant(Duration.ZERO)); + } + + public static Resource> lessThanOrEquals(Resource clock, Resource> threshold) { + return ClockResources.lessThanOrEquals(relativeTo(clock, threshold), constant(Duration.ZERO)); + } + + public static Resource> greaterThan(Resource clock, Resource> threshold) { + return ClockResources.greaterThan(relativeTo(clock, threshold), constant(Duration.ZERO)); + } + + public static Resource> greaterThanOrEquals(Resource clock, Resource> threshold) { + return ClockResources.greaterThanOrEquals(relativeTo(clock, threshold), constant(Duration.ZERO)); + } +} diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClock.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClock.java new file mode 100644 index 0000000000..7915396af3 --- /dev/null +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClock.java @@ -0,0 +1,19 @@ +package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; + +import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; + +import java.time.Instant; + +import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.addToInstant; + +/** + * A variation on {@link VariableClock} that represents an absolute {@link Instant} + * instead of a relative {@link Duration}. + */ +public record VariableInstantClock(Instant extract, int multiplier) implements Dynamics { + @Override + public VariableInstantClock step(Duration t) { + return new VariableInstantClock(addToInstant(extract, t.times(multiplier)), multiplier); + } +} diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockEffects.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockEffects.java new file mode 100644 index 0000000000..019a31ee4c --- /dev/null +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockEffects.java @@ -0,0 +1,33 @@ +package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; + +import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource; + +import java.time.Instant; + +import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.DynamicsMonad.effect; +import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Naming.name; + +public final class VariableInstantClockEffects { + private VariableInstantClockEffects() {} + + /** + * Stop the clock without affecting the current time. + */ + public static void pause(MutableResource clock) { + clock.emit("Pause", effect($ -> new VariableInstantClock($.extract(), 0))); + } + + /** + * Start the clock without affecting the current time. + */ + public static void start(MutableResource clock) { + clock.emit("Start", effect($ -> new VariableInstantClock($.extract(), 1))); + } + + /** + * Reset the clock to the given time, without affecting how fast it's running. + */ + public static void reset(MutableResource clock, Instant newTime) { + clock.emit(name(effect($ -> new VariableInstantClock(newTime, $.multiplier())), "Reset to %s", newTime)); + } +} diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockResources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockResources.java new file mode 100644 index 0000000000..83df2de990 --- /dev/null +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockResources.java @@ -0,0 +1,42 @@ +package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; + +import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; + +import java.time.Instant; + +import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad.map; +import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Naming.name; +import static gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.InstantClock.durationBetween; +import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources.constant; + +public final class VariableInstantClockResources { + private VariableInstantClockResources() {} + + public static Resource relativeTo(Resource clock, Resource> zeroTime) { + return name(map(clock, zeroTime, (c, t) -> + new VariableClock(durationBetween(c.extract(), t.extract()), c.multiplier())), + "%s relative to %s", clock, zeroTime); + } + + public static Resource> lessThan(Resource clock, Resource> threshold) { + return VariableClockResources.lessThan(relativeTo(clock, threshold), constant(Duration.ZERO)); + } + + public static Resource> lessThanOrEquals(Resource clock, Resource> threshold) { + return VariableClockResources.lessThanOrEquals(relativeTo(clock, threshold), constant(Duration.ZERO)); + } + + public static Resource> greaterThan(Resource clock, Resource> threshold) { + return VariableClockResources.greaterThan(relativeTo(clock, threshold), constant(Duration.ZERO)); + } + + public static Resource> greaterThanOrEquals(Resource clock, Resource> threshold) { + return VariableClockResources.greaterThanOrEquals(relativeTo(clock, threshold), constant(Duration.ZERO)); + } + + public static Resource between(Resource start, Resource end) { + return map(start, end, (s, e) -> new VariableClock(durationBetween(s.extract(), e.extract()), e.multiplier() - s.multiplier())); + } +} diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java index c77bb601c8..1a626b6fda 100644 --- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java @@ -9,10 +9,11 @@ import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExtendWith; +import java.time.Instant; + import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.autoEffects; import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.commutingEffects; import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.noncommutingEffects; -import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete.discrete; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.monads.DiscreteDynamicsMonad.effect; @@ -27,10 +28,11 @@ class MutableResourceTest { @TestInstance(Lifecycle.PER_CLASS) class NonCommutingEffects { public NonCommutingEffects(final Registrar registrar) { - Resources.init(); + Resources.init(Instant.EPOCH); + cell = MutableResource.resource(discrete(42), noncommutingEffects()); } - private final MutableResource> cell = MutableResource.resource(discrete(42), noncommutingEffects()); + private final MutableResource> cell; @Test void gets_initial_value_if_no_effects_are_emitted() { @@ -66,10 +68,11 @@ void throws_exception_when_concurrent_effects_are_applied() { @TestInstance(Lifecycle.PER_CLASS) class CommutingEffects { public CommutingEffects(final Registrar registrar) { - Resources.init(); + Resources.init(Instant.EPOCH); + cell = MutableResource.resource(discrete(42), commutingEffects()); } - private final MutableResource> cell = MutableResource.resource(discrete(42), commutingEffects()); + private final MutableResource> cell; @Test void gets_initial_value_if_no_effects_are_emitted() { @@ -108,11 +111,12 @@ void applies_concurrent_effects_in_any_order() { @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) class AutoEffects { - public AutoEffects(final Registrar registrar) { - Resources.init(); + public AutoEffects() { + Resources.init(Instant.EPOCH); + cell = MutableResource.resource(discrete(42), autoEffects()); } - private final MutableResource> cell = MutableResource.resource(discrete(42), autoEffects()); + private final MutableResource> cell; @Test void gets_initial_value_if_no_effects_are_emitted() { diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java index 8014216f63..75ea39427a 100644 --- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.contrib.streamline.debugging; -import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource; import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; +import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete; import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources; import gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.Polynomial; @@ -11,6 +11,8 @@ import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; +import java.time.Instant; + import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad.*; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.Polynomial.polynomial; @@ -21,12 +23,22 @@ @ExtendWith(MerlinExtension.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class DependenciesTest { - Resource> constantTrue = DiscreteResources.constant(true); - Resource constant1234 = constant(1234); - Resource constant5678 = constant(5678); - Resource polynomialCell = resource(polynomial(1)); - Resource derived = map(constantTrue, constant1234, constant5678, - (b, x, y) -> b.extract() ? x : y); + public DependenciesTest() { + Resources.init(Instant.EPOCH); + + constantTrue = DiscreteResources.constant(true); + constant1234 = constant(1234); + constant5678 = constant(5678); + polynomialCell = resource(polynomial(1)); + derived = map(constantTrue, constant1234, constant5678, + (b, x, y) -> b.extract() ? x : y); + } + + Resource> constantTrue; + Resource constant1234; + Resource constant5678; + Resource polynomialCell; + Resource derived; @Test void constants_are_named_by_their_value() { diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteEffectsTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteEffectsTest.java index 49d4a953e8..ea30dd871a 100644 --- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteEffectsTest.java +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteEffectsTest.java @@ -5,7 +5,6 @@ import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock; import gov.nasa.jpl.aerie.contrib.streamline.unit_aware.UnitAware; -import gov.nasa.jpl.aerie.merlin.framework.Registrar; import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import org.junit.jupiter.api.Test; @@ -13,6 +12,8 @@ import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExtendWith; +import java.time.Instant; + import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentTime; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue; @@ -40,8 +41,10 @@ @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) class DiscreteEffectsTest { - public DiscreteEffectsTest(final Registrar registrar) { - Resources.init(); + { + // We need to initialize this up front, so we can use in-line initializers for other resources after. + // I think in-line initializers for the other resources make the tests easier to read. + Resources.init(Instant.EPOCH); } private final MutableResource> settable = resource(discrete(42)); diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/PrecomputedTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/PrecomputedTest.java index 3849203bf5..d0d8bd733b 100644 --- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/PrecomputedTest.java +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/PrecomputedTest.java @@ -2,7 +2,6 @@ import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; -import gov.nasa.jpl.aerie.merlin.framework.Registrar; import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import org.junit.jupiter.api.Test; @@ -26,8 +25,10 @@ @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) public class PrecomputedTest { - public PrecomputedTest(final Registrar registrar) { - Resources.init(); + { + // We need to initialize this up front, so we can use in-line initializers for other resources after. + // I think in-line initializers for the other resources make the tests easier to read. + Resources.init(Instant.EPOCH); } final Resource> precomputedAsAConstant = diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/ComparisonsTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/ComparisonsTest.java index a7cad57998..67a3e109e9 100644 --- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/ComparisonsTest.java +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/ComparisonsTest.java @@ -5,7 +5,6 @@ import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete; -import gov.nasa.jpl.aerie.merlin.framework.Registrar; import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import org.junit.jupiter.api.Test; @@ -13,6 +12,8 @@ import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExtendWith; +import java.time.Instant; + import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.set; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentData; @@ -28,22 +29,26 @@ @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) public class ComparisonsTest { - public ComparisonsTest(final Registrar registrar) { - Resources.init(); - } + public ComparisonsTest() { + Resources.init(Instant.EPOCH); - private final MutableResource p = resource(polynomial(0)); - private final MutableResource q = resource(polynomial(0)); + p = resource(polynomial(0)); + q = resource(polynomial(0)); - private final Resource> p_lt_q = lessThan(p, q); - private final Resource> p_lte_q = lessThanOrEquals(p, q); - private final Resource> p_gt_q = greaterThan(p, q); - private final Resource> p_gte_q = greaterThanOrEquals(p, q); + p_lt_q = lessThan(p, q); + p_lte_q = lessThanOrEquals(p, q); + p_gt_q = greaterThan(p, q); + p_gte_q = greaterThanOrEquals(p, q); + + min_p_q = min(p, q); + min_q_p = min(q, p); + max_p_q = max(p, q); + max_q_p = max(q, p); + } - private final Resource min_p_q = min(p, q); - private final Resource min_q_p = min(q, p); - private final Resource max_p_q = max(p, q); - private final Resource max_q_p = max(q, p); + private final MutableResource p, q; + private final Resource> p_lt_q, p_lte_q, p_gt_q, p_gte_q; + private final Resource min_p_q, min_q_p, max_p_q, max_q_p; @Test void comparing_distinct_constants() { diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/LinearBoundaryConsistencySolverTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/LinearBoundaryConsistencySolverTest.java index eceec5b70e..254fa93ff7 100644 --- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/LinearBoundaryConsistencySolverTest.java +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/LinearBoundaryConsistencySolverTest.java @@ -10,6 +10,8 @@ import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExtendWith; +import java.time.Instant; + import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.*; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentData; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.LinearBoundaryConsistencySolver.Comparison.*; @@ -25,11 +27,13 @@ class LinearBoundaryConsistencySolverTest { @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) class SingleVariableSingleConstraint { - MutableResource driver = resource(polynomial(10)); + MutableResource driver; Resource result; - public SingleVariableSingleConstraint() { - Resources.init(); + SingleVariableSingleConstraint() { + Resources.init(Instant.EPOCH); + + driver = resource(polynomial(10)); var solver = new LinearBoundaryConsistencySolver("SingleVariableSingleConstraint"); var v = solver.variable("v", Domain::upperBound); @@ -65,13 +69,15 @@ void results_evolve_with_time() { @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) class SingleVariableMultipleConstraint { - MutableResource lowerBound1 = resource(polynomial(10)); - MutableResource lowerBound2 = resource(polynomial(20)); - MutableResource upperBound = resource(polynomial(30)); + MutableResource lowerBound1, lowerBound2, upperBound; Resource result; - public SingleVariableMultipleConstraint() { - Resources.init(); + SingleVariableMultipleConstraint() { + Resources.init(Instant.EPOCH); + + lowerBound1 = resource(polynomial(10)); + lowerBound2 = resource(polynomial(20)); + upperBound = resource(polynomial(30)); var solver = new LinearBoundaryConsistencySolver("SingleVariableMultipleConstraint"); var v = solver.variable("v", Domain::lowerBound); @@ -141,11 +147,13 @@ void failures_are_cleared_if_problem_becomes_feasible_again() { @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) class ScalingConstraint { - MutableResource driver = resource(polynomial(10)); + MutableResource driver; Resource result; - public ScalingConstraint() { - Resources.init(); + ScalingConstraint() { + Resources.init(Instant.EPOCH); + + driver = resource(polynomial(10)); var solver = new LinearBoundaryConsistencySolver("ScalingConstraint"); var v = solver.variable("v", Domain::upperBound); @@ -171,12 +179,14 @@ void scaling_is_respected_for_later_solutions() { @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) class MultipleVariables { - MutableResource upperBound = resource(polynomial(10)); - MutableResource upperBoundOnC = resource(polynomial(5)); + MutableResource upperBound, upperBoundOnC; Resource a, b, c; - public MultipleVariables() { - Resources.init(); + MultipleVariables() { + Resources.init(Instant.EPOCH); + + upperBound = resource(polynomial(10)); + upperBoundOnC = resource(polynomial(5)); var solver = new LinearBoundaryConsistencySolver("MultipleVariablesSingleConstraint"); var a = solver.variable("a", Domain::upperBound); diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PrecomputedTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PrecomputedTest.java index 47427baf17..54122c6581 100644 --- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PrecomputedTest.java +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PrecomputedTest.java @@ -2,13 +2,13 @@ import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; -import gov.nasa.jpl.aerie.merlin.framework.Registrar; import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.extension.ExtendWith; +import java.time.Instant; import java.util.Map; import java.util.TreeMap; @@ -24,8 +24,10 @@ @ExtendWith(MerlinExtension.class) @TestInstance(Lifecycle.PER_CLASS) public class PrecomputedTest { - public PrecomputedTest(final Registrar registrar) { - Resources.init(); + { + // We need to initialize this up front, so we can use in-line initializers for other resources after. + // I think in-line initializers for the other resources make the tests easier to read. + Resources.init(Instant.EPOCH); } final Resource precomputedAsConstantInPast = diff --git a/examples/streamline-demo/src/main/java/gov/nasa/jpl/aerie/streamline_demo/Mission.java b/examples/streamline-demo/src/main/java/gov/nasa/jpl/aerie/streamline_demo/Mission.java index ece739efba..a1d32e971a 100644 --- a/examples/streamline-demo/src/main/java/gov/nasa/jpl/aerie/streamline_demo/Mission.java +++ b/examples/streamline-demo/src/main/java/gov/nasa/jpl/aerie/streamline_demo/Mission.java @@ -5,13 +5,15 @@ import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registrar; import gov.nasa.jpl.aerie.merlin.framework.ModelActions; +import java.time.Instant; + public final class Mission { public final DataModel dataModel; public final ErrorTestingModel errorTestingModel; public final ApproximationModel approximationModel; - public Mission(final gov.nasa.jpl.aerie.merlin.framework.Registrar registrar$, final Configuration config) { - var registrar = new Registrar(registrar$, Registrar.ErrorBehavior.Log); + public Mission(final gov.nasa.jpl.aerie.merlin.framework.Registrar registrar$, Instant planStart, final Configuration config) { + var registrar = new Registrar(registrar$, planStart, Registrar.ErrorBehavior.Log); if (config.traceResources) registrar.setTrace(); if (config.profileResources) Resource.profileAllResources(); dataModel = new DataModel(registrar, config);