diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/InconBehavior.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/InconBehavior.java index f5ed082b07..c51390b18b 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/InconBehavior.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/InconBehavior.java @@ -1,53 +1,35 @@ package gov.nasa.jpl.aerie.contrib.streamline.core; import gov.nasa.jpl.aerie.contrib.streamline.utils.InvertibleFunction; -import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import java.util.Optional; import java.util.function.BiConsumer; -import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Supplier; + +import static gov.nasa.jpl.aerie.contrib.streamline.core.InitialConditionManager.*; /** * Combines the operations of getting initial state and saving final state, * since these operations are intentionally closely coupled. */ public interface InconBehavior { - T getIncon(InitialConditionManager.InitialConditions initialConditions); + T getIncon(InitialConditions initialConditions); - void writeFincon(T state, InitialConditionManager.FinalConditions finalConditions); + void writeFincon(T state, FinalConditions finalConditions); - static InconBehavior of(Function getIncon, BiConsumer writeFincon) { - return new InconBehavior() { + static InconBehavior of(Function getIncon, BiConsumer writeFincon) { + return new InconBehavior<>() { @Override - public T getIncon(InitialConditionManager.InitialConditions initialConditions) { + public T getIncon(InitialConditions initialConditions) { return getIncon.apply(initialConditions); } @Override - public void writeFincon(T state, InitialConditionManager.FinalConditions finalConditions) { + public void writeFincon(T state, FinalConditions finalConditions) { writeFincon.accept(state, finalConditions); } }; } - /** - * The null case of incon behavior, when in fact the state does not get saved out. - */ - static InconBehavior constant(T value) { - return InconBehavior.of($ -> value, (s, f) -> {}); - } - - /** - * The standard case of incon behavior, where the state is serialized out under a single key. - */ - static InconBehavior serialized(String key, Function, T> constructor, Function serializer) { - return InconBehavior.of( - incons -> constructor.apply(incons.get(key)), - (state, fincons) -> fincons.put(key, serializer.apply(state))); - } - /** * Extend this {@link InconBehavior} with an invertible function. *

diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/MutableResource.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/MutableResource.java index a7a0c4f91b..946e918d54 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/MutableResource.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/MutableResource.java @@ -76,12 +76,14 @@ static InconBehavior>> notSaving(D initialValue) { } static InconBehavior>> notSaving(ErrorCatching> initialValue) { - return InconBehavior.constant(initialValue); + return InconBehavior.of($ -> initialValue, (s, f) -> {}); } // TODO - It would be nice if the name we set here could somehow auto-populate the name of the resource, // and also be the name we register the resource as. Same for the value mapper, it would be nice to just use that for registration too. // Alternatively, we could demand a name for every MutableResource, and combine that with the other info here later...? + // On reflection, I think the discrete resource and linear resource constructors are the place to combine all this info. + // Those would know which registrar method to call, and what value mapper to use. static InconBehavior>> serializing(String key, D defaultValue, ValueMapper mapper) { return serializing(key, pure(defaultValue), standardDynamicsMapper(mapper)); } @@ -131,10 +133,9 @@ public Result>, String> deserializeValue(SerializedVal } static InconBehavior>> serializing(String key, ErrorCatching> defaultValue, ValueMapper>> mapper) { - return InconBehavior.serialized( - key, - serializedValue -> serializedValue.map($ -> mapper.deserializeValue($).getSuccessOrThrow()).orElse(defaultValue), - mapper::serializeValue); + return InconBehavior.of( + incons -> incons.get(key).map($ -> mapper.deserializeValue($).getSuccessOrThrow()).orElse(defaultValue), + (state, fincons) -> fincons.put(key, mapper.serializeValue(state))); } static > void set(MutableResource resource, D newDynamics) { diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Demo.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Demo.java index 12da74f904..9d011e6f55 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Demo.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Demo.java @@ -17,6 +17,7 @@ import java.util.Optional; +import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.notSaving; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.black_box.Approximation.approximate; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.black_box.DifferentiableResources.asDifferentiable; @@ -130,7 +131,7 @@ public final class Demo { Resource approxQuotient = approximate(quotient, secantApproximation(IntervalFunctions.>byBoundingError( 1e-6, Duration.SECOND, Duration.HOUR.times(24), errorByOptimization()))); - Resource>> positionAndVelocity = resource(Unstructured.timeBased(t -> /* some spice call */ null)); + Resource>> positionAndVelocity = resource(notSaving(Unstructured.timeBased(t -> /* some spice call */ null))); Resource>> approxPosVel = approximate( positionAndVelocity, DiscreteApproximation., Unstructured>>discreteApproximation( diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/black_box/Approximation.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/black_box/Approximation.java index a89531b4d7..70ff697e2d 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/black_box/Approximation.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/black_box/Approximation.java @@ -10,6 +10,7 @@ import java.util.function.BiFunction; import java.util.function.Function; +import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.notSaving; import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; import static gov.nasa.jpl.aerie.contrib.streamline.core.Expiring.expiring; import static gov.nasa.jpl.aerie.contrib.streamline.core.Reactions.whenever; @@ -32,7 +33,9 @@ private Approximation() {} */ public static , E extends Dynamics> Resource approximate( Resource resource, Function, Expiring> approximation) { - var result = resource(resource.getDynamics().map(approximation)); + // We should, in general, not care about saving the state of an approximation. + // Instead, we should restore the underlying resource and re-approximate + var result = resource(notSaving(resource.getDynamics().map(approximation))); // Register the "updates" and "expires" conditions separately // so that the "updates" condition isn't triggered spuriously. wheneverUpdates(resource, newResourceDynamics -> updateApproximation(newResourceDynamics, approximation, result)); diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/Clock.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/Clock.java index 8258d4576a..6cd9b23ece 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/Clock.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/Clock.java @@ -1,8 +1,10 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics; +import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +@AutoValueMapper.Record public record Clock(Duration extract) implements Dynamics { @Override public Clock step(Duration t) { diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/ClockResources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/ClockResources.java index 9b54d2ac8f..f8ada92031 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/ClockResources.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/ClockResources.java @@ -1,14 +1,13 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; -import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource; 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.contrib.streamline.core.Resource; import gov.nasa.jpl.aerie.contrib.streamline.modeling.linear.Linear; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; import static gov.nasa.jpl.aerie.contrib.streamline.core.Expiring.*; +import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.*; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.signalling; import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad.bind; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete.discrete; @@ -23,8 +22,8 @@ private ClockResources() {} /** * Create a clock starting at zero time. */ - public static Resource clock() { - return resource(Clock.clock(ZERO)); + public static Resource clock(String name) { + return resource(serializing(name, Clock.clock(ZERO), null /* TODO - get auto value mapper for Clock type */)); } public static Resource> lessThan(Resource clock, Resource> threshold) { 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 index e00bb5b323..67f7e128c5 100644 --- 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 @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics; +import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import java.time.Instant; @@ -12,6 +13,7 @@ * A variation on {@link Clock} that represents an absolute {@link Instant} * instead of a relative {@link Duration}. */ +@AutoValueMapper.Record public record InstantClock(Instant extract) implements Dynamics { @Override public InstantClock step(Duration t) { diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableClock.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableClock.java index 637ba689df..a38c54449c 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableClock.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableClock.java @@ -1,10 +1,12 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics; +import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.ZERO; +@AutoValueMapper.Record public record VariableClock(Duration extract, int multiplier) implements Dynamics { @Override public VariableClock step(final Duration t) { 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 index 7915396af3..cc657aa877 100644 --- 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 @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics; +import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import java.time.Instant; @@ -11,6 +12,7 @@ * A variation on {@link VariableClock} that represents an absolute {@link Instant} * instead of a relative {@link Duration}. */ +@AutoValueMapper.Record public record VariableInstantClock(Instant extract, int multiplier) implements Dynamics { @Override public VariableInstantClock step(Duration t) { diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteResources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteResources.java index 5a54a9a229..1da703fc28 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteResources.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteResources.java @@ -2,6 +2,7 @@ import gov.nasa.jpl.aerie.contrib.streamline.core.*; import gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.CommutativityTestInput; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registrar; import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock; import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.monads.DiscreteDynamicsMonad; import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.monads.DiscreteMonad; @@ -11,6 +12,8 @@ import gov.nasa.jpl.aerie.contrib.streamline.unit_aware.Unit; import gov.nasa.jpl.aerie.contrib.streamline.unit_aware.UnitAware; import gov.nasa.jpl.aerie.contrib.streamline.unit_aware.UnitAwareResources; +import gov.nasa.jpl.aerie.merlin.framework.ValueMapper; +import gov.nasa.jpl.aerie.merlin.protocol.model.EffectTrait; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import java.time.Instant; @@ -24,6 +27,7 @@ import static gov.nasa.jpl.aerie.contrib.streamline.core.Expiring.expiring; import static gov.nasa.jpl.aerie.contrib.streamline.core.Expiry.expiry; import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; +import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.serializing; import static gov.nasa.jpl.aerie.contrib.streamline.core.Reactions.every; import static gov.nasa.jpl.aerie.contrib.streamline.core.Reactions.whenever; import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.*; @@ -46,6 +50,68 @@ public static Resource> constant(T value) { return result; } + public static DiscreteResourceBuilder discreteResource(T initialValue) { + + } + + public class DiscreteResourceBuilder { + private ErrorCatching>> defaultValue; + private String name; + private ValueMapper valueMapper; + private InconBehavior>>> inconBehavior; + private EffectTrait>> effectTrait = autoEffects(); + + public DiscreteResourceBuilder defaultValue(T defaultValue) { + return defaultValue(DiscreteDynamicsMonad.pure(defaultValue)); + } + + public DiscreteResourceBuilder defaultValue(ErrorCatching>> defaultValue) { + assertNotSet("default value", this.defaultValue); + this.defaultValue = defaultValue; + return this; + } + + public DiscreteResourceBuilder name(String name) { + assertNotSet("name", this.name); + this.name = name; + return this; + } + + public DiscreteResourceBuilder valueMapper(ValueMapper valueMapper) { + assertNotSet("value mapper", this.valueMapper); + this.valueMapper = valueMapper; + return this; + } + + public DiscreteResourceBuilder inconBehavior(InconBehavior>>> inconBehavior) { + assertNotSet("incon behavior", this.inconBehavior); + this.inconBehavior = inconBehavior; + return this; + } + + private void assertNotSet(String name, Object thing) { + if (thing != null) + throw new IllegalStateException(String.format("%s has already been set on this builder!", name)); + } + + // Terminal methods - these build and return the resource + + // TODO - would it be more convenient to make Registrar a singleton, like the incon manager? + // Then it wouldn't have to be passed around just to give to these builders. + // We already assume you have exactly one registrar, because building it initializes all the singletons... + public Resource> registered(Registrar registrar) { + var result = notRegistered(); + registrar.discrete(name, result, valueMapper); + return result; + } + + public Resource> notRegistered() { + return resource(inconBehavior, effectTrait); + } + } + + // --- REWRITE START --- + // General discrete cell resource constructor public static MutableResource> discreteResource(T initialValue) { return resource(discrete(initialValue)); @@ -66,6 +132,8 @@ public static MutableResource> discreteResource(double initialV input.rightResult().extract())))); } + // --- REWRITE END --- + /** * Returns a condition that's satisfied whenever this resource is true. */